一、背景
在上一节中,我们知道如何接入微信公众号,但是之后公众号会与我们进行交互,那么微信公众号如何通知到我们自己的服务器呢?我们知道我们接入的时候提供的url是 GET
/mp/entry
,那么公众号之后产生的事件将会以 POST
/mp/entry
发送到我们自己的服务器上。
二、代码实现,此处还是使用 weixin-java-mp 这个框架实现
1、引入 weixin-java-mp
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.0.0</version>
</dependency>
2、编写 配置
@Configuration
public class WxMpConfiguration {
@Autowired
private WxMpProperties wxMpProperties;
@Autowired
private SubscribeHandler subscribeHandler;
@Autowired
private UnsubscribeHandler unsubscribeHandler;
@Bean
public WxMpService wxMpService() {
WxMpServiceImpl wxMpService = new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(wxMpConfigStorage());
// 设置多个微信公众号的配置
// wxMpService.setMultiConfigStorages();
return wxMpService;
}
/**
* 这个地方的配置是保存在本地,生产环境需要自己扩展,可以保存在Redis中等等
*
* @return WxMpConfigStorage
*/
public WxMpConfigStorage wxMpConfigStorage() {
WxMpDefaultConfigImpl storage = new WxMpDefaultConfigImpl();
storage.setAppId(wxMpProperties.getAppId());
storage.setSecret(wxMpProperties.getAppSecret());
storage.setAesKey(wxMpProperties.getAesKey());
storage.setToken(wxMpProperties.getToken());
return storage;
}
@Bean
public WxMpMessageRouter messageRouter(WxMpService wxMpService) {
WxMpMessageRouter router = new WxMpMessageRouter(wxMpService);
// 消息去重
router.setMessageDuplicateChecker(new WxMessageInMemoryDuplicateChecker());
// 关注事件
router.rule().async(false).msgType(EVENT).event(SUBSCRIBE)
.handler(this.subscribeHandler)
.end();
// 取消关注事件
router.rule().async(false).msgType(EVENT).event(UNSUBSCRIBE)
.handler(this.unsubscribeHandler)
.end();
return router;
}
}
1、公众号回调给我们的消息会通过 WxMpMessageRouter
来处理。
2、配置的时候需要做好消息的去重处理,如果我们的服务器5s
种没给微信服务器响应,微信服务器会重试 3次
。
3、处理消息实现WxMpMessageHandler
接口
3、回调入口
/**
* 微信回调
*
* @param requestBody
* @param signature
* @param timestamp
* @param nonce
* @param openid
* @param encType
* @param msgSignature
* @return
*/
@PostMapping("/mp/entry")
public String entryCallback(@RequestBody String requestBody,
@RequestParam("signature") String signature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce,
@RequestParam("openid") String openid,
@RequestParam(name = "encrypt_type", required = false) String encType,
@RequestParam(name = "msg_signature", required = false) String msgSignature) {
log.info("\n接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
}
String out = null;
if (encType == null) {
// 明文传输的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
WxMpXmlOutMessage outMessage = this.wxMpMessageRouter.route(inMessage);
if (outMessage == null) {
return "";
}
out = outMessage.toXml();
} else if ("aes".equalsIgnoreCase(encType)) {
// aes加密的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxMpService.getWxMpConfigStorage(),
timestamp, nonce, msgSignature);
log.info("\n消息解密后内容为:\n[{}] ", inMessage.toString());
WxMpXmlOutMessage outMessage = this.wxMpMessageRouter.route(inMessage);
if (outMessage == null) {
return "";
}
out = outMessage.toEncryptedXml(wxMpService.getWxMpConfigStorage());
}
log.info("\n组装回复信息:[{}]", out);
return out;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。