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_微信消息路由器。
源碼參考: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 @Component public 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 @Component public 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 @Component public 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(); } }
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 @Component public 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; @Configuration public 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:
Java開發微信公眾號之整合weixin-java-tools框架開發微信公眾號
從零實現 Spring Boot 2.0 整合 weixin-java-mp(weixin-java-tools) 獲取 openId,用於微信授權
Demo 列表
