Преглед на файлове

fix: 修复公众号用户关联及模板消息发送的三个问题

1. WeixinMPController POST /wx/notify 被注释,关注事件无法到达服务器
2. batchBindMpUser 分页逻辑颠倒,单页粉丝时直接 return 未处理
3. bindMpUser 每次生成新 ID,重复关注产生重复记录
4. updateUnionid 移除无效的 @Async(private 方法内部调用不走代理)
5. 新增 GET /wx/syncMpUsers 手动触发全量同步

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline преди 2 дни
родител
ревизия
7969940d1c

+ 27 - 29
car-wash-miniapp/src/main/java/com/kym/miniapp/controller/WeixinMPController.java

@@ -5,15 +5,19 @@ import cn.dev33.satoken.annotation.SaIgnore;
 import com.kym.common.annotation.ApiLog;
 import com.kym.common.annotation.SysLog;
 import com.kym.common.utils.wx.WxPbUtil;
+import com.kym.common.R;
+import com.kym.service.MpRelationService;
 import com.kym.service.wechat.WeixinMPService;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.error.WxErrorException;
 import org.springframework.http.MediaType;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
 
 import java.io.PrintWriter;
 
@@ -24,28 +28,21 @@ import java.io.PrintWriter;
 public class WeixinMPController {
 
     private final WeixinMPService weixinMPService;
+    private final MpRelationService mpRelationService;
 
-    public WeixinMPController(WeixinMPService weixinMPService) {
+    public WeixinMPController(WeixinMPService weixinMPService, MpRelationService mpRelationService) {
         this.weixinMPService = weixinMPService;
+        this.mpRelationService = mpRelationService;
     }
 
     /**
      * 消息通知(订阅、用户消息)
-     *
-     * @param request
-     */
-
-//    @PostMapping(value = "notify", produces = MediaType.TEXT_XML_VALUE)
-//    @ApiLog(value = "微信公众号服务器推送消息", ignoreParams = true)
-//    public void handleMessage(HttpServletRequest request, HttpServletResponse response) {
-//        weixinMPService.handleWxMPNotify(request, response);
-//    }
-
-
-    /*
-
-
      */
+    @PostMapping(value = "notify", produces = MediaType.TEXT_XML_VALUE)
+    @ApiLog(value = "微信公众号服务器推送消息", ignoreParams = true)
+    public void handleMessage(HttpServletRequest request, HttpServletResponse response) {
+        weixinMPService.handleWxMPNotify(request, response);
+    }
 
     /**
      * 微信服务器token验证
@@ -76,19 +73,20 @@ public class WeixinMPController {
         }
     }
 
-//    @GetMapping(value = "/test")
-//    public void test() throws WxErrorException {
-//        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
-//                .toUser("oK-oR5gAn9hrYNim4x64l4kzmMXs")
-//                .templateId("SjszYYiHcN-GaEeZTKJsCcB6ACxYJWfTddkSywf1q1g")
-//                .url("")
-//                .build();
-//        templateMessage.addData(new WxMpTemplateData("character_string2.DATA", "000001"));
-//        templateMessage.addData(new WxMpTemplateData("thing9.DATA}", "测试站点"));
-//        templateMessage.addData(new WxMpTemplateData("character_string3.DATA", "编号001"));
-//        templateMessage.addData(new WxMpTemplateData("time4.DATA", "2022-12-01 19:30:00"));
-//        wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
-//
-//    }
+    /**
+     * 手动同步公众号关注用户(一次性触发)
+     */
+    @GetMapping(value = "/syncMpUsers")
+    @SaIgnore
+    @ResponseBody
+    public R<?> syncMpUsers() {
+        try {
+            mpRelationService.batchBindMpUser();
+            return R.success("同步完成");
+        } catch (WxErrorException e) {
+            log.error("手动同步公众号用户失败", e);
+            return R.failed("同步失败: " + e.getMessage());
+        }
+    }
 
 }

+ 18 - 8
car-wash-service/src/main/java/com/kym/service/impl/MpRelationServiceImpl.java

@@ -52,14 +52,14 @@ public class MpRelationServiceImpl extends MyBaseServiceImpl<MpRelationMapper, M
         for (; ; ) {
             // 获取公众号所有关注者列表
             WxMpUserList wxUserList = wxMpService.getUserService().userList(nextOpenid);
-            if (CommUtil.isEmptyOrNull(wxUserList.getNextOpenid())) {
+            var openids = wxUserList.getOpenids();
+            if (CommUtil.isEmptyOrNull(openids)) {
                 return;
-            } else {
-                nextOpenid = wxUserList.getNextOpenid();
             }
+
             // 通过unionid获取公众号openid
             var mpRelationList = new ArrayList<MpRelation>();
-            List<WxMpUser> mpUserList = wxMpService.getUserService().userInfoList(wxUserList.getOpenids());
+            List<WxMpUser> mpUserList = wxMpService.getUserService().userInfoList(openids);
             mpUserList.forEach(mpUser -> {
                 MpRelation mpRelation = new MpRelation()
                         .setMpOpenid(mpUser.getOpenId())
@@ -80,6 +80,12 @@ public class MpRelationServiceImpl extends MyBaseServiceImpl<MpRelationMapper, M
             }));
             updateBatchByQueryWrapper(mpRelations, mpRelation ->
                     new QueryWrapper<MpRelation>().eq("unionid", mpRelation.getUnionid()));
+
+            // 检查是否有下一页
+            if (CommUtil.isEmptyOrNull(wxUserList.getNextOpenid())) {
+                return;
+            }
+            nextOpenid = wxUserList.getNextOpenid();
         }
     }
 
@@ -91,8 +97,13 @@ public class MpRelationServiceImpl extends MyBaseServiceImpl<MpRelationMapper, M
     public void bindMpUser(String mpOpenid) {
         try {
             WxMpUser mpUser = wxMpService.getUserService().userInfo(mpOpenid, lang);
-            MpRelation mpRelation = new MpRelation();
-            mpRelation.setId(IDGenerator.INS().nextId());
+
+            // 查询已存在的记录,避免重复插入
+            MpRelation mpRelation = lambdaQuery().eq(MpRelation::getMpOpenid, mpOpenid).one();
+            if (mpRelation == null) {
+                mpRelation = new MpRelation();
+                mpRelation.setId(IDGenerator.INS().nextId());
+            }
             mpRelation
                     .setMpOpenid(mpUser.getOpenId())
                     .setUnionid(mpUser.getUnionId())
@@ -103,9 +114,8 @@ public class MpRelationServiceImpl extends MyBaseServiceImpl<MpRelationMapper, M
             if (user != null) {
                 mpRelation.setOpenid(user.getOpenid());
                 mpRelation.setUserId(user.getId());
-                updateById(mpRelation);
             }
-            replace(mpRelation);
+            saveOrUpdate(mpRelation);
         } catch (WxErrorException e) {
             throw new RuntimeException(e);
         }

+ 1 - 2
car-wash-service/src/main/java/com/kym/service/impl/UserServiceImpl.java

@@ -34,7 +34,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.context.annotation.Lazy;
-import org.springframework.scheduling.annotation.Async;
+
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -197,7 +197,6 @@ public class UserServiceImpl extends MPJBaseServiceImpl<UserMapper, User> implem
         return R.success(of("userId", user.getId(), "satoken", StpUtil.getTokenValue()));
     }
 
-    @Async
     protected void updateUnionid() {
         var unionid = StpUtil.getSession().getString("unionid");
         if (CommUtil.isNotEmptyAndNull(unionid)) {