Browse Source

fix:【MP 公众号】receiveMessage 记录消息时,兜底 MpUserDO 的创建边界

YunaiV 6 months ago
parent
commit
5a87b33df2

+ 1 - 1
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/user/MpUserMapper.java

@@ -21,7 +21,7 @@ public interface MpUserMapper extends BaseMapperX<MpUserDO> {
     }
 
     default MpUserDO selectByAppIdAndOpenid(String appId, String openid) {
-        return selectOne(MpUserDO::getAppId, appId,
+        return selectFirstOne(MpUserDO::getAppId, appId,
                 MpUserDO::getOpenid, openid);
     }
 

+ 0 - 3
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/menu/MenuHandler.java

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.mp.service.handler.menu;
 import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder;
 import cn.iocoder.yudao.module.mp.service.menu.MpMenuService;
 import me.chanjar.weixin.common.session.WxSessionManager;
-import me.chanjar.weixin.mp.api.WxMpMenuService;
 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
@@ -13,8 +12,6 @@ import org.springframework.stereotype.Component;
 import jakarta.annotation.Resource;
 import java.util.Map;
 
-import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
-
 /**
  * 自定义菜单的事件处理器
  *

+ 1 - 1
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/message/MessageReceiveHandler.java

@@ -29,7 +29,7 @@ public class MessageReceiveHandler implements WxMpMessageHandler {
     public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
                                     WxMpService wxMpService, WxSessionManager sessionManager) {
         log.info("[handle][接收到请求消息,内容:{}]", wxMessage);
-        mpMessageService.receiveMessage(MpContextHolder.getAppId(), wxMessage);
+        mpMessageService.receiveMessage(wxMpService, MpContextHolder.getAppId(), wxMessage);
         return null;
     }
 

+ 2 - 1
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageService.java

@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessageP
 import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessageSendReqVO;
 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO;
 import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO;
+import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
 
@@ -31,7 +32,7 @@ public interface MpMessageService {
      * @param appId 微信公众号 appId
      * @param wxMessage 消息
      */
-    void receiveMessage(String appId, WxMpXmlMessage wxMessage);
+    void receiveMessage(WxMpService weixinService, String appId, WxMpXmlMessage wxMessage);
 
     /**
      * 使用公众号,给粉丝回复消息

+ 25 - 8
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageServiceImpl.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.mp.service.message;
 
 import cn.hutool.core.lang.Assert;
-import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.thread.ThreadUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessagePageReqVO;
@@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO;
 import cn.iocoder.yudao.module.mp.service.user.MpUserService;
 import jakarta.annotation.Resource;
 import jakarta.validation.Validator;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -27,10 +28,13 @@ import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import me.chanjar.weixin.mp.bean.result.WxMpUser;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
+import java.util.concurrent.TimeUnit;
+
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MESSAGE_SEND_FAIL;
 
@@ -68,18 +72,31 @@ public class MpMessageServiceImpl implements MpMessageService {
     }
 
     @Override
-    public void receiveMessage(String appId, WxMpXmlMessage wxMessage) {
+    @SneakyThrows
+    public void receiveMessage(WxMpService weixinService, String appId, WxMpXmlMessage wxMessage) {
         // 获得关联信息
         MpAccountDO account = mpAccountService.getAccountFromCache(appId);
         Assert.notNull(account, "公众号账号({}) 不存在", appId);
 
-        // 订阅事件不记录,因为此时公众号粉丝表中还没有此粉丝的数据
-        // TODO @芋艿:这个修复,后续看看还有啥问题
-        if (ObjUtil.equal(wxMessage.getEvent(), WxConsts.EventType.SUBSCRIBE)) {
-            return;
-        }
-
+        // 获取用户
         MpUserDO user = mpUserService.getUser(appId, wxMessage.getFromUser());
+        if (user == null) {
+            // 特殊情况:因为 receiveMessage 是异步记录,可能 SubscribeHandler 还没存储好 User,此时 sleep 轮询
+            for (int i = 0; i < 3; i++) {
+                ThreadUtil.sleep(5, TimeUnit.SECONDS);
+                user = mpUserService.getUser(appId, wxMessage.getFromUser());
+                if (user != null) {
+                    break;
+                }
+                log.warn("[receiveMessage][粉丝({}/{}) 不存在,第 {} 次重试失败]", appId, wxMessage.getFromUser(), i + 1);
+            }
+        }
+        // 特殊情况:可能 SubscribeHandler 没处理正确(例如说发生异常),则主动创建
+        if (user == null) {
+            log.warn("[receiveMessage][粉丝({}/{}) 不存在,主动创建]", appId, wxMessage.getFromUser());
+            WxMpUser wxMpUser = weixinService.getUserService().userInfo(wxMessage.getFromUser());
+            user = mpUserService.saveUser(appId, wxMpUser);
+        }
         Assert.notNull(user, "公众号粉丝({}/{}) 不存在", appId, wxMessage.getFromUser());
 
         // 记录消息