首页
归档
留言
友链
广告合作
壁纸
更多
美女主播
Search
1
博瑞GE车机升级/降级
5,649 阅读
2
Mac打印机设置黑白打印
5,044 阅读
3
修改elementUI中el-table树形结构图标
4,947 阅读
4
Mac客户端添加腾讯企业邮箱方法
4,705 阅读
5
intelliJ Idea 2022.2.X破解
4,460 阅读
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
登录
/
注册
Search
标签搜索
Spring Boot
Java
Vue
Mac
Spring Cloud
MyBatis
WordPress
MacOS
asp.net
Element UI
Nacos
MySQL
.Net
Spring Cloud Alibaba
Mybatis-Plus
Typecho
jQuery
Java Script
IntelliJ IDEA
微信小程序
Laughing
累计撰写
629
篇文章
累计收到
1,421
条评论
首页
栏目
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
页面
归档
留言
友链
广告合作
壁纸
美女主播
搜索到
629
篇与
的结果
2021-05-08
10大免费CDN介绍
CDN也称内容分发网络,其原理大概是将服务内容分发至全网加速节点,让用户从就近的服务器节点上获取内容,从而提高网站的访问速度。 大部分服务商(如阿里云,网易蜂巢,京东云等)的CDN服务是按使用量收费的,也有一些服务商提供免费的CDN服务,本文简单的总结一下目前可免费使用的CDN,对个人网站来说,免费的已经够用了。{mtitle title="腾讯云CDN "/}官网:https://cloud.tencent.com/product/cdn腾讯云可以免费申请SSL证书,腾讯云CDN也能很好的支持SSL证书,从而实现https访问,腾讯云的CDN不是完全免费的,但新注册的用户目前可有免费的流量包赠送,而且腾讯云每月都会赠送10G免费的加速流量,对个人网站来说相当的实用。{mtitle title="FreeCDN"/}官网:http://su.zhiduopc.com免费CDN、平均加速200%以上,访问量提升19%,是唯一一款使用前后不会影响网站访问及搜索引擎排名的免费CDN平台。不限流量不限使用时间,提供国内加速全球加速亚太加速多个节点,支持HTTPS+泛解析+防御DDOS CC ,强烈推荐。{mtitle title="360网站卫士"/}官网:http://wangzhan.360.com/360提供的免费CDN服务,不限流量,CDN加速功能和基本的安全防御功能比较稳定,其提供的免费域名解析服务也很稳定。360网站卫士支持上传SSL证书,还提供免费网站备案服务。请注意360网站卫士与360云加速(cdn.cloud.360.cn)是两个不同的产品,后者主要提供付费的CDN服务。{mtitle title="百度云加速"/}官网:https://su.baidu.com/云加速分为免费版和付费版,免费版不支持SSL证书,海外网站也支持加速。百度云加速声称可以加速百度收录,但效果不是很明显,云加速还提供免费的域名解析服务。请注意,百度云加速与百度云(cloud.baidu.com)以及百度云盘(yun.baidu.com)分别是不同的产品,不要被这混乱的名称绕晕了。{mtitle title="又拍云CDN"/}官网:https://www.upyun.com/products/cdn新注册的又拍云用户可以免费获得代金券,成为又拍云联盟的用户,一年内每月可免费使用10GB存储空间及15GB流量,又拍云也可以免费申请SSL证书实现https访问。{mtitle title="魔门云"/}官网:https://www.cachemoment.com/免费支持SSL,免费版每月10GB的免费流量,每月免费10万次的https请求数,加入魔门云联盟,可享受每月50GB的免费流量和每月50万次免费HTTPS请求数,魔门云还支持海外网站的加速。{mtitle title="七牛云CDN"/}官网:https://www.qiniu.com/products/fusion每个月可使用10G的免费存储量和10G的CDN流量与100万次的Get请求数,七牛云在海外也有众多加速节点,七牛云TCP压缩优化使网页中大图和样式等实现秒加载。使用七牛CDN,须保证账户中有最低金额10元。{mtitle title="性能魔方CDN"/}官网:http://www.mmtrix.com/ispeed性能魔方云加速提供国内外30个IDC和300+CDN节点网络加速,免费版前3个月免费使用百余个CDN节点和每月1000GB流量,之后每月可获得200GB的免费流量,此网站还免费提供网站云监测和WEB检测服务,值得体验。{mtitle title="VeryCloud云"/}官网:https://www.verycloud.cn/cloud/cdninfo云端网络将用户的加速内容分发至部署在全球的近500个服务节点,每月免费赠送50G的CDN加速流量,稳定支撑大量图片、音频、视频等文件的访问。{mtitle title="Cloudflare"/}官网:https://www.cloudflare.com/Cloudflare的免费版功能很强大,它最大亮点是提供完全免费的SSL证书一键实现https访问,如果不想使用国内的CDN服务,Cloudflare是最好的选择。但是由于它的域名解析服务器在国外,速度方面可能比国内差一些。
2021年05月08日
1,649 阅读
0 评论
2 点赞
2021-05-07
console.log()输出多彩信息
平时我们在前端打印日志,可能直接就是使用console.log(),其实console.log()有很多有趣(也可能无用)的用法。下面我们介绍一下通过console.log()输出多彩日志。console.log()可以通过'%c'输出标准的css样式。console.log("%cMy stylish message", "color: red; font-style: italic"); console.log( "%c3D Text", " text-shadow: 0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);font-size:5em" ); console.log( "%cRainbow Text ", "background-image:-webkit-gradient( linear, left top, right top, color-stop(0, #f22), color-stop(0.15, #f2f), color-stop(0.3, #22f), color-stop(0.45, #2ff), color-stop(0.6, #2f2),color-stop(0.75, #2f2), color-stop(0.9, #ff2), color-stop(1, #f22) );color:transparent;-webkit-background-clip: text;font-size:5em;" ); console.log("%c香草物语", "color:#fff; background: linear-gradient(270deg, #986fee, #8695e6, #68b7dd, #18d7d3); padding: 8px 15px; border-radius: 0 15px 0 15px");
2021年05月07日
1,522 阅读
0 评论
5 点赞
2021-05-07
Vue.use()的用法
介绍在vue的main.js中,我们经常使用Vue.use(xx)方法。比如我们引入elementUI,在main.js中,我们一般通过如下代码引入:import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI){message type="error" content="需要先通过npm i element-ui -S安装elementUI"/}原来在开发时,一直都是这么用,但是基本没留意过为什么这么弄。官方解释安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。什么意思呢?Vue.use() 中的参数必须是一个function函数或者是一个Object对象,如果是对象的话,必须在对象中提供一个install方法。之后会将 Vue 作为参数传入。我们分两点来看:如果Vue.use() 中的参数是一个function函数,那么函数的参数是Vue对象。2. 如果Vue.use() 中的参数是一个Object对象,那么这个对象必须提供一个install方法,install方法的参数就是Vue。Demo演示我们通过以下两个Demo来分别演示一下上面说的两种情况。Object对象我们通过自定义一个主键的形式进行演示说明。创建项目vue init webpack-simple custom-global-component一路回车,然后执行npm run dev如果项目能正常启动代表创建成功。创建组件创建components文件夹,并创建loading.vue及index.js文件。目录结构如下loading.vue只是一个简单的组件,代码如下<template> <div> Laoding... </div> </template> <script> export default { } </script>在index.js,我们引入并注册定义的组件。import LoadingComponent from './loading.vue' const Loading = { install:function(Vue){ Vue.component('Loading',LoadingComponent) } } export default Loading在main.js中通过Vue.use()调用。import Loading from './components/loading' Vue.use(Loading)使用在App.vue中使用我们的组件。<template> <div id="app"> <Loading/> </div> </template>function函数创建函数function demo(Vue){ console.log(Vue) } export default demo引入在main.js中引入函数。import demo from './utils/func' Vue.use(demo)
2021年05月07日
1,104 阅读
2 评论
0 点赞
2021-05-07
Typecho后台主题 Fresh模板
问题太多,不推荐使用了。{mtitle title="主题介绍"/} resh主题采用了目前最流行的bootstrap前端开发框架与typecho进行深度适配;主题在继承typecho一贯简单高效风格的同时让其更加贴合现代年轻用户的审美。 自适应+扁平化的设计理念再加上更具活力的配色,能让用户获得最佳的视觉和操作体验,心情愉悦自然会提高写作积极性。 Fresh致敬仍在坚持写博客的每个人。{mtitle title="使用方法"/}备份原文件将admin文件夹及var/Widget/menu.php文件备份上传文件直接删除网站根目录 admin 文件夹,将压缩包内admin文件夹直接上传到网站根目录。移动菜单文件夹内 Menu.php 到网站根目录 var/Widget 文件夹内,清理浏览器缓存,大功告成!{message type="success" content="如果后台主题出现乱码或者无法正常显示,可能是因为有些插件不兼容,请禁用所有插件后清除缓存,如果能够正常显示再一个一个开启插件,找出不兼容的插件后取舍要主题还是要插件。"/}{cloud title="Typecho后台主题 Fresh模板(修复版).zip" type="wy" url="https://share.weiyun.com/adyAZKWU" password=""/}
2021年05月07日
1,666 阅读
0 评论
0 点赞
2021-05-07
mybatis-plus自动注入sql语句
我们在日常开发中,一般会在表里面增加创建人(create_by)、创建时间(create_time)、修改人(update_by)、修改时间(update_time)四个字段。创建人:新增时,通过上下文获取用户信息。创建时间:新增时,获取系统当前时间。修改人:修改时,通过上下文获取用户信息。修改时间:修改时,获取系统当前时间。对于这种公共的字段,如果每次都在Sql中进行处理,那是相当繁琐也是没必要的。如果你用的是MyBatis-Plus那么一切就变的简单了。继承mybatis的Interceptor拦截器/** * Description: mybatis拦截器,自动注入创建人、创建时间、修改人、修改时间 * * @author : laughing * DateTime: 2021-05-06 17:13 */ @Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) @Slf4j @SuppressWarnings("all") public class MybatisSqlInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; String sqlId = mappedStatement.getId(); SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); Object parameter = invocation.getArgs()[1]; if (parameter == null) { return invocation.proceed(); } if(SysOperateLog.class.isAssignableFrom(parameter.getClass()) || SysLoginInfo.class.isAssignableFrom(parameter.getClass())){ return invocation.proceed(); } if (SqlCommandType.INSERT == sqlCommandType) { Field[] fields = ConvertUtils.getAllFields(parameter); Long userId = SecurityUtils.getUserId(); for (Field field : fields) { try { if ("createBy".equals(field.getName())) { field.setAccessible(true); Object local_createBy = field.get(parameter); field.setAccessible(false); if (local_createBy == null || local_createBy.equals("")) { // 登录人账号 field.setAccessible(true); field.set(parameter, userId); field.setAccessible(false); } } // 注入创建时间 if ("createTime".equals(field.getName())) { field.setAccessible(true); Object local_createDate = field.get(parameter); field.setAccessible(false); if (local_createDate == null || local_createDate.equals("")) { field.setAccessible(true); field.set(parameter, new Date()); field.setAccessible(false); } } } catch (Exception e) { } } } if (SqlCommandType.UPDATE == sqlCommandType) { Long userId = SecurityUtils.getUserId(); Field[] fields = null; if (parameter instanceof MapperMethod.ParamMap) { MapperMethod.ParamMap<?> p = (MapperMethod.ParamMap<?>) parameter; if (p.containsKey("et")) { parameter = p.get("et"); } else { parameter = p.get("param1"); } if (parameter == null) { return invocation.proceed(); } fields = ConvertUtils.getAllFields(parameter); } else { fields = ConvertUtils.getAllFields(parameter); } for (Field field : fields) { try { if ("updateBy".equals(field.getName())) { //获取登录用户信息 // 登录账号 field.setAccessible(true); field.set(parameter, userId); field.setAccessible(false); } if ("updateTime".equals(field.getName())) { field.setAccessible(true); field.set(parameter, new Date()); field.setAccessible(false); } } catch (Exception e) { e.printStackTrace(); } } } return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { // TODO Auto-generated method stub } }通过SqlSessionFactory加载插件/** * Mybatis-Plus配置 * * @author leeframe */ @Configuration @EnableTransactionManagement public class MyBatisPlusConfig { @javax.annotation.Resource private Environment env; static final String DEFAULT_RESOURCE_PATTERN = "**/*.class"; private final Logger logger = LoggerFactory.getLogger(MyBatisPlusConfig.class); @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 如果用了分页插件注意先 add TenantLineInnerInterceptor 再 add PaginationInnerInterceptor // 用了分页插件必须设置 MybatisConfiguration#useDeprecatedExecutor = false // interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); interceptor.addInnerInterceptor(new TenantLineInnerInterceptor( new TenantLineHandler() { // manager_id = 1088248166370832385 // 获取租户 ID 值表达式,只支持单个 ID 值 @Override public Expression getTenantId() { return new StringValue(SecurityUtils.getOrgCode()); } // 这是 default 方法,默认返回 false 表示所有表都需要拼多租户条件, // 这里设置 role表不需要该条件 @Override public boolean ignoreTable(String tableName) { return StringUtils.isEmpty(SecurityUtils.getOrgCode()) || LeeFrameConfig.getFilterTableList().stream().anyMatch(e -> e.equalsIgnoreCase(tableName)); } @Override public String getTenantIdColumn() { return "org_code"; } })); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> configuration.setUseDeprecatedExecutor(false); } public static String setTypeAliasesPackage(String typeAliasesPackage) { ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver(); MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver); List<String> allResult = new ArrayList<String>(); try { for (String aliasesPackage : typeAliasesPackage.split(",")) { List<String> result = new ArrayList<String>(); aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN; Resource[] resources = resolver.getResources(aliasesPackage); if (resources != null && resources.length > 0) { MetadataReader metadataReader = null; for (Resource resource : resources) { if (resource.isReadable()) { metadataReader = metadataReaderFactory.getMetadataReader(resource); try { result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } } if (result.size() > 0) { HashSet<String> hashResult = new HashSet<String>(result); allResult.addAll(hashResult); } } if (allResult.size() > 0) { typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0])); } else { throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包"); } } catch (IOException e) { e.printStackTrace(); } return typeAliasesPackage; } public Resource[] resolveMapperLocations(String[] mapperLocations) { ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); List<Resource> resources = new ArrayList<Resource>(); if (mapperLocations != null) { for (String mapperLocation : mapperLocations) { try { Resource[] mappers = resourceResolver.getResources(mapperLocation); resources.addAll(Arrays.asList(mappers)); } catch (IOException e) { // ignore } } } return resources.toArray(new Resource[resources.size()]); } @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { String typeAliasesPackage = env.getProperty("mybatisPlus.typeAliasesPackage"); String mapperLocations = env.getProperty("mybatisPlus.mapperLocations"); String configLocation = env.getProperty("mybatisPlus.configLocation"); typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage); VFS.addImplClass(SpringBootVFS.class); final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setTypeAliasesPackage(typeAliasesPackage); sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ","))); sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation)); sessionFactory.setPlugins(mybatisSqlInterceptor()); return sessionFactory.getObject(); } @Bean public MybatisSqlInterceptor mybatisSqlInterceptor() { MybatisSqlInterceptor mybatisSqlInterceptor = new MybatisSqlInterceptor(); Properties properties = new Properties(); mybatisSqlInterceptor.setProperties(properties); return mybatisSqlInterceptor; } }
2021年05月07日
1,473 阅读
0 评论
0 点赞
2021-05-07
Spring Boot yaml文件配置列表
我们在Spring Boot的yaml配置文件中,一般配置的都是一些文本(字符串)。那么我们在yaml文件中如何配置列表或者数组呢。场景试想一下我们的场景:我们系统涉及到租户,数据库采用行级别的隔离,也就是说表里面有一个org_code列,作为租户之间数据隔离的条件,类似于where org_code = 'xx'。但是,我们不是所有的表都要进行,那么我们在过滤某些表不进行过滤时,首先肯定想到的就是在yaml文件中配置需要过滤的表名。敲代码yaml设置# 项目相关配置 leeframe: # 过滤表名,不进行租户的过滤 filterTableList: - sys_dict_type - sys_dict_data - sys_config - sys_organization - sys_job - sys_user_role配置映射@Component @ConfigurationProperties(prefix = "leeframe") public class LeeFrameConfig { /** * 过滤表名,不进行租户的过滤 */ private static List<String> filterTableList; public static List<String> getFilterTableList() { return filterTableList; } public void setFilterTableList(List<String> filterTableList) { LeeFrameConfig.filterTableList = filterTableList; } }使用LeeFrameConfig.getFilterTableList()
2021年05月07日
1,326 阅读
0 评论
1 点赞
2021-05-07
Spring Boot alibaba druid配置输出sql
用的slf4j打印的sql# 数据源配置 spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver druid: # 主库数据源 master: url: jdbc:mysql://localhost:3306/leeframe?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: root # 从库数据源 slave: # 从数据源开关/默认关闭 enabled: false url: username: password: # 初始连接数 initialSize: 5 # 最小连接池数量 minIdle: 10 # 最大连接池数量 maxActive: 20 # 配置获取连接等待超时的时间 maxWait: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最大生存的时间,单位是毫秒 maxEvictableIdleTimeMillis: 900000 # 配置检测连接是否有效 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false webStatFilter: enabled: true statViewServlet: enabled: true # 设置白名单,不填则允许所有访问 allow: url-pattern: /druid/* # 控制台管理用户名和密码 login-username: login-password: filter: stat: enabled: true # 慢SQL记录 log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true slf4j: enabled: true statement-create-after-log-enabled: false statement-log-enabled: true statement-executable-sql-log-enable: true statement-log-error-enabled: true result-set-log-enabled: false logging: level: druid: sql: Statement: DEBUG
2021年05月07日
1,348 阅读
0 评论
1 点赞
2021-05-06
vue使用axios配置跨域
开发环境中,我们一般通过两种方式解决跨域:让后端设置CORS,允许我们请求。前端在webpack中设置proxyTable{}代理。后端地址我们这里简单模拟一下后台就可以了,请求路径为http://localhost:8080/normal前端配置安装axios通过npm安装axiosnpm install axios --save配置main.jsimport axios from 'axios' Vue.prototype.$axios = axios axios.defaults.baseURL = '/api'修改代理打开vue项目config文件夹下的index.js在里面把proxyTable: {}设置如下proxyTable: { '/api': { target:'http://localhost:8080', // 请求后台的地址 changeOrigin:true, // 在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题 pathRewrite:{ // 路径重写, '^/api': '' // 替换target中的请求地址,相当于前台请求/api/xx会替换成http://localhost:8080/xx。 } } },测试 this.$axios.get('/normal').then(res=>{ console.log(res) })
2021年05月06日
1,330 阅读
1 评论
2 点赞
2021-05-06
vue中三个点(...)的用法
这个其实是es6的扩展运算符。扩展语法。对数组和对象而言,就是将运算符后面的变量里东西每一项拆下来。 console.log(...'张三'); console.log(...[1,2,3,4])
2021年05月06日
1,029 阅读
0 评论
0 点赞
2021-05-06
You aren‘t using a compiler supported by lombok, so lombok will not work and has been disabled.的问题及解决方法
我是通过更新lombok版本解决的。修改pom.xml中lombok的依赖至1.18.14及以上版本<!--Lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.14</version> <scope>provided</scope> </dependency>
2021年05月06日
2,099 阅读
0 评论
1 点赞
2021-05-06
2021五一小长假游记
今年五一去烟台玩了三天,真的体验到了什么叫报复性消费。其实本来打算去西安的,奈何一家三口来回机票就得5K+,确实太贵了。{mtitle title="五一出行路线"/}{timeline}{timeline-item color="#19be6b"} 5.4九丈崖→月牙湾→仙境源→乘轮渡回蓬莱→稍事休息→回家{/timeline-item}{timeline-item color="#ed4014"} 5.3乘轮渡到长岛→海边逛了逛→晚上与朋友一期海鲜大餐→住长岛{/timeline-item}{timeline-item color="#ed4114"} 5.2日蓬莱阁→八仙渡附近骑电车→晚上悦动港湾海鲜自助→返回看电影→回酒店{/timeline-item}{timeline-item color="#fd4014"} 5.1晚9点半到达酒店{/timeline-item}{/timeline}{mtitle title="吃"/}{tabs}{tabs-pane label="推荐"}悦动港湾海鲜自助还是不错的,60多一位的自助,各种海鲜、饮品都不错。{/tabs-pane}{tabs-pane label="不推荐"}强烈不推荐在长岛吃海鲜。5月3号晚上跟朋友一起去吃海鲜,美团找了一个叫海鲜居还是啥的,在滨海路,兄弟两个开的,两个店挨着。美团团购很便宜,但是不让你用,一问就说团购的上面食材没有,巨坑。东西又贵量又少。{/tabs-pane}{/tabs}{mtitle title="住"/}格尔丽都酒店 格尔丽都酒店住了两天,整体环境、加个还算比较实惠。但是也有两个槽点:(1)早饭不是很好,基本没啥吃的,酒店早餐供应说是6~9点,但是8点多去基本就没有了。(2)服务欠佳,住了两天,竟然也不通知也不给打扫卫生、洗漱用品也没给全,打电话找前台,半个多小时才给送,就这服务,多要瓶水都不给。值得点赞的是停车位比较充裕,停车比较方便。长岛恒源大酒店 这个是在长岛住的,价格相对比较便宜,预定之前已经预料到了环境不是太好,但是入住进去才发现我还是太年轻了。槽点:(1)卫生很差,我下午一点多办理入住,走廊里面全是扔的被罩,难以想象的乱、脏。(2)屋里异味,一进去一股厕所的味道,一直开着窗户住的。(3)环境差,座椅也很破,桌子都是晃的,边都烂了。{mtitle title="行"/}高速自驾 走了沈海高速,比较坑,其实高速一点都不赌,明明前面没车,经常车道都被龟速行车的压制了。感觉现在高速上龟速行车的都是一颗毒瘤了,强烈建议高速真正的按车道限制最低车速。景区自驾 蓬莱阁风景区管理也比较混乱,景区门口还有交警维持秩序,别的地方就比较坑了。驾驶员更不用说了,加塞的、占用非机动车道的、机动车道停那下人半天不动的······不可一一而云。景区停车场明明很多车位,但是不让进,不知啥原因。 值得点赞的是,征用了附近一个蓬莱师范学校,操场能够免费停了,所以在那边停车没花一分钱。轮渡 轮渡不算太贵,但是去玩的话不建议升舱,20块钱根本不值,美其名曰喂海鸥,其实不升舱也一样。
2021年05月06日
962 阅读
0 评论
2 点赞
2021-05-02
微信公众号开发之回复用户留言
在微信公众号开发之公众号基础配置一文中,我们介绍了如何对微信公众号进行基础配置。下面基于李森的博客的一个需求说明一下如何实现公众号用户的回复开发。需求描述用户给公众号发送消息时,我们查询博客的内容,然后回复给用户。代码实现其实用户回复的请求,跟微信公众号开发之公众号基础配置中配置的URL是一致的。区别在于我们在微信公众号开发之公众号基础配置中配置的请求是GET请求,用户回复的时候,微信会通过POST请求到后台。定义Controller相应微信请求POST请求定义其实没啥特别的,代码如下 @PostMapping("official") public void post(HttpServletRequest request, HttpServletResponse response) { try { request.setCharacterEncoding("UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } response.setCharacterEncoding("UTF-8"); // 调用核心业务类接收消息、处理消息 // String respMessage = weixinPost(request); String respMessage = messageService.newMessageRequest(request); // 响应消息 PrintWriter out = null; try { out = response.getWriter(); out.print(respMessage); } catch (IOException e) { e.printStackTrace(); logger.error(e.getMessage()); } finally { out.close(); out = null; } }封装实体封装消息基础实体BaseMessage.java/** * 微信自动回复消息封装 */ @Data public class BaseMessage { // 开发者微信号 private String ToUserName; // 发送方帐号(一个OpenID) private String FromUserName; // 消息创建时间 (整型) private long CreateTime; // 消息类型(text/image/location/link) private String MsgType; // 消息id,64位整型 private long MsgId; /** * 位0x0001被标志时,星标刚收到的消息 */ private int FuncFlag; }封装普通文本消息实体TextMessage.java@EqualsAndHashCode(callSuper = true) @Data public class TextMessage extends BaseMessage{ // 消息内容 private String Content; }封装图文消息实体Article.java@Data public class Article { /** * 图文消息描述 */ private String Description; /** * 图片链接,支持JPG、PNG格式,<br> * 较好的效果为大图640*320,小图80*80 */ private String PicUrl; /** * 图文消息名称 */ private String Title; /** * 点击图文消息跳转链接 */ private String Url; }封装多条图文消息实体'NewsMessage.java'@EqualsAndHashCode(callSuper = true) @Data public class NewsMessage extends BaseMessage{ /** * 图文消息个数,限制为10条以内 */ private Integer ArticleCount; /** * 多条图文消息信息,默认第一个item为大图 */ private List<Article> Articles; }封装工具类我们需要将实体转换成xml结构,微信消息都是通过xml格式进行数据交互的。public class MessageUtil { /** * 返回消息类型:文本 */ public static final String RESP_MESSAGE_TYPE_TEXT = "text"; /** * 返回消息类型:音乐 */ public static final String RESP_MESSAGE_TYPE_MUSIC = "music"; /** * 返回消息类型:图文 */ public static final String RESP_MESSAGE_TYPE_NEWS = "news"; /** * 请求消息类型:文本 */ public static final String REQ_MESSAGE_TYPE_TEXT = "text"; /** * 请求消息类型:图片 */ public static final String REQ_MESSAGE_TYPE_IMAGE = "image"; /** * 请求消息类型:链接 */ public static final String REQ_MESSAGE_TYPE_LINK = "link"; /** * 请求消息类型:地理位置 */ public static final String REQ_MESSAGE_TYPE_LOCATION = "location"; /** * 请求消息类型:音频 */ public static final String REQ_MESSAGE_TYPE_VOICE = "voice"; /** * 请求消息类型:推送 */ public static final String REQ_MESSAGE_TYPE_EVENT = "event"; /** * 事件类型:subscribe(订阅) */ public static final String EVENT_TYPE_SUBSCRIBE = "subscribe"; /** * 事件类型:unsubscribe(取消订阅) */ public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe"; /** * 事件类型:CLICK(自定义菜单点击事件) */ public static final String EVENT_TYPE_CLICK = "CLICK"; /** * xml转换为map * * @param request * @return * @throws IOException */ public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException { Map<String, String> map = new HashMap<String, String>(); SAXReader reader = new SAXReader(); InputStream ins = null; try { ins = request.getInputStream(); } catch (IOException e1) { e1.printStackTrace(); } Document doc = null; try { doc = reader.read(ins); Element root = doc.getRootElement(); List<Element> list = root.elements(); for (Element e : list) { map.put(e.getName(), e.getText()); } return map; } catch (DocumentException e1) { e1.printStackTrace(); } finally { ins.close(); } return null; } /** * @param @param request * @param @return * @param @throws Exception * @Description: 解析微信发来的请求(XML) */ public static Map<String, String> parseXml(HttpServletRequest request) throws Exception { // 将解析结果存储在HashMap中 Map<String, String> map = new HashMap<String, String>(); // 从request中取得输入流 InputStream inputStream = request.getInputStream(); // 读取输入流 SAXReader reader = new SAXReader(); Document document = reader.read(inputStream); // 得到xml根元素 Element root = document.getRootElement(); // 得到根元素的所有子节点 List<Element> elementList = root.elements(); // 遍历所有子节点 for (Element e : elementList) map.put(e.getName(), e.getText()); // 释放资源 inputStream.close(); inputStream = null; return map; } // public static XStream xstream = new XStream(); /** * 文本消息对象转换成xml * * @param textMessage 文本消息对象 * @return xml */ public static String textMessageToXml(TextMessage textMessage) { // XStream xstream = new XStream(); xstream.alias("xml", textMessage.getClass()); return xstream.toXML(textMessage); } /** * @param @param newsMessage * @param @return * @Description: 图文消息对象转换成xml */ public static String newsMessageToXml(NewsMessage newsMessage) { xstream.alias("xml", newsMessage.getClass()); xstream.alias("item", new Article().getClass()); return xstream.toXML(newsMessage); } /** * 对象到xml的处理 */ private static XStream xstream = new XStream(new XppDriver() { public HierarchicalStreamWriter createWriter(Writer out) { return new PrettyPrintWriter(out) { // 对所有xml节点的转换都增加CDATA标记 boolean cdata = true; @SuppressWarnings("rawtypes") public void startNode(String name, Class clazz) { super.startNode(name, clazz); } protected void writeText(QuickWriter writer, String text) { if (cdata) { writer.write("<![CDATA["); writer.write(text); writer.write("]]>"); } else { writer.write(text); } } }; } }); }封装服务层 /** * 微信公众号处理 * * @param request * @return */ @Override public String newMessageRequest(HttpServletRequest request) { String respMessage = null; try { // xml请求解析 Map<String, String> requestMap = MessageUtil.xmlToMap(request); // 发送方帐号(open_id) String fromUserName = requestMap.get("FromUserName"); // 公众帐号 String toUserName = requestMap.get("ToUserName"); // 消息类型 String msgType = requestMap.get("MsgType"); // 用户发送的消息消息内容 String content = requestMap.get("Content"); logger.info("FromUserName is:" + fromUserName + ", ToUserName is:" + toUserName + ", MsgType is:" + msgType + ",content:" + content); // 文本消息 if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) { logger.info("进入方法内"); QueryWrapper<TypechoContents> queryWrapper = new QueryWrapper<>(); queryWrapper.lambda() .like(TypechoContents::getTitle, content) .or() .like(TypechoContents::getText, content); List<TypechoContents> typechoContentsList = typechoContentsMapper.selectTypechoContentsList(content); logger.info("数据查询完成:" + typechoContentsList.size()); if (typechoContentsList.size() <= 0) { //自动回复 TextMessage text = new TextMessage(); String string = "未找到要查询的内容,请换个关键字试试"; text.setContent(string); text.setToUserName(fromUserName); text.setFromUserName(toUserName); text.setCreateTime(new Date().getTime()); text.setMsgType(msgType); respMessage = MessageUtil.textMessageToXml(text); return respMessage; } else if (typechoContentsList.size() > 1) { TextMessage text = new TextMessage(); StringBuilder stringBuilder = new StringBuilder("搜索到以下内容:\r\n"); for (TypechoContents typechoContents : typechoContentsList) { stringBuilder.append("<a href='https://lisen.cc/").append(typechoContents.getCategory()).append("/").append(typechoContents.getSlug()).append(".html'>").append(typechoContents.getTitle()).append("</a>"); stringBuilder.append("\r\n"); } text.setContent(stringBuilder.toString()); text.setToUserName(fromUserName); text.setFromUserName(toUserName); text.setCreateTime(new Date().getTime()); text.setMsgType(msgType); respMessage = MessageUtil.textMessageToXml(text); return respMessage; } else { //一条回复图文消息 NewsMessage newsMessage = new NewsMessage(); newsMessage.setArticles(new ArrayList<>()); newsMessage.setArticleCount(typechoContentsList.size()); newsMessage.setToUserName(fromUserName); newsMessage.setFromUserName(toUserName); newsMessage.setCreateTime(new Date().getTime()); newsMessage.setMsgType("news"); for (TypechoContents typechoContents : typechoContentsList) { Article article = new Article(); article.setUrl("https://lisen.cc/" + typechoContents.getCategory() + "/" + typechoContents.getSlug() + ".html"); article.setDescription(typechoContents.getTitle()); List<String> imageUrlList = MessageUtil.getMatchString(typechoContents.getText()); if (imageUrlList.size() <= 0) { article.setPicUrl("https://lisen.cc/usr/themes/lisen/assets/img/logo.png"); } else { logger.info(imageUrlList.get(0)); article.setPicUrl(imageUrlList.get(0)); } article.setTitle(typechoContents.getTitle()); newsMessage.getArticles().add(article); } respMessage = MessageUtil.newsMessageToXml(newsMessage); return respMessage; } } // 事件推送 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) { String eventType = requestMap.get("Event");// 事件类型 // 订阅 if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) { //文本消息 TextMessage text = new TextMessage(); logger.info(LiSenConfig.getResp()); text.setContent(LiSenConfig.getResp().replace("<br/>","\n")); text.setToUserName(fromUserName); text.setFromUserName(toUserName); text.setCreateTime(new Date().getTime()); text.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT); respMessage = MessageUtil.textMessageToXml(text); return respMessage; } // 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息 else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {// 取消订阅 } } } catch (Exception e) { logger.error("error......"); } return respMessage; }
2021年05月02日
1,085 阅读
0 评论
0 点赞
1
...
27
28
29
...
53