Commit 5a87b33df2fd9fda3999b1558966557f2183fa05

Authored by YunaiV
1 parent 0343c4d2

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

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> {
21 21 }
22 22  
23 23 default MpUserDO selectByAppIdAndOpenid(String appId, String openid) {
24   - return selectOne(MpUserDO::getAppId, appId,
  24 + return selectFirstOne(MpUserDO::getAppId, appId,
25 25 MpUserDO::getOpenid, openid);
26 26 }
27 27  
... ...
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;
3 3 import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder;
4 4 import cn.iocoder.yudao.module.mp.service.menu.MpMenuService;
5 5 import me.chanjar.weixin.common.session.WxSessionManager;
6   -import me.chanjar.weixin.mp.api.WxMpMenuService;
7 6 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
8 7 import me.chanjar.weixin.mp.api.WxMpService;
9 8 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
... ... @@ -13,8 +12,6 @@ import org.springframework.stereotype.Component;
13 12 import jakarta.annotation.Resource;
14 13 import java.util.Map;
15 14  
16   -import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
17   -
18 15 /**
19 16 * 自定义菜单的事件处理器
20 17 *
... ...
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 {
29 29 public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
30 30 WxMpService wxMpService, WxSessionManager sessionManager) {
31 31 log.info("[handle][接收到请求消息,内容:{}]", wxMessage);
32   - mpMessageService.receiveMessage(MpContextHolder.getAppId(), wxMessage);
  32 + mpMessageService.receiveMessage(wxMpService, MpContextHolder.getAppId(), wxMessage);
33 33 return null;
34 34 }
35 35  
... ...
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
5 5 import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessageSendReqVO;
6 6 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO;
7 7 import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO;
  8 +import me.chanjar.weixin.mp.api.WxMpService;
8 9 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
9 10 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
10 11  
... ... @@ -31,7 +32,7 @@ public interface MpMessageService {
31 32 * @param appId 微信公众号 appId
32 33 * @param wxMessage 消息
33 34 */
34   - void receiveMessage(String appId, WxMpXmlMessage wxMessage);
  35 + void receiveMessage(WxMpService weixinService, String appId, WxMpXmlMessage wxMessage);
35 36  
36 37 /**
37 38 * 使用公众号,给粉丝回复消息
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageServiceImpl.java
1 1 package cn.iocoder.yudao.module.mp.service.message;
2 2  
3 3 import cn.hutool.core.lang.Assert;
4   -import cn.hutool.core.util.ObjUtil;
  4 +import cn.hutool.core.thread.ThreadUtil;
5 5 import cn.hutool.core.util.StrUtil;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7 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;
20 20 import cn.iocoder.yudao.module.mp.service.user.MpUserService;
21 21 import jakarta.annotation.Resource;
22 22 import jakarta.validation.Validator;
  23 +import lombok.SneakyThrows;
23 24 import lombok.extern.slf4j.Slf4j;
24 25 import me.chanjar.weixin.common.api.WxConsts;
25 26 import me.chanjar.weixin.common.error.WxErrorException;
... ... @@ -27,10 +28,13 @@ import me.chanjar.weixin.mp.api.WxMpService;
27 28 import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
28 29 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
29 30 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
  31 +import me.chanjar.weixin.mp.bean.result.WxMpUser;
30 32 import org.springframework.context.annotation.Lazy;
31 33 import org.springframework.stereotype.Service;
32 34 import org.springframework.validation.annotation.Validated;
33 35  
  36 +import java.util.concurrent.TimeUnit;
  37 +
34 38 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
35 39 import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MESSAGE_SEND_FAIL;
36 40  
... ... @@ -68,18 +72,31 @@ public class MpMessageServiceImpl implements MpMessageService {
68 72 }
69 73  
70 74 @Override
71   - public void receiveMessage(String appId, WxMpXmlMessage wxMessage) {
  75 + @SneakyThrows
  76 + public void receiveMessage(WxMpService weixinService, String appId, WxMpXmlMessage wxMessage) {
72 77 // 获得关联信息
73 78 MpAccountDO account = mpAccountService.getAccountFromCache(appId);
74 79 Assert.notNull(account, "公众号账号({}) 不存在", appId);
75 80  
76   - // 订阅事件不记录,因为此时公众号粉丝表中还没有此粉丝的数据
77   - // TODO @芋艿:这个修复,后续看看还有啥问题
78   - if (ObjUtil.equal(wxMessage.getEvent(), WxConsts.EventType.SUBSCRIBE)) {
79   - return;
80   - }
81   -
  81 + // 获取用户
82 82 MpUserDO user = mpUserService.getUser(appId, wxMessage.getFromUser());
  83 + if (user == null) {
  84 + // 特殊情况:因为 receiveMessage 是异步记录,可能 SubscribeHandler 还没存储好 User,此时 sleep 轮询
  85 + for (int i = 0; i < 3; i++) {
  86 + ThreadUtil.sleep(5, TimeUnit.SECONDS);
  87 + user = mpUserService.getUser(appId, wxMessage.getFromUser());
  88 + if (user != null) {
  89 + break;
  90 + }
  91 + log.warn("[receiveMessage][粉丝({}/{}) 不存在,第 {} 次重试失败]", appId, wxMessage.getFromUser(), i + 1);
  92 + }
  93 + }
  94 + // 特殊情况:可能 SubscribeHandler 没处理正确(例如说发生异常),则主动创建
  95 + if (user == null) {
  96 + log.warn("[receiveMessage][粉丝({}/{}) 不存在,主动创建]", appId, wxMessage.getFromUser());
  97 + WxMpUser wxMpUser = weixinService.getUserService().userInfo(wxMessage.getFromUser());
  98 + user = mpUserService.saveUser(appId, wxMpUser);
  99 + }
83 100 Assert.notNull(user, "公众号粉丝({}/{}) 不存在", appId, wxMessage.getFromUser());
84 101  
85 102 // 记录消息
... ...