首页
归档
留言
友链
广告合作
壁纸
更多
美女主播
Search
1
博瑞GE车机升级/降级
5,718 阅读
2
Mac打印机设置黑白打印
5,261 阅读
3
修改elementUI中el-table树形结构图标
4,977 阅读
4
Mac客户端添加腾讯企业邮箱方法
4,731 阅读
5
intelliJ Idea 2022.2.X破解
4,703 阅读
后端开发
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
累计撰写
630
篇文章
累计收到
1,421
条评论
首页
栏目
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
页面
归档
留言
友链
广告合作
壁纸
美女主播
搜索到
630
篇与
的结果
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,105 阅读
0 评论
0 点赞
2021-04-30
微信公众号自动回复typecho文章
{mtitle title="这是个啥"/}这是一个SpringBoot写的,实现微信公众号留言自动回复、关注发送消息及取关发送消息的Jar包。{mtitle title="能提供什么"/}目前我们提供以下功能:用户关注公众号自动回复。用户给公众号留言时,自动查找博客内容(目前按照标题查找)并将查询内容返回给用户。创建底部菜单(由于我的公众号是个人的,目前无法验证,所以暂时不放开)安装JDKjar包依赖JDK 1.8,所以需要先在服务器上配置好。不会的童鞋自己百度。修改配置文件用压缩软件打开gongzhonghao-0.0.1-SNAPSHOT.jar,找到application.yaml文件。配置信息port用于配置程序运行的端口,如果不使用80端口需要使用nginx进行端口转发。resp用于配置用户关注时回复的信息。如需换行请使用<br/>。AppID、AppSecret、token为配置微信公众号的后台信息。url、username、password用于配置typecho的数据库连接信息。参考如下spring: datasource: url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: root配置文件如下:server: port: 1234 lisen: AppID: 公众号AppId AppSecret: 公众号AppSecret token: lisen resp: 感谢关注<br/> <a href='https://lisen.cc'>李森的博客</a><br/> 现在可以回复关键字查询博客的文章啦~~~<br/> 快来试试吧☆ ̄(>。☆) spring: datasource: url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: root mybatis-plus: mapper-locations: classpath:/**/*.xml运行jar包将jar包传到外网服务器后台,进入jar包所在目录,执行以下命令(需要提前配置好JDK)nohup java -jar gongzhonghao-0.0.1-SNAPSHOT.jar > log.file 2>&1 &配置公众号进入公众号后台URL为你的域名+/wechat/officialtoken与上面配置的token保持一致EncodingAESKey随机生成即可。jar包下载隐藏内容,请前往内页查看详情
2021年04月30日
2,029 阅读
4 评论
3 点赞
2021-04-30
Sonar基础使用系列文章
sonar自动化测试一:sonar简介sonar自动化测试二:SonarQube服务端安装sonar自动化测试三:SonarScanner安装配置sonar自动化测试四:SonarScanner使用
2021年04月30日
1,477 阅读
1 评论
1 点赞
2021-04-30
sonar自动化测试四:SonarScanner使用
创建配置文件进入到待测试的项目根目录,新建sonar-project.properties文件: 输入命令vi sonar-project.properties,进行文本编辑模式。增加如下配置,其中:sonar.projectName是项目名字,sonar.sources是源文件所在的目录# must be unique in a given SonarQube instance sonar.projectKey=my:intelligence-operations-system # this is the name displayed in the SonarQube UI sonar.projectName= intelligence-operations-system sonar.projectVersion=1.0 # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. # Since SonarQube 4.2, this property is optional if sonar.modules is set. # If not set, SonarQube starts looking for source code from the directory containing # the sonar-project.properties file. sonar.sources= src/main/java # Encoding of the source code. Default is default system encoding #sonar.sourceEncoding=UTF-8 #path to your project build output path sonar.java.binaries=target/classes使用打开终端,进入待测试项目根目录,执行命令:sonar-scanner查看后台任务打开SonarQube,在浏览器打开http://localhost:9000,即可看见正在分析中的后台任务
2021年04月30日
1,149 阅读
0 评论
1 点赞
2021-04-30
sonar自动化测试三:SonarScanner安装配置
配置环境变量以下以Mac系统为例介绍,Win或Linux请具体配置对应的环境变量。首先进入bash.profile文件,输入命令 vi ~/.bash_profile,进行编辑文本模式。配置sonar_scanner_home、path(路径换成你的sonarqube与sonar-scanner文件所在的绝对路径),以我的为例:export SONAR_SCANNER_HOME=/Users/laughing/Downloads/sonar-scanner-4.6.0.2311-macosx export PATH=$PATH:$SONAR_SCANNER_HOME/bin退出文本编辑模式(按Esc,输入:wq),配置生效执行命令: source ~/.bash_profile使配置立即生效测试sonar-scanner是否安装成功输入命令:sonar-scanner -v
2021年04月30日
1,047 阅读
0 评论
0 点赞
2021-04-30
sonar自动化测试二:SonarQube服务端安装
准备工作jdk(请自行安装JDK1.8或以上版本)sonarqube(建议下载7.9以下版本):http://www.sonarqube.org/downloads/SonarQube+Scanner:https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/mysql数据库(请自行安装MySQL 5.7以上及8.0以下版本)启动SonarQube进入SonarQube目录cd /Downloads/sonarqube-7.8/bin/macosx-universal-64{message type="warning" content="不同操作系统,请进入bin的不同目录下"/}执行以下命令启动./sonar.sh start测试配置是否成功启动浏览器,访问http://localhost:9000,如果显示下面页面代表配置成功配置数据库打开mysql,新建一个数据库。打开sonarqube安装目录下的conf/sonar.properties文件配置认证信息,username和password为MySQL的用户名密码sonar.jdbc.username=sonar sonar.jdbc.password=sonar在mysql5.X节点下输入以下信息sonar.jdbc.url=jdbc:mysql://dotnetcore.com.cn:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance&useSSL=false重启sonarqube服务./sonar.sh restart再次访问http://localhost:9000,会稍微有点慢,因为要初始化数据库信息数据库初始化成功后,登录默认用户名和密码是admin;admin安装中文插件进入系统,依次选择,Administration -> Marketplace→输入“chinese”,找到“Chinese Pack”,点击“install”安装插件安装完成后,重新登录,界面即显示中文
2021年04月30日
1,276 阅读
0 评论
0 点赞
2021-04-30
sonar自动化测试一:sonar简介
{card-default label="" width=""}SonarQube(sonar)是一个开源平台,用于管理源代码的质量。 SonarQube不只是一个质量数据报告工具,更是代码质量管理平台。 支持java, C#, C/C++, PL/SQL, Cobol, JavaScrip, Groovy 等等二十几种编程语言的代码质量管理与检测。 SonarQube可以从以下七个维度检测代码质量,而作为开发人员至少需要处理前5种代码质量问题。{/card-default}不遵循代码标准SonarQube可以通过PMD,CheckStyle,Findbugs等等代码规则检测工具规范代码编写。潜在的缺陷SonarQube可以通过PMD,CheckStyle,Findbugs等等代码规则检测工具检测出潜在的缺陷。糟糕的复杂度分布文件、类、方法等,如果复杂度过高将难以改变,这会使得开发人员难以理解它们,且如果没有自动化的单元测试,对于程序中的任何组件的改变都将可能导致需要全面的回归测试。重复显然程序中包含大量复制粘贴的代码是质量低下的,SonarQube可以展示源码中重复严重的地方。注释不足或者过多没有注释将使代码可读性变差,特别是当不可避免地出现人员变动时,程序的可读性将大幅下降 而过多的注释又会使得开发人员将精力过多地花费在阅读注释上,亦违背初衷。缺乏单元测试SonarQube可以很方便地统计并展示单元测试覆盖率。糟糕的设计通过SonarQube可以找出循环,展示包与包、类与类之间的相互依赖关系,可以检测自定义的架构规则。通过SonarQube可以管理第三方的jar包,可以利用LCOM4检测单个任务规则的应用情况, 检测耦合。
2021年04月30日
1,244 阅读
0 评论
0 点赞
2021-04-29
恒创科技五一云聚惠低至2.5折,香港云服务器年付317元起
恒创科技又发布了五一期间的促销方案,全场爆品低至2.5折起,香港云服务器年付317元起。 本次活动持续至5月14日止,参与活动的产品包括云服务器、物理服务器、DDoS高防服务器等。这是香港SonderCloud Limited旗下的IDC品牌,成立于2010年了,主营中国香港、美国、日本、韩国等地骨干级机房优质资源,BGP国际多线网络,三网直连,CN2 GIA高速回国。https://www.henghost.com/act/2021workersday.shtml配置数据中心云系统盘带宽(CN2)购买周期购买周期1核1G中国香港50GB2M年317.001核2G中国香港50GB2M年454.002核2G中国香港50GB2M半年491.002核4G中国香港50GB2M半年718.00入门款的还算合适,其他的不是很合适,不如阿里云、腾讯云双11力度优惠大。
2021年04月29日
1,213 阅读
0 评论
1 点赞
2021-04-28
微信公众号开发之公众号基础配置
微信公众号开发的前提是我们要对公众号进行正确的配置。公众号的配置包括两部分:配置白名单,只有配置了白名单我们才能获取到access_token。配置服务器,正确配置服务器后,微信公众号才能将消息转到我们服务端进行处理。配置白名单白名单的配置比较简单。我们打开公众号,左侧找到【安全中心】,点击之后,找到【IP白名单】,点击【查看】按钮,在打开的界面,输入我们的服务器的 IP ,注意,这里输入的是 IP。启用服务器配置进入微信公众号后台,选择【开发】→【基本设置】,打开如下界面下面我们对服务器的几个参数进行将要说明:参数说明服务器地址(URL)我们在启用服务器配置时,微信会通过我们配置的服务器地址,发送一条 GET 请求。请求会携带以下参数序号参数名称描述1signature微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。2timestamp时间戳3nonce随机数4echostr随机字符串我们在请求中,通过检验 signature 对请求进行校验。若确认此次 GET 请求来自微信服务器,我们只需要原样返回 echostr 参数内容,代表接入成功,否则接入失败。TokenToken 可由我们任意填写,用作生成签名(该 Token 会和接口 URL 中包含的 Token 进行比对,从而验证安全性),主要用于后期调用接口使用。EncodingAESKeyEncodingAESKey 我们可以手动填写或随机生成,将用作消息体加解密密钥。消息加解密方式明文模式、兼容模式和安全模式。模式的选择与服务器配置在提交后都会立即生效,请开发者谨慎填写及选择。加解密方式的默认状态为明文模式,选择兼容模式和安全模式需要提前配置好相关加解密代码。后台代码后台代码,我们主要用于对 URL 的请求进行响应。首先我们需要定义工具类,用于签名验证SignUtil.java/** * 校验签名 * @param signature 签名 * @param timestamp 时间戳 * @param nonce 随机数 * @return true 成功,false 失败 */ public static boolean checkSignature(String signature,String timestamp, String nonce){ String checktext = null; if(null != signature){ //对Token,timestamp nonce 按字典排序 String [] paramArr = new String[] {token, timestamp, nonce}; Arrays.sort(paramArr); //将排序后的结果拼成一个字符串 String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]); try { MessageDigest md = MessageDigest.getInstance("SHA-1"); //对接后的字符串进行sha1加密 byte[] digest = md.digest(content.toString().getBytes()); checktext = byteToStr(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } //将加密后的字符串与signature进行对比 return checktext != null ? checktext.matches(signature.toUpperCase()) :false; } /** * 将字节数组转化为16进制字符串 * @return 字符串 */ private static String byteToStr(byte[] byteArrays) { String str=""; for (int i = 0; i < byteArrays.length; i++){ str += byteToHexStr(byteArrays[i]); } return str; } /** * 将字节转化为十六进制字符串 * @param myByte 字节 * @return 字符串 */ private static String byteToHexStr(byte myByte) { char[] Digit = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; char[] tempArr = new char[2]; tempArr[0] = Digit[(myByte >>> 4)&0X0F]; tempArr[1] = Digit[myByte & 0x0F]; String str = new String(tempArr); return str; }配置controller响应URL请求我们在微信公众号后台配置的URL就是我们后台对应的URL。并且是 GET 请求。增加WeChatController.java@RestController @RequestMapping("wechat") public class WeChatController { private final Logger logger = LoggerFactory.getLogger(WeChatController.class); /** * 服务器配置启用设置 * @param signature 签名 * @param timestamp 时间戳 * @param nonce 随机数 * @param echostr 随机字符串 * @return 随机字符串 * @throws Exception 异常信息 */ @GetMapping("official") public String authentication(@RequestParam("signature") String signature, @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce, @RequestParam("echostr") String echostr) throws Exception { if (SignUtil.checkSignature(signature, timestamp, nonce)) { System.out.println(echostr); return echostr; } return""; } }启用服务器配置后台代码配置完成后,我们上传到外网服务器,点击启用按钮,系统提示操作成功。
2021年04月28日
2,138 阅读
1 评论
2 点赞
2021-04-24
npm替换淘宝源
由于node下载第三方依赖包是从国外服务器下载,虽然没有被墙,但是下载的速度是非常的缓慢且有可能会出现异常。所以为了提高效率,我们还是把npm的镜像源替换成淘宝的镜像源。有几种方式供我们选择使用cnpm使用阿里定制的cnpm命令行工具代替默认的npm,输入以下代码$ npm install -g cnpm --registry=https://registry.npm.taobao.org检测是否安装成功$ cnpm -v安装成功之后,以后安装依赖包的方式和npm的是一样的,只是npm的命令换成是cnpm就可以了假如你已经习惯了使用npm的安装方式的,不想去下载阿里的cnpm命令工具的话,很简单,我们直接将node的仓库地址换成淘宝仓库地址即可单次使用$ npm install --registry=https://registry.npm.taobao.org永久使用在开发react-native的时候,不要使用cnpm!cnpm安装的模块路径比较奇怪,packager不能正常识别。所以,为了方便开发,我们最好是直接永久使用淘宝的镜像源直接命令行的设置$ npm config set registry https://registry.npm.taobao.org手动修改设置1.打开.npmrc文件(C:\Program Files\nodejs\node_modules\npm\npmrc,没有的话可以使用git命令行建一个( touch .npmrc),用cmd命令建会报错) 2.增加 registry =https://registry.npm.taobao.org 即可。检测是否修改成功// 配置后可通过下面方式来验证是否成功 npm config get registry // 或 npm info express注:如果想还原npm仓库地址的话,只需要在把地址配置成npm镜像就可以了npm config set registry https://registry.npmjs.org/
2021年04月24日
1,343 阅读
0 评论
2 点赞
2021-04-24
Spring Boot 2.0+ MyBatis-Plusg通过注解动态切换数据源
在Spring Boot 2.0+ ByBatis-Plus动态切换数据源 - 香草物语 (lisen.cc)中我们介绍了如何实现多个数据源的切换。但是我们切换数据源时,是通过DynamicDataSourceContextHolder手动切换的,如果每次都这么设置,明显不恰当。所以我们这里介绍一下通过注解的方式实现数据源的切换。定义注解/** * 自定义多数据源切换注解 * * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准 * 如果传递value,则切换到value对应的数据源 * * @author laughing */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface DataSource { String value() default ""; }优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准如果传递value,则切换到value对应的数据源定义切面/** * 动态数据源切面拦截 * 请注意:这里order一定要小于tx:annotation-driven的order,即先执行DynamicDataSourceAspectAdvice切面,再执行事务切面,才能获取到最终的数据源 * * @author laughing * @version 1.0 */ @Slf4j @Aspect @Component @Order(1) @EnableAspectJAutoProxy(proxyTargetClass = true) public class DynamicDataSourceAspect { @Pointcut("@annotation(cc.lisen.dynamicdatasource.annotation.DataSource) || @within(cc.lisen.dynamicdatasource.annotation.DataSource)") public void dsPointCut() { } @Around("dsPointCut()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = servletRequestAttributes.getRequest(); try { //1.取注解的参数 DataSource dataSource = getDataSource(joinPoint); if (dataSource != null && !StringUtils.isEmpty(dataSource.value())) { DynamicDataSourceContextHolder.setDataSourceKey(dataSource.value()); return joinPoint.proceed(); } //2.模拟参数 String dynamicDataSource = request.getParameter("dynamicDataSource"); if (!StringUtils.isEmpty(dynamicDataSource)) { DynamicDataSourceContextHolder.setDataSourceKey(dynamicDataSource); return joinPoint.proceed(); } return joinPoint.proceed(); } finally { //每次使用完成,清空数据源 DynamicDataSourceContextHolder.clearDataSourceKey(); } } /** * 获取需要切换的数据源 */ public DataSource getDataSource(ProceedingJoinPoint point) { MethodSignature signature = (MethodSignature) point.getSignature(); DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); if (Objects.nonNull(dataSource)) { return dataSource; } return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class); } }测试获取数据源1的数据@DataSource(value = "dynamicDataSourceOne") @GetMapping("listTableOne") public List<TableOne> listTableOne() { return tableOneMapper.selectList(new QueryWrapper<>()); }获取数据源2的数据@DataSource(value = "dynamicDataSourceTwo") @GetMapping("listTableTwo") public List<TableTwo> listTableTwo(){ return tableTwoMapper.selectList(new QueryWrapper<>()); }根据参数,系统动态切换数据源@DataSource @GetMapping("tableList") public String tableList(){ return "当前数据源为:"+DynamicDataSourceContextHolder.getDataSourceKey(); }
2021年04月24日
1,284 阅读
3 评论
1 点赞
2021-04-24
Typecho使用又拍云CDN后无法登陆后台解决办法
{mtitle title="问题现象"/}进入typecho后台,点击登录按钮,系统没有任何反应,仍然停留在当前登录页面。{mtitle title="解决措施"/}隐藏内容,请前往内页查看详情
2021年04月24日
1,571 阅读
3 评论
0 点赞
1
...
28
29
30
...
53