zl程序教程

您现在的位置是:首页 >  .Net

当前栏目

处理微信回调事件

2023-02-18 16:28:05 时间

一、背景

上一节中,我们知道如何接入微信公众号,但是之后公众号会与我们进行交互,那么微信公众号如何通知到我们自己的服务器呢?我们知道我们接入的时候提供的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;
    }

三、参考文档

1、公众号消息加解密
2、接收普通消息
3、接收事件消息

四、代码实现

https://gitee.com/huan1993/wechat-development