Explorar el Código

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

YunaiV hace 2 años
padre
commit
69e653cd94

+ 7 - 0
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> {
                 .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.MESSAGE.getType())
                 .eq(MpAutoReplyDO::getRequestMessageType, requestMessageType));
     }
+
+    default List<MpAutoReplyDO> selectListByAppIdAndSubscribe(String appId) {
+        return selectList(new LambdaQueryWrapperX<MpAutoReplyDO>()
+                .eq(MpAutoReplyDO::getAppId, appId)
+                .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.SUBSCRIBE.getType()));
+    }
+
 }

+ 4 - 4
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 {
     @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
     public MpServiceFactory mpServiceFactory(RedisTemplateWxRedisOps redisTemplateWxRedisOps,
                                              WxMpProperties wxMpProperties,
-                                             MessageReceiveHandler logHandler,
+                                             MessageReceiveHandler messageReceiveHandler,
                                              KfSessionHandler kfSessionHandler,
                                              StoreCheckNotifyHandler storeCheckNotifyHandler,
                                              MenuHandler menuHandler,
@@ -45,10 +45,10 @@ public class MpConfiguration {
                                              UnsubscribeHandler unsubscribeHandler,
                                              LocationHandler locationHandler,
                                              ScanHandler scanHandler,
-                                             MessageAutoReplyHandler msgHandler) {
+                                             MessageAutoReplyHandler messageAutoReplyHandler) {
         return new DefaultMpServiceFactory(redisTemplateWxRedisOps, wxMpProperties,
-                logHandler, kfSessionHandler, storeCheckNotifyHandler, menuHandler,
-                nullHandler, subscribeHandler, unsubscribeHandler, locationHandler, scanHandler, msgHandler);
+                messageReceiveHandler, kfSessionHandler, storeCheckNotifyHandler, menuHandler,
+                nullHandler, subscribeHandler, unsubscribeHandler, locationHandler, scanHandler, messageAutoReplyHandler);
     }
 
 }

+ 4 - 4
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 {
 
     // ========== 各种 Handler ==========
 
-    private final MessageReceiveHandler logHandler;
+    private final MessageReceiveHandler messageReceiveHandler;
     private final KfSessionHandler kfSessionHandler;
     private final StoreCheckNotifyHandler storeCheckNotifyHandler;
     private final MenuHandler menuHandler;
@@ -58,7 +58,7 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
     private final UnsubscribeHandler unsubscribeHandler;
     private final LocationHandler locationHandler;
     private final ScanHandler scanHandler;
-    private final MessageAutoReplyHandler msgHandler;
+    private final MessageAutoReplyHandler messageAutoReplyHandler;
 
     @Override
     public void init(List<MpAccountDO> list) {
@@ -108,7 +108,7 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
     private WxMpMessageRouter buildMpMessageRouter(WxMpService mpService) {
         WxMpMessageRouter router = new WxMpMessageRouter(mpService);
         // 记录所有事件的日志(异步执行)
-        router.rule().handler(logHandler).next();
+        router.rule().handler(messageReceiveHandler).next();
 
         // 接收客服会话管理事件
         router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
@@ -159,7 +159,7 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
                 .event(WxConsts.EventType.SCAN).handler(scanHandler).end();
 
         // 默认
-        router.rule().async(false).handler(msgHandler).end();
+        router.rule().async(false).handler(messageAutoReplyHandler).end();
         return router;
     }
 

+ 22 - 18
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/LocationHandler.java

@@ -1,6 +1,11 @@
 package cn.iocoder.yudao.module.mp.service.handler.user;
 
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
+import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder;
+import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService;
 import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.session.WxSessionManager;
 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
 import me.chanjar.weixin.mp.api.WxMpService;
@@ -8,38 +13,37 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.Resource;
 import java.util.Map;
 
 /**
  * 上报地理位置的事件处理器
  *
- * // TODO @芋艿:需要实现一下~
+ * 触发操作:打开微信公众号 -> 点击 + 号 -> 选择「语音」
+ *
+ * 逻辑:用户上传地理位置时,也可以触发自动回复
+ *
+ * @author 芋道源码
  */
 @Component
 @Slf4j
 public class LocationHandler implements WxMpMessageHandler {
 
+    @Resource
+    private MpAutoReplyService mpAutoReplyService;
+
     @Override
     public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
                                     WxMpService wxMpService, WxSessionManager sessionManager) {
-//        if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
-//            //TODO 接收处理用户发送的地理位置消息
-//            try {
-//                String content = "感谢反馈,您的的地理位置已收到!";
-//                return new TextBuilder().build(content, wxMessage, null);
-//            } catch (Exception e) {
-//                log.error("位置消息接收处理失败", e);
-//                return null;
-//            }
-//        }
-//
-//        //上报地理位置事件
-//       log.info("上报地理位置,纬度 : {},经度 : {},精度 : {}",
-//            wxMessage.getLatitude(), wxMessage.getLongitude(), String.valueOf(wxMessage.getPrecision()));
-
-        //TODO  可以将用户地理位置信息保存到本地数据库,以便以后使用
+        // 防御性编程:必须是 LOCATION 消息
+        if (ObjectUtil.notEqual(wxMessage.getMsgType(), WxConsts.XmlMsgType.LOCATION)) {
+            return null;
+        }
+        log.info("[handle][上报地理位置,纬度({})、经度({})、精度({})", wxMessage.getLatitude(),
+                wxMessage.getLongitude(), wxMessage.getPrecision());
 
-        return null;
+        // 自动回复
+        return mpAutoReplyService.replyForMessage(MpContextHolder.getAppId(), wxMessage);
     }
 
 }

+ 6 - 23
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;
 import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO;
 import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder;
 import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
+import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService;
 import cn.iocoder.yudao.module.mp.service.user.MpUserService;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -22,19 +23,15 @@ import java.util.Map;
  * 关注的事件处理器
  *
  * @author 芋道源码
- *
- * // TODO 芋艿:待实现
  */
 @Component
 @Slf4j
 public class SubscribeHandler implements WxMpMessageHandler {
 
-    @Resource
-    @Lazy // 延迟加载,解决循环依赖的问题
-    private MpAccountService mpAccountService;
-
     @Resource
     private MpUserService mpUserService;
+    @Resource
+    private MpAutoReplyService mpAutoReplyService;
 
     @Override
     public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
@@ -49,24 +46,10 @@ public class SubscribeHandler implements WxMpMessageHandler {
         }
 
         // 第二步,保存用户信息
-        MpUserDO mpUser = null;
-        if (wxMpUser != null) {
-            mpUser = mpUserService.saveUser(MpContextHolder.getAppId(), wxMpUser);
-        }
-
-        // 第三步,回复关注的欢迎语  TODO 芋艿:关注的欢迎语
-//        return new TextBuilder().build("感谢关注", wxMessage, weixinService);
-        return null;
-    }
-
-    /**
-     * 处理特殊请求,比如如果是扫码进来的,可以做相应处理
-     */
-    private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage)
-            throws Exception {
+        mpUserService.saveUser(MpContextHolder.getAppId(), wxMpUser);
 
-        //TODO
-        return null;
+        // 第三步,回复关注的欢迎语
+        return mpAutoReplyService.replyForSubscribe(MpContextHolder.getAppId(), wxMessage);
     }
 
 }

+ 9 - 0
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 {
      */
     WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage);
 
+    /**
+     * 当用户关注时,自动回复
+     *
+     * @param appId 微信公众号 appId
+     * @param wxMessage 消息
+     * @return 回复的消息
+     */
+    WxMpXmlOutMessage replyForSubscribe(String appId, WxMpXmlMessage wxMessage);
+
 }

+ 28 - 5
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyServiceImpl.java

@@ -1,13 +1,16 @@
 package cn.iocoder.yudao.module.mp.service.message;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.iocoder.yudao.module.mp.builder.TextBuilder;
+import cn.hutool.core.lang.Assert;
+import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO;
 import cn.iocoder.yudao.module.mp.dal.mysql.message.MpAutoReplyMapper;
-import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyMatchEnum;
+import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyTypeEnum;
+import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
@@ -25,15 +28,15 @@ public class MpAutoReplyServiceImpl implements MpAutoReplyService {
 
     @Resource
     private MpMessageService mpMessageService;
+    @Resource
+    @Lazy // 延迟加载,避免循环依赖
+    private MpAccountService mpAccountService;
 
     @Resource
     private MpAutoReplyMapper mpAutoReplyMapper;
 
     @Override
     public WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage) {
-//        if (true) {
-//            return new TextBuilder().build("nihao", wxMessage, null);
-//        }
         // 第一步,匹配自动回复
         List<MpAutoReplyDO> replies = null;
         // 1.1 关键字
@@ -58,4 +61,24 @@ public class MpAutoReplyServiceImpl implements MpAutoReplyService {
         return mpMessageService.createFromAutoReply(wxMessage.getFromUser(), reply);
     }
 
+    @Override
+    public WxMpXmlOutMessage replyForSubscribe(String appId, WxMpXmlMessage wxMessage) {
+        // 第一步,匹配自动回复
+        List<MpAutoReplyDO> replies = mpAutoReplyMapper.selectListByAppIdAndSubscribe(appId);
+        MpAutoReplyDO reply = CollUtil.isNotEmpty(replies) ? CollUtil.getFirst(replies)
+                : buildDefaultSubscribeAutoReply(appId); // 如果不存在,提供一个默认末班
+
+        // 第二步,基于自动回复,创建消息
+        return mpMessageService.createFromAutoReply(wxMessage.getFromUser(), reply);
+    }
+
+    private MpAutoReplyDO buildDefaultSubscribeAutoReply(String appId) {
+        MpAccountDO account = mpAccountService.getAccountFromCache(appId);
+        Assert.notNull(account, "公众号账号({}) 不存在", appId);
+        // 构建默认的【关注】自动回复
+        return new MpAutoReplyDO().setAppId(appId).setAccountId(account.getId())
+                .setType(MpAutoReplyTypeEnum.SUBSCRIBE.getType())
+                .setResponseMessageType(WxConsts.XmlMsgType.TEXT).setResponseContent("感谢关注");
+    }
+
 }

+ 1 - 1
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 {
         }
         mpMessageMapper.insert(message);
 
-//        WxConsts.MenuButtonType.VIEW
+//        WxConsts.MenuButtonType.VIEW TODO 芋艿:待测试
 //        wxMessage.getEventKey()
 
 //        WxConsts.MenuButtonType.CLICK