Commit 69e653cd941dea253e80f02e78714c43cd98b6cb

Authored by YunaiV
1 parent 44f0bcd1

mp:location 的自动回复;关注后的自动回复

yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpAutoReplyMapper.java
... ... @@ -34,4 +34,11 @@ public interface MpAutoReplyMapper extends BaseMapperX<MpAutoReplyDO> {
34 34 .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.MESSAGE.getType())
35 35 .eq(MpAutoReplyDO::getRequestMessageType, requestMessageType));
36 36 }
  37 +
  38 + default List<MpAutoReplyDO> selectListByAppIdAndSubscribe(String appId) {
  39 + return selectList(new LambdaQueryWrapperX<MpAutoReplyDO>()
  40 + .eq(MpAutoReplyDO::getAppId, appId)
  41 + .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.SUBSCRIBE.getType()));
  42 + }
  43 +
37 44 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/MpConfiguration.java
... ... @@ -36,7 +36,7 @@ public class MpConfiguration {
36 36 @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
37 37 public MpServiceFactory mpServiceFactory(RedisTemplateWxRedisOps redisTemplateWxRedisOps,
38 38 WxMpProperties wxMpProperties,
39   - MessageReceiveHandler logHandler,
  39 + MessageReceiveHandler messageReceiveHandler,
40 40 KfSessionHandler kfSessionHandler,
41 41 StoreCheckNotifyHandler storeCheckNotifyHandler,
42 42 MenuHandler menuHandler,
... ... @@ -45,10 +45,10 @@ public class MpConfiguration {
45 45 UnsubscribeHandler unsubscribeHandler,
46 46 LocationHandler locationHandler,
47 47 ScanHandler scanHandler,
48   - MessageAutoReplyHandler msgHandler) {
  48 + MessageAutoReplyHandler messageAutoReplyHandler) {
49 49 return new DefaultMpServiceFactory(redisTemplateWxRedisOps, wxMpProperties,
50   - logHandler, kfSessionHandler, storeCheckNotifyHandler, menuHandler,
51   - nullHandler, subscribeHandler, unsubscribeHandler, locationHandler, scanHandler, msgHandler);
  50 + messageReceiveHandler, kfSessionHandler, storeCheckNotifyHandler, menuHandler,
  51 + nullHandler, subscribeHandler, unsubscribeHandler, locationHandler, scanHandler, messageAutoReplyHandler);
52 52 }
53 53  
54 54 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java
... ... @@ -49,7 +49,7 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
49 49  
50 50 // ========== 各种 Handler ==========
51 51  
52   - private final MessageReceiveHandler logHandler;
  52 + private final MessageReceiveHandler messageReceiveHandler;
53 53 private final KfSessionHandler kfSessionHandler;
54 54 private final StoreCheckNotifyHandler storeCheckNotifyHandler;
55 55 private final MenuHandler menuHandler;
... ... @@ -58,7 +58,7 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
58 58 private final UnsubscribeHandler unsubscribeHandler;
59 59 private final LocationHandler locationHandler;
60 60 private final ScanHandler scanHandler;
61   - private final MessageAutoReplyHandler msgHandler;
  61 + private final MessageAutoReplyHandler messageAutoReplyHandler;
62 62  
63 63 @Override
64 64 public void init(List<MpAccountDO> list) {
... ... @@ -108,7 +108,7 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
108 108 private WxMpMessageRouter buildMpMessageRouter(WxMpService mpService) {
109 109 WxMpMessageRouter router = new WxMpMessageRouter(mpService);
110 110 // 记录所有事件的日志(异步执行)
111   - router.rule().handler(logHandler).next();
  111 + router.rule().handler(messageReceiveHandler).next();
112 112  
113 113 // 接收客服会话管理事件
114 114 router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
... ... @@ -159,7 +159,7 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
159 159 .event(WxConsts.EventType.SCAN).handler(scanHandler).end();
160 160  
161 161 // 默认
162   - router.rule().async(false).handler(msgHandler).end();
  162 + router.rule().async(false).handler(messageAutoReplyHandler).end();
163 163 return router;
164 164 }
165 165  
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/LocationHandler.java
1 1 package cn.iocoder.yudao.module.mp.service.handler.user;
2 2  
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  5 +import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder;
  6 +import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService;
3 7 import lombok.extern.slf4j.Slf4j;
  8 +import me.chanjar.weixin.common.api.WxConsts;
4 9 import me.chanjar.weixin.common.session.WxSessionManager;
5 10 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
6 11 import me.chanjar.weixin.mp.api.WxMpService;
... ... @@ -8,38 +13,37 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
8 13 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
9 14 import org.springframework.stereotype.Component;
10 15  
  16 +import javax.annotation.Resource;
11 17 import java.util.Map;
12 18  
13 19 /**
14 20 * 上报地理位置的事件处理器
15 21 *
16   - * // TODO @芋艿:需要实现一下~
  22 + * 触发操作:打开微信公众号 -> 点击 + 号 -> 选择「语音」
  23 + *
  24 + * 逻辑:用户上传地理位置时,也可以触发自动回复
  25 + *
  26 + * @author 芋道源码
17 27 */
18 28 @Component
19 29 @Slf4j
20 30 public class LocationHandler implements WxMpMessageHandler {
21 31  
  32 + @Resource
  33 + private MpAutoReplyService mpAutoReplyService;
  34 +
22 35 @Override
23 36 public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
24 37 WxMpService wxMpService, WxSessionManager sessionManager) {
25   -// if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
26   -// //TODO 接收处理用户发送的地理位置消息
27   -// try {
28   -// String content = "感谢反馈,您的的地理位置已收到!";
29   -// return new TextBuilder().build(content, wxMessage, null);
30   -// } catch (Exception e) {
31   -// log.error("位置消息接收处理失败", e);
32   -// return null;
33   -// }
34   -// }
35   -//
36   -// //上报地理位置事件
37   -// log.info("上报地理位置,纬度 : {},经度 : {},精度 : {}",
38   -// wxMessage.getLatitude(), wxMessage.getLongitude(), String.valueOf(wxMessage.getPrecision()));
39   -
40   - //TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用
  38 + // 防御性编程:必须是 LOCATION 消息
  39 + if (ObjectUtil.notEqual(wxMessage.getMsgType(), WxConsts.XmlMsgType.LOCATION)) {
  40 + return null;
  41 + }
  42 + log.info("[handle][上报地理位置,纬度({})、经度({})、精度({})", wxMessage.getLatitude(),
  43 + wxMessage.getLongitude(), wxMessage.getPrecision());
41 44  
42   - return null;
  45 + // 自动回复
  46 + return mpAutoReplyService.replyForMessage(MpContextHolder.getAppId(), wxMessage);
43 47 }
44 48  
45 49 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/SubscribeHandler.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.mp.service.handler.user;
3 3 import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO;
4 4 import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder;
5 5 import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
  6 +import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService;
6 7 import cn.iocoder.yudao.module.mp.service.user.MpUserService;
7 8 import lombok.extern.slf4j.Slf4j;
8 9 import me.chanjar.weixin.common.error.WxErrorException;
... ... @@ -22,19 +23,15 @@ import java.util.Map;
22 23 * 关注的事件处理器
23 24 *
24 25 * @author 芋道源码
25   - *
26   - * // TODO 芋艿:待实现
27 26 */
28 27 @Component
29 28 @Slf4j
30 29 public class SubscribeHandler implements WxMpMessageHandler {
31 30  
32 31 @Resource
33   - @Lazy // 延迟加载,解决循环依赖的问题
34   - private MpAccountService mpAccountService;
35   -
36   - @Resource
37 32 private MpUserService mpUserService;
  33 + @Resource
  34 + private MpAutoReplyService mpAutoReplyService;
38 35  
39 36 @Override
40 37 public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
... ... @@ -49,24 +46,10 @@ public class SubscribeHandler implements WxMpMessageHandler {
49 46 }
50 47  
51 48 // 第二步,保存用户信息
52   - MpUserDO mpUser = null;
53   - if (wxMpUser != null) {
54   - mpUser = mpUserService.saveUser(MpContextHolder.getAppId(), wxMpUser);
55   - }
56   -
57   - // 第三步,回复关注的欢迎语 TODO 芋艿:关注的欢迎语
58   -// return new TextBuilder().build("感谢关注", wxMessage, weixinService);
59   - return null;
60   - }
61   -
62   - /**
63   - * 处理特殊请求,比如如果是扫码进来的,可以做相应处理
64   - */
65   - private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage)
66   - throws Exception {
  49 + mpUserService.saveUser(MpContextHolder.getAppId(), wxMpUser);
67 50  
68   - //TODO
69   - return null;
  51 + // 第三步,回复关注的欢迎语
  52 + return mpAutoReplyService.replyForSubscribe(MpContextHolder.getAppId(), wxMessage);
70 53 }
71 54  
72 55 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyService.java
... ... @@ -19,4 +19,13 @@ public interface MpAutoReplyService {
19 19 */
20 20 WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage);
21 21  
  22 + /**
  23 + * 当用户关注时,自动回复
  24 + *
  25 + * @param appId 微信公众号 appId
  26 + * @param wxMessage 消息
  27 + * @return 回复的消息
  28 + */
  29 + WxMpXmlOutMessage replyForSubscribe(String appId, WxMpXmlMessage wxMessage);
  30 +
22 31 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyServiceImpl.java
1 1 package cn.iocoder.yudao.module.mp.service.message;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4   -import cn.iocoder.yudao.module.mp.builder.TextBuilder;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
5 6 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO;
6 7 import cn.iocoder.yudao.module.mp.dal.mysql.message.MpAutoReplyMapper;
7   -import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyMatchEnum;
  8 +import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyTypeEnum;
  9 +import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
8 10 import me.chanjar.weixin.common.api.WxConsts;
9 11 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
10 12 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
  13 +import org.springframework.context.annotation.Lazy;
11 14 import org.springframework.stereotype.Service;
12 15 import org.springframework.validation.annotation.Validated;
13 16  
... ... @@ -25,15 +28,15 @@ public class MpAutoReplyServiceImpl implements MpAutoReplyService {
25 28  
26 29 @Resource
27 30 private MpMessageService mpMessageService;
  31 + @Resource
  32 + @Lazy // 延迟加载,避免循环依赖
  33 + private MpAccountService mpAccountService;
28 34  
29 35 @Resource
30 36 private MpAutoReplyMapper mpAutoReplyMapper;
31 37  
32 38 @Override
33 39 public WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage) {
34   -// if (true) {
35   -// return new TextBuilder().build("nihao", wxMessage, null);
36   -// }
37 40 // 第一步,匹配自动回复
38 41 List<MpAutoReplyDO> replies = null;
39 42 // 1.1 关键字
... ... @@ -58,4 +61,24 @@ public class MpAutoReplyServiceImpl implements MpAutoReplyService {
58 61 return mpMessageService.createFromAutoReply(wxMessage.getFromUser(), reply);
59 62 }
60 63  
  64 + @Override
  65 + public WxMpXmlOutMessage replyForSubscribe(String appId, WxMpXmlMessage wxMessage) {
  66 + // 第一步,匹配自动回复
  67 + List<MpAutoReplyDO> replies = mpAutoReplyMapper.selectListByAppIdAndSubscribe(appId);
  68 + MpAutoReplyDO reply = CollUtil.isNotEmpty(replies) ? CollUtil.getFirst(replies)
  69 + : buildDefaultSubscribeAutoReply(appId); // 如果不存在,提供一个默认末班
  70 +
  71 + // 第二步,基于自动回复,创建消息
  72 + return mpMessageService.createFromAutoReply(wxMessage.getFromUser(), reply);
  73 + }
  74 +
  75 + private MpAutoReplyDO buildDefaultSubscribeAutoReply(String appId) {
  76 + MpAccountDO account = mpAccountService.getAccountFromCache(appId);
  77 + Assert.notNull(account, "公众号账号({}) 不存在", appId);
  78 + // 构建默认的【关注】自动回复
  79 + return new MpAutoReplyDO().setAppId(appId).setAccountId(account.getId())
  80 + .setType(MpAutoReplyTypeEnum.SUBSCRIBE.getType())
  81 + .setResponseMessageType(WxConsts.XmlMsgType.TEXT).setResponseContent("感谢关注");
  82 + }
  83 +
61 84 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageServiceImpl.java
... ... @@ -89,7 +89,7 @@ public class MpMessageServiceImpl implements MpMessageService {
89 89 }
90 90 mpMessageMapper.insert(message);
91 91  
92   -// WxConsts.MenuButtonType.VIEW
  92 +// WxConsts.MenuButtonType.VIEW TODO 芋艿:待测试
93 93 // wxMessage.getEventKey()
94 94  
95 95 // WxConsts.MenuButtonType.CLICK
... ...