SpringCloud : 接入 微信公众号平台(一)、接入微信请求(支持多公众号)

Maven:

Feign 版本10.1.0

Spring 版本 5.1.5.RELEASE

SpringBoot 版本 2.1.5.RELEASE

SpringCloud 版本 2.1.1.RELEASE

Weixin-java 版本 3.7.0,链接

<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.60</version></dependency><dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version></dependency><dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-mp</artifactId> <version>3.7.0</version></dependency>

 

公共网关接口: https://你的域名/gate/微信公众号appId

其中 validAuth 方法负责校验签名,微信服务器会发送一个 普通的GET请求,命中该方法处理。

msgForward 方法负责消息的转发,微信服务器会发送一个xml协议的POST请求,命中该方法。

 

消息的加解密参考:MP_消息的加解密 ,更多使用技巧。

消息路由:MP_微信消息路由器。

源码参考:WxPortalController.java 。

import com.phpdragon.wechat.proxy.config.WeChatConfig;import com.phpdragon.wechat.proxy.config.WechatEventConfig;import com.phpdragon.wechat.proxy.handler.EventHandler;import com.phpdragon.wechat.proxy.handler.LogHandler;import com.phpdragon.wechat.proxy.handler.MsgHandler;import com.phpdragon.wechat.proxy.handler.TplMsgFeedbackHandler;import lombok.extern.slf4j.Slf4j;import me.chanjar.weixin.common.api.WxConsts;import me.chanjar.weixin.mp.api.WxMpMessageRouter;import me.chanjar.weixin.mp.api.WxMpService;import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.lang.Nullable;import org.springframework.web.bind.annotation.*;import java.util.Objects;/** * 参考:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html */@Slf4j@RestController@RequestMapping("/gate/")public class GateController { @Autowired private WeChatConfig weChatConfig; @Autowired private LogHandler logHandler; @Autowired private EventHandler eventHandler; @Autowired private TplMsgFeedbackHandler tplMsgFeedbackHandler; @Autowired private MsgHandler msgHandler; /** * 微信验签 * * @param signature * @param timestamp * @param nonce * @param echostr * @return */ @ResponseBody @GetMapping(value = "/{app_id}", produces = "text/plain;charset=utf-8") public String validAuth(@PathVariable("app_id") String appId, @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) { log.info("接收到来自微信服务器的认证请求:[appId:{},{}, {}, {}, {}]", appId, signature, timestamp, nonce, echostr); if (StringUtils.isAnyBlank(appId, signature, timestamp, nonce, echostr)) { throw new IllegalArgumentException("请求参数非法!"); } WxMpService wxMpService = weChatConfig.getWxMpService(appId); if (wxMpService.checkSignature(timestamp, nonce, signature)) { return echostr; } return "请求非法"; } /** * 消息转发---中转站 * 每次微信端的消息都会来到这里进行分发 * 对微信公众号相关的一些动作,都以报文形式推送到该接口, * 根据请求的类型,进行路由分发处理 */ @PostMapping(value = "/{app_id}", produces = "application/xml; charset=UTF-8") public String msgForward(@PathVariable("app_id") String appId, @RequestParam(name = "encrypt_type", required = false) String encryptType, @RequestParam(name = "signature", required = false) String signature, @RequestParam(name = "timestamp", required = false) String timestamp, @RequestParam(name = "nonce", required = false) String nonce, @RequestParam(name = "msg_signature", required = false) String msgSignature, @RequestBody String requestBody) { log.info("接收微信服务器请求:[signature=[{}], encType=[{}], msgSignature=[{}]," + " timestamp=[{}], nonce=[{}], requestBody=[n{}n] ", signature, encryptType, msgSignature, timestamp, nonce, requestBody); String outMsg = ""; try { outMsg = this.handleMsg(appId, encryptType, signature, timestamp, nonce, msgSignature, requestBody); log.info("返回响应消息,outMsg:n{}", outMsg); } catch (Exception e) { log.error("响应请求异常,error:{},{}", e.getMessage(), e); } return outMsg; } /** * 处理消息的入口 * * @param appId * @param signature * @param encryptType * @param msgSignature * @param timestamp * @param nonce * @param requestBody * @return */ @Nullable private String handleMsg(String appId, String encryptType, String signature, String timestamp, String nonce, String msgSignature, String requestBody) { WxMpService wxMpService = weChatConfig.getWxMpService(appId); if ("aes".equals(encryptType)) { if (!wxMpService.checkSignature(timestamp, nonce, signature)) { throw new IllegalArgumentException("非法请求,可能属于伪造的请求!"); } } boolean isEncrypt = "aes".equals(encryptType); WxMpXmlMessage inMessage; if (isEncrypt) { inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxMpService.getWxMpConfigStorage(), timestamp, nonce, msgSignature); } else { inMessage = WxMpXmlMessage.fromXml(requestBody); } WxMpXmlOutMessage outMessage = this.buildMsgRouter(wxMpService).route(inMessage); if (Objects.isNull(outMessage)) { return ""; } String outMsg = outMessage.toXml(); if (isEncrypt) { WxMpCryptUtil cryptUtil = new WxMpCryptUtil(wxMpService.getWxMpConfigStorage()); outMsg = cryptUtil.encrypt(outMsg); } return outMsg; } /** * 构造消息路由处理器 * * @param wxMpService */ private WxMpMessageRouter buildMsgRouter(final WxMpService wxMpService) { final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService); // 记录所有事件的日志 newRouter.rule().handler(this.logHandler).next(); // 处理事件请求 for (String eventKey : WechatEventConfig.ALL_EVENTS) { newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) .event(eventKey).handler(this.eventHandler) .end(); } //处理模版消息的发送反馈 newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) .event(WxConsts.EventType.TEMPLATE_SEND_JOB_FINISH) .handler(this.tplMsgFeedbackHandler) .end(); // 默认,转发消息给客服人员 newRouter.rule().async(false).handler(this.msgHandler).end(); return newRouter; }}

 

LogHandler:

import lombok.extern.slf4j.Slf4j;import me.chanjar.weixin.common.session.WxSessionManager;import me.chanjar.weixin.mp.api.WxMpMessageHandler;import me.chanjar.weixin.mp.api.WxMpService;import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;import org.springframework.stereotype.Component;import java.util.Map;/** * 对所有接收到的消息输出日志,也可进行持久化处理 * <p> * Created by FirenzesEagle on 2016/7/27 0027. * Email:liumingbo2008@gmail.com */@Slf4j@Componentpublic class LogHandler implements WxMpMessageHandler { @Override public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService, WxSessionManager sessionManager) { //TODO: 保存消息日志 //wXLogService.doSaveReceiveLog(inMessage); log.info("n接收到事件请求,内容:【{}】", wxMessage.toString()); return null; }}

 

TplMsgFeedbackHandler:

import com.phpdragon.wechat.proxy.logic.MsgTplLogic;import lombok.extern.slf4j.Slf4j;import me.chanjar.weixin.common.error.WxErrorException;import me.chanjar.weixin.common.session.WxSessionManager;import me.chanjar.weixin.mp.api.WxMpMessageHandler;import me.chanjar.weixin.mp.api.WxMpService;import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.util.Map;/** * 处理事件 */@Slf4j@Componentpublic class TplMsgFeedbackHandler implements WxMpMessageHandler { @Autowired private MsgTplLogic msgTplLogic; @Override public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> map, WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException { msgTplLogic.updateLog(wxMessage); return null; }}

 

MsgHandler:

import lombok.extern.slf4j.Slf4j;import me.chanjar.weixin.common.session.WxSessionManager;import me.chanjar.weixin.mp.api.WxMpMessageHandler;import me.chanjar.weixin.mp.api.WxMpService;import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;import org.springframework.stereotype.Component;import java.util.Map;/** * 处理客户消息 */@Slf4j@Componentpublic class MsgHandler implements WxMpMessageHandler { @Override public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService, WxSessionManager sessionManager) { return WxMpXmlOutMessage.TEXT().fromUser(wxMessage.getToUser()) .toUser(wxMessage.getFromUser()).content("您好,正在处理您的请求").build(); //转发给客服// return WxMpXmlOutMessage// .TRANSFER_CUSTOMER_SERVICE().fromUser(wxMessage.getToUser())// .toUser(wxMessage.getFromUser()).build(); }}

 

SpringCloud : 接入 微信公众号平台(一)、接入微信请求(支持多公众号)

EventHandler:

import lombok.extern.slf4j.Slf4j;import me.chanjar.weixin.common.session.WxSessionManager;import me.chanjar.weixin.mp.api.WxMpMessageHandler;import me.chanjar.weixin.mp.api.WxMpService;import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;import org.springframework.stereotype.Component;import java.util.Map;/** * 处理事件 */@Slf4j@Componentpublic class EventHandler implements WxMpMessageHandler { @Override public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService, WxSessionManager sessionManager) { return WxMpXmlOutMessage.TEXT().fromUser(wxMessage.getToUser()) .toUser(wxMessage.getFromUser()).content("您好,正在处理您的请求").build(); }}

 

WeChatConfig:

import me.chanjar.weixin.mp.api.WxMpService;import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import redis.clients.jedis.JedisPool;@Configurationpublic class WeChatConfig { //TODO: 你的域名 public static final String CURRENT_HOST = "你的域名"; @Autowired private JedisPool jedisPool; /** * 取mp SDK * * @param appId * @return */ public WxMpService getWxMpService(String appId) { WxMpRedisConfigImpl mpConfig = new WxMpRedisConfigImpl(jedisPool); //TODO: 用数据库进行保存 mpConfig.setAppId("微信ID"); mpConfig.setSecret("微信密钥"); mpConfig.setToken("微信通讯token"); mpConfig.setAesKey("加密密钥"); WxMpService wxMpService = new WxMpServiceImpl(); wxMpService.setWxMpConfigStorage(mpConfig); return wxMpService; }}

 

接入到此完毕,使用官方推荐工具调试一下看看是否可通,微信公众平台接口调试工具!。

 

 

PS:

公众号开发文档wiki

Java开发微信公众号之整合weixin-java-tools框架开发微信公众号

从零实现 Spring Boot 2.0 整合 weixin-java-mp(weixin-java-tools) 获取 openId,用于微信授权

 

Demo 列表

  1. 微信支付 Demo:GitHub、码云
  2. 企业号/企业微信 Demo:GitHub、码云
  3. 微信小程序 Demo:GitHub、码云
  4. 开放平台 Demo:GitHub、码云
  5. 公众号 Demo:
    • 使用 Spring MVC 实现的公众号 Demo:GitHub、码云
    • 使用 Spring Boot 实现的公众号 Demo(支持多公众号):GitHub、码云
    • 含公众号和部分微信支付代码的 Demo:GitHub、码云

 

相关文章