Browse Source

微信公众号事件推送处理

skyline 1 year ago
parent
commit
119b510278

+ 12 - 34
miniapp/src/main/java/com/kym/miniapp/controller/WeixinController.java → miniapp/src/main/java/com/kym/miniapp/controller/WeixinMPController.java

@@ -1,11 +1,8 @@
 package com.kym.miniapp.controller;
 
 
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.XmlUtil;
 import com.kym.common.annotation.ApiLog;
-import com.kym.common.utils.CommUtil;
+import com.kym.service.wechat.WeixinMPService;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.extern.slf4j.Slf4j;
@@ -14,15 +11,18 @@ import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Map;
-
 
 @Controller
 @RequestMapping("wx")
 @Slf4j
-public class WeixinController {
+public class WeixinMPController {
+
+    private final WeixinMPService weixinMPService;
+
+    public WeixinMPController(WeixinMPService weixinMPService) {
+        this.weixinMPService = weixinMPService;
+    }
+
     /**
      * 消息通知(订阅、用户消息)
      *
@@ -30,36 +30,14 @@ public class WeixinController {
      */
 
     @PostMapping(value = "check", produces = MediaType.TEXT_XML_VALUE)
-    @ApiLog("微信公众号服务器推送消息")
+    @ApiLog(value = "微信公众号服务器推送消息", ignoreParams = true)
     public void handleMessage(HttpServletRequest request, HttpServletResponse response) {
-        String result = "";
-        try {
-            String xml = IoUtil.read(request.getInputStream(), CharsetUtil.CHARSET_UTF_8);
-            log.info("wx mp receive xml message:\n{}", xml);
-
-            Map<String, Object> ret = XmlUtil.xmlToMap(xml);
-            log.info("wx mp receive map message:\n{}", ret);
-            if (!CommUtil.isEmptyOrNull(ret)) {
-                response.setContentType("text/html");
-                result = XmlUtil.mapToXmlStr(ret);
-            }
-        } catch (Exception e) {
-            log.error("WxController.handleMessage ERR", e);
-        } finally {
-            try {
-                log.info("WxController.handleMessage response: \n{}", result);
-                PrintWriter writer = response.getWriter();
-                writer.print(result);
-                writer.close();
-            } catch (IOException e) {
-                log.error(e.getMessage(), e);
-            }
-        }
+        weixinMPService.handleWxMPNotify(request, response);
     }
 
 //    @Resource
 //    WxMpService wxMpService;
-//    private Logger logger = LoggerFactory.getLogger(WeixinController.class);
+//    private Logger logger = LoggerFactory.getLogger(WeixinMPController.class);
 
 
     /*

+ 1 - 1
service/src/main/java/com/kym/service/miniapp/MpRelationService.java

@@ -15,5 +15,5 @@ import me.chanjar.weixin.common.error.WxErrorException;
 public interface MpRelationService extends MyBaseService<MpRelation> {
 
     // 关联小程序用户
-    void bindMpUser() throws WxErrorException;
+    void batchBindMpUser() throws WxErrorException;
 }

+ 32 - 7
service/src/main/java/com/kym/service/miniapp/impl/MpRelationServiceImpl.java

@@ -29,6 +29,7 @@ import java.util.ArrayList;
 @Service
 public class MpRelationServiceImpl extends MyBaseServiceImpl<MpRelationMapper, MpRelation> implements MpRelationService {
 
+    private static final String lang = "zh_CN";
     private final UserService userService;
     private final WxMpService wxMpService;
 
@@ -38,15 +39,14 @@ public class MpRelationServiceImpl extends MyBaseServiceImpl<MpRelationMapper, M
         this.wxMpService = wxMpService;
     }
 
-
     /**
-     * 公众号用户关联小程序用户
+     * 批量处理(全量)公众号用户关联小程序用户
      *
      * @throws WxErrorException
      */
     @Override
     @Transactional
-    public void bindMpUser() throws WxErrorException {
+    public void batchBindMpUser() throws WxErrorException {
         String nextOpenid = null;
         for (; ; ) {
             // 获取公众号所有关注者列表
@@ -57,7 +57,6 @@ public class MpRelationServiceImpl extends MyBaseServiceImpl<MpRelationMapper, M
                 nextOpenid = wxUserList.getNextOpenid();
             }
             // 通过unionid获取公众号openid
-            String lang = "zh_CN";
             var mpRelationList = new ArrayList<MpRelation>();
             wxUserList.getOpenids().forEach(openid -> {
                 try {
@@ -75,9 +74,7 @@ public class MpRelationServiceImpl extends MyBaseServiceImpl<MpRelationMapper, M
                 }
             });
 
-            // todo 优化成批量replace
-            // saveBatch(mpRelationList);
-
+            // 批量replace
             replaceBatch(mpRelationList);
 
             var mpRelations = mpRelationList.stream().filter(mpRelation -> mpRelation.getUnionid() != null && !mpRelation.getUnionid().isEmpty()).toList();
@@ -93,4 +90,32 @@ public class MpRelationServiceImpl extends MyBaseServiceImpl<MpRelationMapper, M
         }
     }
 
+    /**
+     * 绑定公众号用户
+     *
+     * @param mpOpenid
+     */
+    public void bindMpUser(String mpOpenid) {
+        try {
+            WxMpUser mpUser = wxMpService.getUserService().userInfo(mpOpenid, lang);
+            MpRelation mpRelation = new MpRelation();
+            mpRelation.setId(IDGenerator.INS().nextId());
+            mpRelation
+                    .setMpOpenid(mpUser.getOpenId())
+                    .setUnionid(mpUser.getUnionId())
+                    .setSubscribe(mpUser.getSubscribe())
+                    .setSubscribeScene(mpUser.getSubscribeScene());
+
+            var user = userService.getOne(new QueryWrapper<User>().eq("unionid", mpRelation.getUnionid()));
+            if (user != null) {
+                mpRelation.setOpenid(user.getOpenid());
+                mpRelation.setUserId(user.getId());
+                updateById(mpRelation);
+            }
+            replace(mpRelation);
+        } catch (WxErrorException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
 }

+ 8 - 0
service/src/main/java/com/kym/service/wechat/WeixinMPService.java

@@ -0,0 +1,8 @@
+package com.kym.service.wechat;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+public interface WeixinMPService {
+    void handleWxMPNotify(HttpServletRequest request, HttpServletResponse response);
+}

+ 107 - 0
service/src/main/java/com/kym/service/wechat/impl/WeixinMPServiceImpl.java

@@ -0,0 +1,107 @@
+package com.kym.service.wechat.impl;
+
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.XmlUtil;
+import com.kym.common.utils.CommUtil;
+import com.kym.entity.miniapp.MpRelation;
+import com.kym.service.miniapp.impl.MpRelationServiceImpl;
+import com.kym.service.wechat.WeixinMPService;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Map;
+
+/**
+ * 微信公众号服务
+ *
+ * @author skyline
+ */
+@Service
+@Slf4j
+public class WeixinMPServiceImpl implements WeixinMPService {
+
+    private final MpRelationServiceImpl mpRelationService;
+
+    public WeixinMPServiceImpl(MpRelationServiceImpl mpRelationService) {
+        this.mpRelationService = mpRelationService;
+    }
+
+    /**
+     * 处理微信公众号通知
+     *
+     * @param request
+     * @param response
+     */
+    @Override
+    public void handleWxMPNotify(HttpServletRequest request, HttpServletResponse response) {
+        String result = "";
+        try {
+            String xml = IoUtil.read(request.getInputStream(), CharsetUtil.CHARSET_UTF_8);
+            log.info("收到微信公众号通知:xml message:{}", xml);
+
+            Map<String, Object> ret = XmlUtil.xmlToMap(xml);
+            log.info("收到微信公众号通知:map message:{}", ret);
+
+            if (!CommUtil.isEmptyOrNull(ret)) {
+                // 公众号用户的openid
+                var mpOpenid = ret.get("FromUserName").toString();
+                // 事件类型
+                var msgType = ret.get("MsgType").toString();
+                var event = ret.get("Event").toString();
+                if ("event".equals(msgType) && CommUtil.isEmptyOrNull(event)) {
+                    switch (msgType) {
+                        case "subscribe":
+                            // 关注公众号
+                            log.info("收到微信公众号关注通知: {}", mpOpenid);
+                            // 通过openid获取用户信息中的unionid,关联小程序用户
+                            mpRelationService.bindMpUser(mpOpenid);
+                            break;
+                        case "unsubscribe":
+                            // 取消关注公众号
+                            log.info("收到微信公众号取消关注通知: {}", mpOpenid);
+                            // 更新用户的关注状态
+                            mpRelationService.lambdaUpdate().set(MpRelation::getSubscribe, false).eq(MpRelation::getOpenid, mpOpenid).update();
+                            break;
+                        case "scan":
+                            // 扫描二维码
+                            log.info("收到微信公众号扫描二维码通知: {}", mpOpenid);
+                            break;
+                        case "location":
+                            // 上报地理位置
+                            log.info("收到微信公众号上报地理位置通知: {}", mpOpenid);
+                            break;
+                        case "click":
+                            // 点击菜单拉取消息
+                            log.info("收到微信公众号点击菜单拉取消息通知: {}", mpOpenid);
+                            break;
+                        case "view":
+                            // 点击菜单跳转链接
+                            log.info("收到微信公众号点击菜单跳转链接通知: {}", mpOpenid);
+                            break;
+                    }
+                }
+
+                response.setContentType("text/html");
+                result = XmlUtil.mapToXmlStr(ret);
+            }
+        } catch (Exception e) {
+            log.error("微信公众号消息处理异常", e);
+        } finally {
+            try {
+                log.info("收到微信公众号通知响应: {}", result);
+                PrintWriter writer = response.getWriter();
+                writer.print(result);
+                writer.close();
+            } catch (IOException e) {
+                log.error(e.getMessage(), e);
+            }
+        }
+
+    }
+
+}