微信开发者接入文档 : https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319
微信公众平台测试账号申请: http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
一、前言
首先,在要做微信项目开发前,大家都会去了解微信公众号的类型和注册流程,以及不同公众号的功能使用权限,这个我前面文章也有过介绍,做微信开发公众号最起码得是一个已认证的服务号, 强调一下,这里我是指企业项目哈;另外订阅号现在是不支持认证了,所以订阅号没有开发者相关的权限,因此订阅号只能够大家自己玩玩自媒体啦,企业项目开发的话还是得申请已认证的服务号或者已认证的企业号;当然如果是自己学习研究的话,直接去微信公众平台申请测试号即可,不过这里提前说下,测试号功能权限有限哦,不过大部分常用接口权限还都是有的,日常企业开发或者自己玩用来调试足够了。
另外,关于微信公众号的类型和注册流程请参考这篇: Java微信公众号开发之初步认识微信公众平台
其次,本篇文章我主要记录如何将开源微信SDK框架所提供的demo:https://github.com/binarywang/weixin-java-mp-demo-springmvc 接入到我们自己的项目中,用于微信公众号后台项目的开发,避免重复造轮子,而且人家写的也很好可以借鉴借鉴,因为里面有一套写的比较好的路由规则和微信接入入口的接口,这些都是微信开发必不可少的工作,整合了这个demo,就不用我们自己再去写了,接下来关于写在前面的话,比较重要,请大家一定要认真阅读;
二、写在前面的话
我项目所使用的架构师基于传统的: Spring+SpringMVC+Mybatis+Shiro ,以下简称SSM,若你所使用的框架是SpringBoot快速开发框架,请移步这篇文章: SpringBoot 系列教程(六十五):Spring Boot整合WxJava开发微信公众号
1、Spring+SpringMVC+Mybatis框架
在整合微信框架weixin-java-tools之前,我假设你们已经使用Spring+SpringMVC+Mybatis技术栈搭建好了一套SSM框架。我要做的就是把 weixin-java-mp-demo-springmvc 这个demo项目里面封装的一些比较好的类加到我们自己的项目框架中去。
2、weixin-java-tools介绍
微信系列项目开发我们选用当下微信比较热门的框架WxJava,前名叫weixin-java-tools,后改名叫 WxJava (微信开发 Java SDK),是一款涵盖了微信支付、开放平台、小程序、企业微信/企业号和公众号等后端开发的SDK,该SDK封装了微信公众平台上大部分Api接口,我们开发时直接调用这个SDK里面的接口即可,同时作者针对WxJava 这个SDK还提供了一些接入的Demo,可能是为了方便开发者更快的介入这款SDK吧,而我们的主要目的就是引入WxJava 依赖和作者提供接入的demo即可。
本次我们单纯的是为了开发微信公众号项目,那么我们只需要使用到weixin-java-tools中的微信公众号模块weixin-java-mp ,WxJava框架如下:
3、Maven引用微信公众号SDK方式
Maven引入微信公众号模块依赖如下:
<!-- 微信框架 参考:https://github.com/Wechat-Group/weixin-java-tools --><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-mp</artifactId><version>3.0.0</version></dependency>
4、内网穿透
关于微信开发,有个东西很重要,微信开发需要使用内网穿透才可以进行开发调试,也就是将本地localhost地址通过内网穿透,映射到外网去,通过外网才可以和微信的服务器进行消息通讯,数据的传输,这里我用过好几种内网穿透,为了避免大家不知道怎么选择,我推荐大家选择Natapp,Natapp很稳定,速度也快,https://natapp.cn/ ,单纯的微信开发调试选择购买9元每个月的隧道就行了,免费的域名随时变动,而且不稳定,因此不推荐大家使用,具体使用和配置参考:内网穿透常用的工具
说明: 内网穿透是微信开发必不可少的,上面给大家介绍了使用natapp并不是给他打广告,也没有任何合作,我纯粹是为了大家少走弯路才提及哦,市场上内网穿透种类也有很多种,大家可以自行选择。
5. 微信公众平台测试账号申请与功能权限列表
微信公众平台测试账号申请: http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
接口功能权限列表:
三、整合weixin-java-mp-demo-springmvc
1、Demo项目
- 在码云和
GitHub
上均可访问,会尽量保持同步,请根据自己情况选用。 - 一般来说,
Github
上的版本应该是最新的,但也有可能没及时同步,此种情况下请以Github
上的版本为准,有问题也请在Github
对应项目Issues
页面提问)。 - 欢迎提供更多的 demo 实现。
2、Spring Boot Starter
实现
- 微信支付:点击查看使用方法
- 微信公众号:点击查看使用方法
- 微信小程序:点击查看使用方法
3、Demo 列表
- 微信支付 Demo:GitHub、码云
- 企业号/企业微信 Demo:GitHub、码云
- 微信小程序 Demo:GitHub、码云
- 开放平台 Demo:GitHub、码云
- 公众号 Demo:
- 使用
Spring MVC
实现的公众号 Demo:GitHub、码云 - 使用
Spring Boot
实现的公众号 Demo(支持多公众号):GitHub、码云 - 含公众号和部分微信支付代码的 Demo:GitHub、码云
- 使用
注: 如果你的项目是SpringBoot框架, 可以下载Demo列表中的SpringBoot版,接入方式都一样,参照后续步骤
4、下载weixin-java-demo-springmvc的demo
下载地址: https://github.com/Wechat-Group/weixin-java-demo-springmvc
5、微信路由WeixinService核心类
demo下载下来后,看一下WeixinService代码,里面涉及到作者自己写的路由,如果不想自己写路由,可以直接借鉴复用
package com.github.binarywang.demo.spring.service;import javax.annotation.PostConstruct;import me.chanjar.weixin.mp.constant.WxMpEventConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.github.binarywang.demo.spring.config.WxMpConfig;
import com.github.binarywang.demo.spring.handler.AbstractHandler;
import com.github.binarywang.demo.spring.handler.KfSessionHandler;
import com.github.binarywang.demo.spring.handler.LocationHandler;
import com.github.binarywang.demo.spring.handler.LogHandler;
import com.github.binarywang.demo.spring.handler.MenuHandler;
import com.github.binarywang.demo.spring.handler.MsgHandler;
import com.github.binarywang.demo.spring.handler.NullHandler;
import com.github.binarywang.demo.spring.handler.StoreCheckNotifyHandler;
import com.github.binarywang.demo.spring.handler.SubscribeHandler;
import com.github.binarywang.demo.spring.handler.UnsubscribeHandler;import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;import static me.chanjar.weixin.common.api.WxConsts.*;/*** * @author Binary Wang**/
@Service
public class WeixinService extends WxMpServiceImpl {private final Logger logger = LoggerFactory.getLogger(this.getClass());@Autowiredprotected LogHandler logHandler;@Autowiredprotected NullHandler nullHandler;@Autowiredprotected KfSessionHandler kfSessionHandler;@Autowiredprotected StoreCheckNotifyHandler storeCheckNotifyHandler;@Autowiredprivate WxMpConfig wxConfig;@Autowiredprivate LocationHandler locationHandler;@Autowiredprivate MenuHandler menuHandler;@Autowiredprivate MsgHandler msgHandler;@Autowiredprivate UnsubscribeHandler unsubscribeHandler;@Autowiredprivate SubscribeHandler subscribeHandler;private WxMpMessageRouter router;@PostConstructpublic void init() {final WxMpInMemoryConfigStorage config = new WxMpInMemoryConfigStorage();config.setAppId(this.wxConfig.getAppid());// 设置微信公众号的appidconfig.setSecret(this.wxConfig.getAppsecret());// 设置微信公众号的app corpSecretconfig.setToken(this.wxConfig.getToken());// 设置微信公众号的tokenconfig.setAesKey(this.wxConfig.getAesKey());// 设置消息加解密密钥super.setWxMpConfigStorage(config);this.refreshRouter();}private void refreshRouter() {final WxMpMessageRouter newRouter = new WxMpMessageRouter(this);// 记录所有事件的日志newRouter.rule().handler(this.logHandler).next();// 接收客服会话管理事件newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION).handler(this.kfSessionHandler).end();newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION).handler(this.kfSessionHandler).end();newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION).handler(this.kfSessionHandler).end();// 门店审核事件newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(WxMpEventConstants.POI_CHECK_NOTIFY).handler(this.storeCheckNotifyHandler).end();// 自定义菜单事件newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(MenuButtonType.CLICK).handler(this.getMenuHandler()).end();// 点击菜单连接事件newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(MenuButtonType.VIEW).handler(this.nullHandler).end();// 关注事件newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(EventType.SUBSCRIBE).handler(this.getSubscribeHandler()).end();// 取消关注事件newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(EventType.UNSUBSCRIBE).handler(this.getUnsubscribeHandler()).end();// 上报地理位置事件newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(EventType.LOCATION).handler(this.getLocationHandler()).end();// 接收地理位置消息newRouter.rule().async(false).msgType(XmlMsgType.LOCATION).handler(this.getLocationHandler()).end();// 扫码事件newRouter.rule().async(false).msgType(XmlMsgType.EVENT).event(EventType.SCAN).handler(this.getScanHandler()).end();// 默认newRouter.rule().async(false).handler(this.getMsgHandler()).end();this.router = newRouter;}public WxMpXmlOutMessage route(WxMpXmlMessage message) {try {return this.router.route(message);}catch (Exception e) {this.logger.error(e.getMessage(), e);}return null;}public boolean hasKefuOnline() {try {WxMpKfOnlineList kfOnlineList = this.getKefuService().kfOnlineList();return kfOnlineList != null && kfOnlineList.getKfOnlineList().size() > 0;}catch (Exception e) {this.logger.error("获取客服在线状态异常: " + e.getMessage(), e);}return false;}protected MenuHandler getMenuHandler() {return this.menuHandler;}protected SubscribeHandler getSubscribeHandler() {return this.subscribeHandler;}protected UnsubscribeHandler getUnsubscribeHandler() {return this.unsubscribeHandler;}protected AbstractHandler getLocationHandler() {return this.locationHandler;}protected MsgHandler getMsgHandler() {return this.msgHandler;}protected AbstractHandler getScanHandler() {return null;}}
3、接入项目
从这一步开始,我们就把上面的weixin-java-demo-springmvc demo代码接入到我们已经搭建好框架的项目中去
1、 首先在我的项目中新建包名为wechat
2、然后将下载的Demo中包aop、builder、config、controller、dto、handler、service包括一个配置文件wx.properties复制到我们自己的项目中
移植到我们自己项目中的效果图如下,红框是移植过来的文件和配置:
3、这一步我们需要将上一步中移植过来的的wx.properties加载到Spring容器中,随着web.xml一起加载初始化,具体见下面截图红框框出来的,在我们自己项目中配置wx.properties如下:
wx.properties内容展示:
#=========微信公众号开发基本配置============
#微信公众号的appid
wx_appid=xxx
#微信公众号的appsecret
wx_appsecret=xxx
#微信公众号的token
wx_token=xxx
#微信公众号的消息加解密密钥aeskey
wx_aeskey=WoDWc9c9jseK4gYzOcZChVaGDkcLTgmoS3O2F7KZtWV
加载到Spring容器如下截图中红框所示
4、需要在wx.properties中配置微信公众平台的几个参数来接入微信服务器的验证参数 ,这里的=后面数值都要填上
#=========微信公众号开发基本配置============
#微信公众号的appid
wx_appid=xxx
#微信公众号的appsecret
wx_appsecret=xxx
#微信公众号的token
wx_token=xxx
#微信公众号的消息加解密密钥aeskey
wx_aeskey=WoDWc9c9jseK4gYzOcZChVaGDkcLTgmoS3O2F7KZtWV
5、微信的入口 :WxMpPortalController ,这里是跟微信公众平台配置我们项目服务器的URL交互类
package com.thinkgem.jeesite.modules.wechat.controller;import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;import com.thinkgem.jeesite.modules.wechat.service.WXLogService;
import com.thinkgem.jeesite.modules.wechat.service.WeixinService;/*** * @ClassName: WxMpPortalController* @Description: 微信主入口* @author CaoWenCao* @date 2018年6月12日 下午10:13:57*/
@RestController
@RequestMapping("/wechat/portal")
public class WxMpPortalController {@Autowiredprivate WeixinService wxService;@Autowiredprivate WXLogService wXLogService;private final Logger logger = LoggerFactory.getLogger(this.getClass());/** 微信验签*/@ResponseBody@GetMapping(produces = "text/plain;charset=utf-8")public String authGet(@RequestParam(name = "signature", required = false) String signature, @RequestParam(name = "timestamp", required = false) String timestamp, @RequestParam(name = "nonce", required = false) String nonce,@RequestParam(name = "echostr", required = false) String echostr) {this.logger.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature, timestamp, nonce, echostr);if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {throw new IllegalArgumentException("请求参数非法,请核实!");}if (this.getWxService().checkSignature(timestamp, nonce, signature)) {return echostr;}return "非法请求";}/** 消息转发---中转站 每次微信端的消息都会来到这里进行分发 对微信公众号相关的一些动作,都以报文形式推送到该接口,根据请求的类型,进行路由分发处理*/@ResponseBody@PostMapping(produces = "application/xml; charset=UTF-8")public String post(@RequestBody String requestBody, @RequestParam("signature") String signature, @RequestParam(name = "encrypt_type", required = false) String encType, @RequestParam(name = "msg_signature", required = false) String msgSignature,@RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) {this.logger.info("\n接收微信请求:[signature=[{}], encType=[{}], msgSignature=[{}]," + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", signature, encType, msgSignature, timestamp, nonce, requestBody);if (!this.wxService.checkSignature(timestamp, nonce, signature)) {throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");}String out = null;if (encType == null) {// 明文传输的消息WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);// 如果是明文传输 ,保存 微信接收 信息,保存到数据库,用于微信消息管理中的客服互动wXLogService.doSaveReceiveLog(inMessage);//this.logger.info("\n保存微信接受信息WxMpXmlMessage:\n{}", inMessage);WxMpXmlOutMessage outMessage = this.getWxService().route(inMessage);if (outMessage == null) {return "";}out = outMessage.toXml();// 日志出口时,保存微信发出去的XML(给用户)wXLogService.doSaveMsgLogOut(outMessage);//this.logger.info("\n保存微信输出日志WxMpXmlOutMessage信息:\n{}", outMessage);}else if ("aes".equals(encType)) {// aes加密的消息WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, this.getWxService().getWxMpConfigStorage(), timestamp, nonce, msgSignature);this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString());// 如果是密文传输 ,保存 微信接收 信息wXLogService.doSaveReceiveLog(inMessage);WxMpXmlOutMessage outMessage = this.getWxService().route(inMessage);if (outMessage == null) {return "";}out = outMessage.toEncryptedXml(this.getWxService().getWxMpConfigStorage());// 日志出口时,保存微信发出去的XML(给用户)wXLogService.doSaveMsgLogOut(outMessage);this.logger.info("\n保存微信输出日志WxMpXmlOutMessage信息:\n{}", outMessage);// 保存回复消息记录//wXLogService.doSaveReplyLog(outMessage);}this.logger.debug("\n组装回复信息:{}", out);return out;}protected WeixinService getWxService() {return this.wxService;}}
6、整合完成后项目完整截图
四、对接微信公众平台配置
1、消息传递流程
关于微信公众号后台开发发出消息和收到响应结果的一个流程,大家看下面这张图
这是大家在公众号后台回复关键字的情况。那么这个消息是怎么样一个传递流程呢?我们来看看下面这张图:
这张图,我给大家稍微解释下:
首先"4" 这个字符从公众号上发送到了微信服务器
接下来微信服务器会把 “4” 转发到我自己的服务器上
我们服务器收到 “4” 这个字符之后,就去数据库中查询,将查询的结果,按照腾讯要求的 XML 格式进行返回
微信服务器把从我的服务器收到的信息,再发回到微信上,于是小伙伴们就看到了返回结果了
大致的流程就是这个样子。
接下来我们就来看一下实现细节。
2. 公众号后台配置
开发的第一步,是微信服务器要验证我们自己的服务器是否有效。
首先我们登录微信公众平台官网后,在公众平台官网的 开发-基本设置 页面,勾选协议成为开发者,然后点击“修改配置”按钮,填写:
- 服务器地址(URL)
- Token
- EncodingAESKey
开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带四个参数:
参数 | 描述 |
---|---|
signature | 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 |
timestamp | 时间戳 |
nonce | 随机数 |
echostr | 随机字符串 |
原理: 开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。
signature验证结合了token,和请求中的timestamp参数,nonce参数
加密/校验流程如下:
- 1. 将token、timestamp、nonce三个参数进行字典排序
- 2. 将三个参数字符串拼接成一个字符串进行SHA散列加密
- 3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
解释:
URL: 这里的 URL 配置好之后,我们需要针对这个 URL 开发两个接口,一个是 GET 请求的接口,这个接口用来做服务器有效性验证;另一个则是 POST 请求的接口,这个用来接收微信服务器发送来的消息。也就是说,微信服务器的消息都是通过 POST 请求发给我的。
Token: 可由开发者可以任意填写,用作生成签名(该 Token 会和接口 URL 中包含的 Token 进行比对,从而验证安全性)。
EncodingAESKey: 由开发者手动填写或随机生成,将用作消息体加解密密钥。
同时,开发者可选择消息加解密方式:明文模式、兼容模式和安全模式。明文模式就是我们自己的服务器收到微信服务器发来的消息是明文字符串,直接就可以读取并且解析,安全模式则是我们收到微信服务器发来的消息是加密的消息,需要我们手动解析后才能使用,一般无特殊要求默认使用明文模式。
3、服务器有效性校验Rest接口
我们需要在微信公众号后台配置URL访问这个Rest接口,这是与微信公众平台交互的门户入口。
package com.thinkgem.jeesite.modules.wechat.controller;import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;import com.thinkgem.jeesite.modules.wechat.service.WXLogService;
import com.thinkgem.jeesite.modules.wechat.service.WeixinService;/*** * @ClassName: WxMpPortalController* @Description: 微信主入口* @author CaoWenCao* @date 2018年6月12日 下午10:13:57*/
@RestController
@RequestMapping("/wechat/portal")
public class WxMpPortalController {@Autowiredprivate WeixinService wxService;@Autowiredprivate WXLogService wXLogService;private final Logger logger = LoggerFactory.getLogger(this.getClass());/** 微信验签*/@ResponseBody@GetMapping(produces = "text/plain;charset=utf-8")public String authGet(@RequestParam(name = "signature", required = false) String signature, @RequestParam(name = "timestamp", required = false) String timestamp, @RequestParam(name = "nonce", required = false) String nonce,@RequestParam(name = "echostr", required = false) String echostr) {this.logger.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature, timestamp, nonce, echostr);if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {throw new IllegalArgumentException("请求参数非法,请核实!");}if (this.getWxService().checkSignature(timestamp, nonce, signature)) {return echostr;}return "非法请求";}/** 消息转发---中转站 每次微信端的消息都会来到这里进行分发 对微信公众号相关的一些动作,都以报文形式推送到该接口,根据请求的类型,进行路由分发处理*/@ResponseBody@PostMapping(produces = "application/xml; charset=UTF-8")public String post(@RequestBody String requestBody, @RequestParam("signature") String signature, @RequestParam(name = "encrypt_type", required = false) String encType, @RequestParam(name = "msg_signature", required = false) String msgSignature,@RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) {this.logger.info("\n接收微信请求:[signature=[{}], encType=[{}], msgSignature=[{}]," + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", signature, encType, msgSignature, timestamp, nonce, requestBody);if (!this.wxService.checkSignature(timestamp, nonce, signature)) {throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");}String out = null;if (encType == null) {// 明文传输的消息WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);// 如果是明文传输 ,保存 微信接收 信息,保存到数据库,用于微信消息管理中的客服互动wXLogService.doSaveReceiveLog(inMessage);//this.logger.info("\n保存微信接受信息WxMpXmlMessage:\n{}", inMessage);WxMpXmlOutMessage outMessage = this.getWxService().route(inMessage);if (outMessage == null) {return "";}out = outMessage.toXml();// 日志出口时,保存微信发出去的XML(给用户)wXLogService.doSaveMsgLogOut(outMessage);//this.logger.info("\n保存微信输出日志WxMpXmlOutMessage信息:\n{}", outMessage);}else if ("aes".equals(encType)) {// aes加密的消息WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, this.getWxService().getWxMpConfigStorage(), timestamp, nonce, msgSignature);this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString());// 如果是密文传输 ,保存 微信接收 信息wXLogService.doSaveReceiveLog(inMessage);WxMpXmlOutMessage outMessage = this.getWxService().route(inMessage);if (outMessage == null) {return "";}out = outMessage.toEncryptedXml(this.getWxService().getWxMpConfigStorage());// 日志出口时,保存微信发出去的XML(给用户)wXLogService.doSaveMsgLogOut(outMessage);this.logger.info("\n保存微信输出日志WxMpXmlOutMessage信息:\n{}", outMessage);// 保存回复消息记录//wXLogService.doSaveReplyLog(outMessage);}this.logger.debug("\n组装回复信息:{}", out);return out;}protected WeixinService getWxService() {return this.wxService;}}
4、关于验证服务器地址的有效性
在配置我们自己开发的后台管理系统对接微信公众平台之前(也叫做接入开发者),我们来看一下后台管理系统需要哪些参数:
- appId : 微信appId
- secret : 微信secret
- token : 微信token
- aesKey : 微信加解密密钥(用到消息加解密需配置)
在我们自己的后台项目配置文件中里配置这4个参数,接下来就是配置URL了,这个URL就是微信公众平台服务器跟我们自己的后台服务器产生事件消息推送的一根桥梁线,所以URL需要填写地址如:http://xxxx.natapp1.cc/greenwx/wechat/portal 。
5、关于事件推送
URL是用户与微信公众号交互时,产生的一些事件推送,微信服务器将这些事件推送到我们服务器的一个地址,填写了我们服务器的地址后,微信服务器就知道往这个URL所在的服务器推送消息,就可以产生交互。
- 具体的事件推送有如下这些:
- Get请求:
上面WxMpPortalController中有两个方法,这两个方法是微信服务器与我们自身服务器交流的一个门户入口,是连接微信服务器的大门,你需要理解的是,默认的微信验签会走authGet这个方法,请求方式是get,前面填写的4个参数就会在这个方法里走验签逻辑,验签不通过无法接入开发者模式;
- Post请求
另外一个接口Post的作用就是当用户在与微信公众号事件推送时,微信服务器会把XML格式的消息通过我们填写的这个URL地址推送到我们后台服务器,这个时候是请求接口post, 请求方式是也是post,转发到post这个方法的接口上时,这个方法会根据消息类型判断,然后走路由转发,将请求转发到各个handler进行处理;
- 最后
到此为止,接入完成,可以开始调SDK接口开发微信相关功能了,因为路由和服务器验证等等接口不用我们写了,这样我们只关注功能的实现就行了,框架的对接借鉴了demo中一些比较好的封装类,为开发时间节点省去了不少时间,如果对此文章有不懂流程的,请评论里留下问题,我会回复;