Browse Source

mp:增加 MpServiceFactory 管理创建的 MpService~

YunaiV 2 years ago
parent
commit
275a1b10f6
25 changed files with 539 additions and 357 deletions
  1. 2 2
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/MpAccountController.java
  2. 0 9
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/account/MpAccountDO.java
  3. 6 0
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/account/MpAccountMapper.java
  4. 46 0
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/MpConfiguration.java
  5. 158 0
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java
  6. 38 0
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java
  7. 4 4
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/package-info.java
  8. 0 106
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/weixin/WxMpMessageRouterConfiguration.java
  9. 29 0
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/MpConfigRefreshConsumer.java
  10. 0 29
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/WxConfigDataRefreshConsumer.java
  11. 2 2
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/MpConfigRefreshMessage.java
  12. 4 4
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/MpConfigProducer.java
  13. 6 5
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountService.java
  14. 159 0
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java
  15. 0 157
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountServiceImpl.java
  16. 6 4
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/fansmsgres/NullHandler.java
  17. 14 6
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/DefaultMessageHandler.java
  18. 9 5
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/KfSessionHandler.java
  19. 8 4
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LocationHandler.java
  20. 9 4
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LogHandler.java
  21. 6 1
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/MenuHandler.java
  22. 4 1
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/ScanHandler.java
  23. 2 3
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/StoreCheckNotifyHandler.java
  24. 14 6
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/SubscribeHandler.java
  25. 13 5
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/UnsubscribeHandler.java

+ 2 - 2
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/MpAccountController.java

@@ -5,7 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.*;
 import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert;
 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
-import cn.iocoder.yudao.module.mp.service.account.WxAccountService;
+import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiOperation;
@@ -25,7 +25,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 public class MpAccountController {
 
     @Resource
-    private WxAccountService wxAccountService;
+    private MpAccountService wxAccountService;
 
     @PostMapping("/create")
     @ApiOperation("创建公众号账户")

+ 0 - 9
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/account/MpAccountDO.java

@@ -63,13 +63,4 @@ public class MpAccountDO extends BaseDO {
      */
     private String remark;
 
-    // TODO 芋艿:需要迁移走
-    public WxMpConfigStorage toWxMpConfigStorage(RedisTemplateWxRedisOps redisTemplateWxRedisOps, WxMpProperties wxMpProperties) {
-        WxMpRedisConfigImpl wxMpRedisConfig = new WxMpRedisConfigImpl(redisTemplateWxRedisOps, wxMpProperties.getConfigStorage().getKeyPrefix());
-        wxMpRedisConfig.setAppId(appId);
-        wxMpRedisConfig.setSecret(appSecret);
-        wxMpRedisConfig.setToken(token);
-        wxMpRedisConfig.setAesKey(aesKey);
-        return wxMpRedisConfig;
-    }
 }

+ 6 - 0
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/account/MpAccountMapper.java

@@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO;
 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.time.LocalDateTime;
 
 @Mapper
 public interface MpAccountMapper extends BaseMapperX<MpAccountDO> {
@@ -18,4 +21,7 @@ public interface MpAccountMapper extends BaseMapperX<MpAccountDO> {
                 .orderByDesc(MpAccountDO::getId));
     }
 
+    @Select("SELECT COUNT(*) FROM mp_account WHERE update_time > #{maxUpdateTime}")
+    Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
+
 }

+ 46 - 0
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/MpConfiguration.java

@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.mp.framework.mp.config;
+
+import cn.iocoder.yudao.module.mp.framework.mp.core.DefaultMpServiceFactory;
+import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
+import cn.iocoder.yudao.module.mp.service.fansmsgres.NullHandler;
+import cn.iocoder.yudao.module.mp.service.handler.*;
+import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
+import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.core.StringRedisTemplate;
+
+/**
+ * 微信公众号的配置类
+ *
+ * @author 芋道源码
+ */
+@Configuration
+public class MpConfiguration {
+
+    @Bean
+    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
+    public RedisTemplateWxRedisOps redisTemplateWxRedisOps(StringRedisTemplate stringRedisTemplate) {
+        return new RedisTemplateWxRedisOps(stringRedisTemplate);
+    }
+
+    @Bean
+    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
+    public MpServiceFactory mpServiceFactory(RedisTemplateWxRedisOps redisTemplateWxRedisOps,
+                                             WxMpProperties wxMpProperties,
+                                             LogHandler logHandler,
+                                             KfSessionHandler kfSessionHandler,
+                                             StoreCheckNotifyHandler storeCheckNotifyHandler,
+                                             MenuHandler menuHandler,
+                                             NullHandler nullHandler,
+                                             SubscribeHandler subscribeHandler,
+                                             UnsubscribeHandler unsubscribeHandler,
+                                             LocationHandler locationHandler,
+                                             ScanHandler scanHandler,
+                                             DefaultMessageHandler msgHandler) {
+        return new DefaultMpServiceFactory(redisTemplateWxRedisOps, wxMpProperties,
+                logHandler, kfSessionHandler, storeCheckNotifyHandler, menuHandler,
+                nullHandler, subscribeHandler, unsubscribeHandler, locationHandler, scanHandler, msgHandler);
+    }
+
+}

+ 158 - 0
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java

@@ -0,0 +1,158 @@
+package cn.iocoder.yudao.module.mp.framework.mp.core;
+
+import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
+import cn.iocoder.yudao.module.mp.service.fansmsgres.NullHandler;
+import cn.iocoder.yudao.module.mp.service.handler.*;
+import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
+import com.google.common.collect.Maps;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.api.WxConsts;
+import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
+import me.chanjar.weixin.mp.api.WxMpMessageRouter;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
+import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
+import me.chanjar.weixin.mp.constant.WxMpEventConstants;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 默认的 {@link MpServiceFactory} 实现类
+ *
+ * @author 芋道源码
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class DefaultMpServiceFactory implements MpServiceFactory {
+
+    /**
+     * 微信 appId 与 WxMpService 的映射
+     */
+    private volatile Map<String, WxMpService> mpServices;
+    /**
+     * 微信 appId 与 WxMpMessageRouter 的映射
+     */
+    private volatile Map<String, WxMpMessageRouter> mpMessageRouters;
+
+    private final RedisTemplateWxRedisOps redisTemplateWxRedisOps;
+    private final WxMpProperties mpProperties;
+
+    // ========== 各种 Handler ==========
+
+    private final LogHandler logHandler;
+    private final KfSessionHandler kfSessionHandler;
+    private final StoreCheckNotifyHandler storeCheckNotifyHandler;
+    private final MenuHandler menuHandler;
+    private final NullHandler nullHandler;
+    private final SubscribeHandler subscribeHandler;
+    private final UnsubscribeHandler unsubscribeHandler;
+    private final LocationHandler locationHandler;
+    private final ScanHandler scanHandler;
+    private final DefaultMessageHandler msgHandler;
+
+    @Override
+    public void init(List<MpAccountDO> list) {
+        Map<String, WxMpService> mpServices = Maps.newHashMap();
+        Map<String, WxMpMessageRouter> mpMessageRouters = Maps.newHashMap();
+        // 处理 list
+        list.forEach(account -> {
+            // 构建 WxMpService 对象
+            WxMpService mpService = buildMpService(account);
+            mpServices.put(account.getAppId(), mpService);
+            // 构建 WxMpMessageRouter 对象
+            WxMpMessageRouter mpMessageRouter = buildMpMessageRouter(mpService);
+            mpMessageRouters.put(account.getAppId(), mpMessageRouter);
+        });
+
+        // 设置到缓存
+        this.mpServices = mpServices;
+        this.mpMessageRouters = mpMessageRouters;
+    }
+
+    @Override
+    public WxMpService getMpService(String appId) {
+        return mpServices.get(appId);
+    }
+
+    @Override
+    public WxMpMessageRouter getMpMessageRouter(String appId) {
+        return mpMessageRouters.get(appId);
+    }
+
+    private WxMpService buildMpService(MpAccountDO account) {
+        // 第一步,创建 WxMpRedisConfigImpl 对象
+        // TODO 芋艿:需要确认下,redis key 的存储结构
+        WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl(
+                redisTemplateWxRedisOps, mpProperties.getConfigStorage().getKeyPrefix());
+        configStorage.setAppId(account.getAppId());
+        configStorage.setSecret(account.getAppSecret());
+        configStorage.setToken(account.getToken());
+        configStorage.setAesKey(account.getAesKey());
+
+        // 第二步,创建 WxMpService 对象
+        WxMpService service = new WxMpServiceImpl();
+        service.setWxMpConfigStorage(configStorage);
+        return null;
+    }
+
+    private WxMpMessageRouter buildMpMessageRouter(WxMpService mpService) {
+        final WxMpMessageRouter newRouter = new WxMpMessageRouter(mpService);
+        // 记录所有事件的日志(异步执行)
+        newRouter.rule().handler(logHandler).next();
+
+        // 接收客服会话管理事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION)
+                .handler(kfSessionHandler).end();
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION)
+                .handler(kfSessionHandler)
+                .end();
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION)
+                .handler(kfSessionHandler).end();
+
+        // 门店审核事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxMpEventConstants.POI_CHECK_NOTIFY)
+                .handler(storeCheckNotifyHandler).end();
+
+        // 自定义菜单事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxConsts.MenuButtonType.CLICK).handler(menuHandler).end();
+
+        // 点击菜单连接事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxConsts.MenuButtonType.VIEW).handler(nullHandler).end();
+
+        // 关注事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxConsts.EventType.SUBSCRIBE).handler(subscribeHandler)
+                .end();
+
+        // 取消关注事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxConsts.EventType.UNSUBSCRIBE)
+                .handler(unsubscribeHandler).end();
+
+        // 上报地理位置事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxConsts.EventType.LOCATION).handler(locationHandler)
+                .end();
+
+        // 接收地理位置消息
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION)
+                .handler(locationHandler).end();
+
+        // 扫码事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxConsts.EventType.SCAN).handler(scanHandler).end();
+
+        // 默认
+        newRouter.rule().async(false).handler(msgHandler).end();
+        return newRouter;
+    }
+
+}

+ 38 - 0
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.mp.framework.mp.core;
+
+import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
+import me.chanjar.weixin.mp.api.WxMpMessageRouter;
+import me.chanjar.weixin.mp.api.WxMpService;
+
+import java.util.List;
+
+/**
+ * {@link WxMpService} 工厂接口
+ *
+ * @author 芋道源码
+ */
+public interface MpServiceFactory {
+
+    /**
+     * 基于微信公众号的账号,初始化对应的 WxMpService 与 WxMpMessageRouter 实例
+     *
+     * @param list 公众号的账号列表
+     */
+    void init(List<MpAccountDO> list);
+
+    /**
+     * 获得 appId 对应的 WxMpService 实例
+     *
+     * @param appId 微信公众号 appId
+     * @return WxMpService 实例
+     */
+    WxMpService getMpService(String appId);
+
+    /**
+     * 获得 appId 对应的 WxMpMessageRouter 实例
+     *
+     * @param appId 微信公众号 appId
+     * @return WxMpMessageRouter 实例
+     */
+    WxMpMessageRouter getMpMessageRouter(String appId);
+}

+ 4 - 4
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/package-info.java

@@ -1,6 +1,6 @@
 /**
- * @date 2022/6/20
- * @author feng-dan
- * @version 1.0
+ * 属于 mp 模块的 framework 封装
+ *
+ * @author 芋道源码
  */
-package cn.iocoder.yudao.module.mp.framework;
+package cn.iocoder.yudao.module.mp.framework;

+ 0 - 106
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/weixin/WxMpMessageRouterConfiguration.java

@@ -1,106 +0,0 @@
-package cn.iocoder.yudao.module.mp.framework.weixin;
-
-
-import cn.iocoder.yudao.module.mp.handler.*;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.api.WxConsts;
-import me.chanjar.weixin.mp.api.WxMpMessageRouter;
-import me.chanjar.weixin.mp.api.WxMpService;
-import me.chanjar.weixin.mp.constant.WxMpEventConstants;
-import org.springframework.context.annotation.Bean;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * @author fengdan
- */
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class WxMpMessageRouterConfiguration {
-
-    @Resource
-    private WxMpService wxMpService;
-    @Resource
-    private LogHandler logHandler;
-    @Resource
-    private KfSessionHandler kfSessionHandler;
-    @Resource
-    private StoreCheckNotifyHandler storeCheckNotifyHandler;
-    @Resource
-    private MenuHandler menuHandler;
-    @Resource
-    private NullHandler nullHandler;
-    @Resource
-    private SubscribeHandler subscribeHandler;
-    @Resource
-    private UnsubscribeHandler unsubscribeHandler;
-    @Resource
-    private LocationHandler locationHandler;
-    @Resource
-    private ScanHandler scanHandler;
-    @Resource
-    private MsgHandler msgHandler;
-
-    @Bean
-    public WxMpMessageRouter messageRouter() {
-        final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);
-        // 记录所有事件的日志 (异步执行)
-        newRouter.rule().handler(logHandler).next();
-
-        // 接收客服会话管理事件
-        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
-                .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION)
-                .handler(kfSessionHandler).end();
-        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
-                .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION)
-                .handler(kfSessionHandler)
-                .end();
-        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
-                .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION)
-                .handler(kfSessionHandler).end();
-
-        // 门店审核事件
-        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
-                .event(WxMpEventConstants.POI_CHECK_NOTIFY)
-                .handler(storeCheckNotifyHandler).end();
-
-        // 自定义菜单事件
-        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
-                .event(WxConsts.MenuButtonType.CLICK).handler(menuHandler).end();
-
-        // 点击菜单连接事件
-        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
-                .event(WxConsts.MenuButtonType.VIEW).handler(nullHandler).end();
-
-        // 关注事件
-        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
-                .event(WxConsts.EventType.SUBSCRIBE).handler(subscribeHandler)
-                .end();
-
-        // 取消关注事件
-        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
-                .event(WxConsts.EventType.UNSUBSCRIBE)
-                .handler(unsubscribeHandler).end();
-
-        // 上报地理位置事件
-        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
-                .event(WxConsts.EventType.LOCATION).handler(locationHandler)
-                .end();
-
-        // 接收地理位置消息
-        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION)
-                .handler(locationHandler).end();
-
-        // 扫码事件
-        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
-                .event(WxConsts.EventType.SCAN).handler(scanHandler).end();
-
-        // 默认
-        newRouter.rule().async(false).handler(msgHandler).end();
-
-        return newRouter;
-    }
-}

+ 29 - 0
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/MpConfigRefreshConsumer.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.mp.mq.costomer;
+
+import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
+import cn.iocoder.yudao.module.mp.mq.message.MpConfigRefreshMessage;
+import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 针对 {@link MpConfigRefreshMessage} 的消费者
+ *
+ * @author lyz
+ */
+@Component
+@Slf4j
+public class MpConfigRefreshConsumer extends AbstractChannelMessageListener<MpConfigRefreshMessage> {
+
+    @Resource
+    private MpAccountService wxAccountService;
+
+    @Override
+    public void onMessage(MpConfigRefreshMessage message) {
+        log.info("[onMessage][收到 MpConfig 刷新消息]");
+        wxAccountService.initLocalCache();
+    }
+
+}

+ 0 - 29
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/WxConfigDataRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.mp.mq.costomer;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.mp.mq.message.WxConfigDataRefreshMessage;
-import cn.iocoder.yudao.module.mp.service.account.WxAccountService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link WxConfigDataRefreshMessage} 的消费者
- *
- * @author lyz
- */
-@Component
-@Slf4j
-public class WxConfigDataRefreshConsumer extends AbstractChannelMessageListener<WxConfigDataRefreshMessage> {
-
-    @Resource
-    private WxAccountService wxAccountService;
-
-    @Override
-    public void onMessage(WxConfigDataRefreshMessage message) {
-        log.info("[onMessage][收到 WxConfigData 刷新消息]");
-        wxAccountService.initLoadWxMpConfigStorages();
-    }
-
-}

+ 2 - 2
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/WxConfigDataRefreshMessage.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/MpConfigRefreshMessage.java

@@ -9,11 +9,11 @@ import lombok.EqualsAndHashCode;
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
-public class WxConfigDataRefreshMessage extends AbstractChannelMessage {
+public class MpConfigRefreshMessage extends AbstractChannelMessage {
 
     @Override
     public String getChannel() {
-        return "wechat-mp.wx-config-data.refresh";
+        return "mp.config-data.refresh";
     }
 
 }

+ 4 - 4
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/WxMpConfigDataProducer.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/MpConfigProducer.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.mp.mq.producer;
 
 import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
-import cn.iocoder.yudao.module.mp.mq.message.WxConfigDataRefreshMessage;
+import cn.iocoder.yudao.module.mp.mq.message.MpConfigRefreshMessage;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
@@ -10,16 +10,16 @@ import javax.annotation.Resource;
  * 微信配置数据相关消息的 Producer
  */
 @Component
-public class WxMpConfigDataProducer {
+public class MpConfigProducer {
 
     @Resource
     private RedisMQTemplate redisMQTemplate;
 
     /**
-     * 发送 {@link WxConfigDataRefreshMessage} 消息
+     * 发送 {@link MpConfigRefreshMessage} 消息
      */
     public void sendDictDataRefreshMessage() {
-        WxConfigDataRefreshMessage message = new WxConfigDataRefreshMessage();
+        MpConfigRefreshMessage message = new MpConfigRefreshMessage();
         redisMQTemplate.send(message);
     }
 

+ 6 - 5
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountService.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountService.java

@@ -14,7 +14,12 @@ import javax.validation.Valid;
  *
  * @author 芋道源码
  */
-public interface WxAccountService {
+public interface MpAccountService {
+
+    /**
+     * 初始化缓存
+     */
+    void initLocalCache();
 
     /**
      * 创建公众号账户
@@ -64,8 +69,4 @@ public interface WxAccountService {
      */
     MpAccountDO findBy(SFunction<MpAccountDO, ?> field, Object val);
 
-    /**
-     * 初始化
-     */
-    void initLoadWxMpConfigStorages();
 }

+ 159 - 0
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java

@@ -0,0 +1,159 @@
+package cn.iocoder.yudao.module.mp.service.account;
+
+import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
+import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO;
+import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO;
+import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountUpdateReqVO;
+import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert;
+import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
+import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper;
+import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants;
+import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
+import cn.iocoder.yudao.module.mp.mq.producer.MpConfigProducer;
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.util.List;
+
+
+/**
+ * 公众号账户 Service 实现类
+ *
+ * @author fengdan
+ */
+@Slf4j
+@Service
+@Validated
+public class MpAccountServiceImpl implements MpAccountService {
+
+    /**
+     * 定时执行 {@link #schedulePeriodicRefresh()} 的周期
+     * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高
+     */
+    private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
+
+    /**
+     * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新
+     */
+    @Getter
+    private volatile LocalDateTime maxUpdateTime;
+
+    @Resource
+    private MpAccountMapper mpAccountMapper;
+
+    @Resource
+    @Lazy // 延迟加载,解决循环依赖的问题
+    private MpServiceFactory mpServiceFactory;
+
+    @Resource
+    private MpConfigProducer mpConfigDataProducer;
+
+    @Override
+    @PostConstruct
+    public void initLocalCache() {
+        initLocalCacheIfUpdate(null);
+    }
+
+    @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
+    public void schedulePeriodicRefresh() {
+        initLocalCacheIfUpdate(this.maxUpdateTime);
+    }
+
+    /**
+     * 刷新本地缓存
+     *
+     * @param maxUpdateTime 最大更新时间
+     *                      1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
+     *                      2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
+     */
+    private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
+        // 注意:忽略自动多租户,因为要全局初始化缓存
+        TenantUtils.executeIgnore(() -> {
+            // 第一步:基于 maxUpdateTime 判断缓存是否刷新。
+            // 如果没有增量的数据变化,则不进行本地缓存的刷新
+            if (maxUpdateTime != null
+                    && mpAccountMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
+                log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
+                return;
+            }
+            List<MpAccountDO> accounts = mpAccountMapper.selectList();
+            log.info("[initLocalCacheIfUpdate][缓存公众号账号,数量为:{}]", accounts.size());
+
+            // 第二步:构建缓存。创建或更新支付 Client
+            mpServiceFactory.init(accounts);
+
+            // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
+            this.maxUpdateTime = CollectionUtils.getMaxValue(accounts, MpAccountDO::getUpdateTime);
+        });
+    }
+
+    @Override
+    public Long createAccount(MpAccountCreateReqVO createReqVO) {
+        // TODO 芋艿:校验唯一性
+        // 插入
+        MpAccountDO wxAccount = MpAccountConvert.INSTANCE.convert(createReqVO);
+        mpAccountMapper.insert(wxAccount);
+
+        // TODO 芋艿:刷新的方式
+        mpConfigDataProducer.sendDictDataRefreshMessage();
+        // 返回
+        return wxAccount.getId();
+    }
+
+    @Override
+    public void updateAccount(MpAccountUpdateReqVO updateReqVO) {
+        // TODO 芋艿:校验唯一性
+        // 校验存在
+        validateWxAccountExists(updateReqVO.getId());
+        // 更新
+        MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO);
+        mpAccountMapper.updateById(updateObj);
+
+        // TODO 芋艿:刷新的方式
+        mpConfigDataProducer.sendDictDataRefreshMessage();
+    }
+
+    @Override
+    public void deleteAccount(Long id) {
+        // 校验存在
+        validateWxAccountExists(id);
+        // 删除
+        mpAccountMapper.deleteById(id);
+
+        // TODO 芋艿:刷新的方式
+        mpConfigDataProducer.sendDictDataRefreshMessage();
+    }
+
+    private void validateWxAccountExists(Long id) {
+        if (mpAccountMapper.selectById(id) == null) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.WX_ACCOUNT_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public MpAccountDO getAccount(Long id) {
+        return mpAccountMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<MpAccountDO> getAccountPage(MpAccountPageReqVO pageReqVO) {
+        return mpAccountMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public MpAccountDO findBy(SFunction<MpAccountDO, ?> field, Object val) {
+        return mpAccountMapper.selectOne(field, val);
+    }
+
+}

+ 0 - 157
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountServiceImpl.java

@@ -1,157 +0,0 @@
-package cn.iocoder.yudao.module.mp.service.account;
-
-import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
-import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO;
-import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO;
-import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountUpdateReqVO;
-import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert;
-import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
-import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper;
-import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants;
-import cn.iocoder.yudao.module.mp.mq.producer.WxMpConfigDataProducer;
-import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
-import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
-import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
-import me.chanjar.weixin.mp.api.WxMpService;
-import me.chanjar.weixin.mp.config.WxMpConfigStorage;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-import org.springframework.validation.annotation.Validated;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.Resource;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-
-/**
- * 公众号账户 Service 实现类
- *
- * @author fengdan
- */
-@Slf4j
-@Service
-@Validated
-public class WxAccountServiceImpl implements WxAccountService {
-
-    private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
-
-    @Resource
-    private MpAccountMapper wxAccountMapper;
-    @Resource
-    private WxMpConfigDataProducer wxMpConfigDataProducer;
-    @Resource
-    private StringRedisTemplate stringRedisTemplate;
-    @Resource
-    private WxMpService wxMpService;
-    @Resource
-    private WxMpProperties wxMpProperties;
-    @Resource
-    @Lazy // 注入自己,所以延迟加载
-    private WxAccountService self;
-
-    @Override
-    public Long createAccount(MpAccountCreateReqVO createReqVO) {
-        // TODO 芋艿:校验唯一性
-        // 插入
-        MpAccountDO wxAccount = MpAccountConvert.INSTANCE.convert(createReqVO);
-        wxAccountMapper.insert(wxAccount);
-
-        // TODO 芋艿:刷新的方式
-        wxMpConfigDataProducer.sendDictDataRefreshMessage();
-        // 返回
-        return wxAccount.getId();
-    }
-
-    @Override
-    public void updateAccount(MpAccountUpdateReqVO updateReqVO) {
-        // TODO 芋艿:校验唯一性
-        // 校验存在
-        validateWxAccountExists(updateReqVO.getId());
-        // 更新
-        MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO);
-        wxAccountMapper.updateById(updateObj);
-
-        // TODO 芋艿:刷新的方式
-        wxMpConfigDataProducer.sendDictDataRefreshMessage();
-    }
-
-    @Override
-    public void deleteAccount(Long id) {
-        // 校验存在
-        validateWxAccountExists(id);
-        // 删除
-        wxAccountMapper.deleteById(id);
-
-        // TODO 芋艿:刷新的方式
-        wxMpConfigDataProducer.sendDictDataRefreshMessage();
-    }
-
-    private void validateWxAccountExists(Long id) {
-        if (wxAccountMapper.selectById(id) == null) {
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.WX_ACCOUNT_NOT_EXISTS);
-        }
-    }
-
-    @Override
-    public MpAccountDO getAccount(Long id) {
-        return wxAccountMapper.selectById(id);
-    }
-
-    @Override
-    public PageResult<MpAccountDO> getAccountPage(MpAccountPageReqVO pageReqVO) {
-        return wxAccountMapper.selectPage(pageReqVO);
-    }
-
-    @Override
-    public MpAccountDO findBy(SFunction<MpAccountDO, ?> field, Object val) {
-        return wxAccountMapper.selectOne(field, val);
-    }
-
-    @PostConstruct
-    @TenantIgnore
-    @Override
-    public void initLoadWxMpConfigStorages() {
-        // TODO 芋艿:刷新的方式
-        List<MpAccountDO> wxAccountList = this.wxAccountMapper.selectList();
-        if (CollectionUtils.isEmpty(wxAccountList)) {
-            log.info("未读取到公众号配置,请在管理后台添加");
-            return;
-        }
-        log.info("加载到{}条公众号配置", wxAccountList.size());
-        wxAccountList.forEach(account -> addAccountToRuntime(account, new RedisTemplateWxRedisOps(stringRedisTemplate)));
-        log.info("公众号配置加载完成");
-    }
-
-    /**
-     * 添加账号到当前程序,如首次添加需初始化configStorageMap
-     *
-     * @param account 公众号
-     */
-    private synchronized void addAccountToRuntime(MpAccountDO account, RedisTemplateWxRedisOps redisOps) {
-        String appId = account.getAppId();
-        WxMpConfigStorage wxMpRedisConfig = account.toWxMpConfigStorage(redisOps, wxMpProperties);
-        try {
-            wxMpService.addConfigStorage(appId, wxMpRedisConfig);
-        } catch (NullPointerException e) {
-            log.info("需初始化configStorageMap...");
-            Map<String, WxMpConfigStorage> configStorages = new HashMap<>(4);
-            configStorages.put(appId, wxMpRedisConfig);
-            wxMpService.setMultiConfigStorages(configStorages, appId);
-        }
-    }
-
-    @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
-    public void schedulePeriodicRefresh() {
-        self.initLoadWxMpConfigStorages();
-    }
-
-
-}

+ 6 - 4
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/NullHandler.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/fansmsgres/NullHandler.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.mp.handler;
+package cn.iocoder.yudao.module.mp.service.fansmsgres;
 
 import me.chanjar.weixin.common.session.WxSessionManager;
 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
@@ -9,13 +9,15 @@ import org.springframework.stereotype.Component;
 
 import java.util.Map;
 
+/**
+ * 点击菜单连接的事件处理器
+ */
 @Component
 public class NullHandler implements WxMpMessageHandler {
 
     @Override
-    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
-                                    Map<String, Object> context, WxMpService wxMpService,
-                                    WxSessionManager sessionManager) {
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
+                                    WxMpService wxMpService, WxSessionManager sessionManager) {
         return null;
     }
 

+ 14 - 6
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MsgHandler.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/DefaultMessageHandler.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.mp.handler;
+package cn.iocoder.yudao.module.mp.service.handler;
 
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.http.HtmlUtil;
@@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.infra.api.file.FileApi;
 import cn.iocoder.yudao.module.mp.builder.TextBuilder;
 import cn.iocoder.yudao.module.mp.controller.admin.fansmsg.vo.WxFansMsgCreateReqVO;
 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
-import cn.iocoder.yudao.module.mp.service.account.WxAccountService;
+import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
 import cn.iocoder.yudao.module.mp.service.fansmsg.WxFansMsgService;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.api.WxConsts;
@@ -21,6 +21,7 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
 import me.chanjar.weixin.mp.bean.result.WxMpUser;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
@@ -28,11 +29,18 @@ import java.io.File;
 import java.io.UnsupportedEncodingException;
 import java.util.Map;
 
+/**
+ * 默认所有消息的事件处理器
+ *
+ * // TODO 芋艿:待实现
+ */
 @Component
 @Slf4j
-public class MsgHandler implements WxMpMessageHandler {
-    @Autowired
-    private WxAccountService wxAccountService;
+public class DefaultMessageHandler implements WxMpMessageHandler {
+
+    @Resource
+    @Lazy // 延迟加载,解决循环依赖的问题
+    private MpAccountService mpAccountService;
 
     @Autowired
     private WxFansMsgService wxFansMsgService;
@@ -55,7 +63,7 @@ public class MsgHandler implements WxMpMessageHandler {
                 WxMpUser wxmpUser = weixinService.getUserService()
                         .userInfo(wxMessage.getFromUser(), null);
                 if (wxmpUser != null) {
-                    MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
+                    MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
                     if (wxAccount != null) {
 
                         if (wxMessage.getMsgType().equals(WxConsts.XmlMsgType.TEXT)) {

+ 9 - 5
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/KfSessionHandler.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/KfSessionHandler.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.mp.handler;
+package cn.iocoder.yudao.module.mp.service.handler;
 
 import me.chanjar.weixin.common.session.WxSessionManager;
 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
@@ -9,14 +9,18 @@ import org.springframework.stereotype.Component;
 
 import java.util.Map;
 
+/**
+ * 接收客服会话管理的事件处理器
+ *
+ * @author 芋道源码
+ */
 @Component
 public class KfSessionHandler implements WxMpMessageHandler {
 
     @Override
-    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
-                                    Map<String, Object> context, WxMpService wxMpService,
-                                    WxSessionManager sessionManager) {
-        //TODO 对会话做处理
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
+                                    WxMpService wxMpService, WxSessionManager sessionManager) {
+        // TODO 对会话做处理
         return null;
     }
 

+ 8 - 4
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LocationHandler.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LocationHandler.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.mp.handler;
+package cn.iocoder.yudao.module.mp.service.handler;
 
 import cn.iocoder.yudao.module.mp.builder.TextBuilder;
 import lombok.extern.slf4j.Slf4j;
@@ -13,14 +13,18 @@ import java.util.Map;
 
 import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
 
+/**
+ * 上报地理位置的事件处理器
+ *
+ * // TODO @芋艿:需要实现一下~
+ */
 @Component
 @Slf4j
 public class LocationHandler implements WxMpMessageHandler {
 
     @Override
-    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
-                                    Map<String, Object> context, WxMpService wxMpService,
-                                    WxSessionManager sessionManager) {
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
+                                    WxMpService wxMpService, WxSessionManager sessionManager) {
         if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
             //TODO 接收处理用户发送的地理位置消息
             try {

+ 9 - 4
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LogHandler.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LogHandler.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.mp.handler;
+package cn.iocoder.yudao.module.mp.service.handler;
 
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import lombok.extern.slf4j.Slf4j;
@@ -11,13 +11,18 @@ import org.springframework.stereotype.Component;
 
 import java.util.Map;
 
+/**
+ * 保存微信消息的事件处理器
+ *
+ * // TODO 芋艿:实现一下
+ */
 @Component
 @Slf4j
 public class LogHandler implements WxMpMessageHandler {
+
     @Override
-    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
-                                    Map<String, Object> context, WxMpService wxMpService,
-                                    WxSessionManager sessionManager) {
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
+                                    WxMpService wxMpService, WxSessionManager sessionManager) {
         log.info("接收到请求消息,内容:{}", JsonUtils.toJsonString(wxMessage));
         return null;
     }

+ 6 - 1
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MenuHandler.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/MenuHandler.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.mp.handler;
+package cn.iocoder.yudao.module.mp.service.handler;
 
 import me.chanjar.weixin.common.session.WxSessionManager;
 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
@@ -11,6 +11,11 @@ import java.util.Map;
 
 import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
 
+/**
+ * 自定义菜单的事件处理器
+ *
+ * // TODO 芋艿:待实现
+ */
 @Component
 public class MenuHandler implements WxMpMessageHandler {
 

+ 4 - 1
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/ScanHandler.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/ScanHandler.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.mp.handler;
+package cn.iocoder.yudao.module.mp.service.handler;
 
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.session.WxSessionManager;
@@ -10,6 +10,9 @@ import org.springframework.stereotype.Component;
 
 import java.util.Map;
 
+/**
+ * 扫码的事件处理器
+ */
 @Component
 public class ScanHandler implements WxMpMessageHandler {
 

+ 2 - 3
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/StoreCheckNotifyHandler.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/StoreCheckNotifyHandler.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.mp.handler;
+package cn.iocoder.yudao.module.mp.service.handler;
 
 import me.chanjar.weixin.common.session.WxSessionManager;
 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
@@ -10,8 +10,7 @@ import org.springframework.stereotype.Component;
 import java.util.Map;
 
 /**
- * 门店审核事件处理
- *
+ * 门店审核事件的事件处理器
  */
 @Component
 public class StoreCheckNotifyHandler implements WxMpMessageHandler {

+ 14 - 6
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/SubscribeHandler.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/SubscribeHandler.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.mp.handler;
+package cn.iocoder.yudao.module.mp.service.handler;
 
 import cn.hutool.core.date.DateUtil;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
@@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
 import cn.iocoder.yudao.module.mp.dal.dataobject.accountfans.WxAccountFansDO;
 import cn.iocoder.yudao.module.mp.dal.dataobject.subscribetext.WxSubscribeTextDO;
 import cn.iocoder.yudao.module.mp.dal.dataobject.texttemplate.WxTextTemplateDO;
-import cn.iocoder.yudao.module.mp.service.account.WxAccountService;
+import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
 import cn.iocoder.yudao.module.mp.service.accountfans.WxAccountFansService;
 import cn.iocoder.yudao.module.mp.service.accountfanstag.WxAccountFansTagService;
 import cn.iocoder.yudao.module.mp.service.subscribetext.WxSubscribeTextService;
@@ -23,11 +23,18 @@ 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.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.Resource;
 import java.io.UnsupportedEncodingException;
 import java.util.Map;
 
+/**
+ * 关注的事件处理器
+ *
+ * // TODO 芋艿:待实现
+ */
 @Component
 @Slf4j
 public class SubscribeHandler implements WxMpMessageHandler {
@@ -35,8 +42,9 @@ public class SubscribeHandler implements WxMpMessageHandler {
     @Autowired
     private WxTextTemplateService wxTextTemplateService;
 
-    @Autowired
-    private WxAccountService wxAccountService;
+    @Resource
+    @Lazy // 延迟加载,解决循环依赖的问题
+    private MpAccountService mpAccountService;
 
     @Autowired
     private WxSubscribeTextService wxSubscribeTextService;
@@ -60,7 +68,7 @@ public class SubscribeHandler implements WxMpMessageHandler {
                     .userInfo(wxMessage.getFromUser(), null);
             if (wxmpUser != null) {
                 // 可以添加关注用户到本地数据库
-                MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
+                MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
                 if (wxAccount != null) {
                     WxAccountFansDO wxAccountFans = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, wxmpUser.getOpenId());
                     if (wxAccountFans == null) {//insert
@@ -128,7 +136,7 @@ public class SubscribeHandler implements WxMpMessageHandler {
 
         try {
             String content = "感谢关注!";//默认
-            MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
+            MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
             if (wxAccount != null) {
                 WxSubscribeTextDO wxSubscribeText = wxSubscribeTextService.findBy(WxSubscribeTextDO::getWxAccountId, String.valueOf(wxAccount.getId()));
                 if (wxSubscribeText != null) {

+ 13 - 5
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/UnsubscribeHandler.java → yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/UnsubscribeHandler.java

@@ -1,9 +1,9 @@
-package cn.iocoder.yudao.module.mp.handler;
+package cn.iocoder.yudao.module.mp.service.handler;
 
 import cn.iocoder.yudao.module.mp.controller.admin.accountfans.vo.WxAccountFansUpdateReqVO;
 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
 import cn.iocoder.yudao.module.mp.dal.dataobject.accountfans.WxAccountFansDO;
-import cn.iocoder.yudao.module.mp.service.account.WxAccountService;
+import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
 import cn.iocoder.yudao.module.mp.service.accountfans.WxAccountFansService;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.session.WxSessionManager;
@@ -12,16 +12,24 @@ import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.Resource;
 import java.util.Map;
 
+/**
+ * 取消关注的事件处理器
+ *
+ * // TODO 芋艿:待实现
+ */
 @Component
 @Slf4j
 public class UnsubscribeHandler implements WxMpMessageHandler {
 
-    @Autowired
-    private WxAccountService wxAccountService;
+    @Resource
+    @Lazy // 延迟加载,解决循环依赖的问题
+    private MpAccountService mpAccountService;
 
     @Autowired
     private WxAccountFansService wxAccountFansService;
@@ -34,7 +42,7 @@ public class UnsubscribeHandler implements WxMpMessageHandler {
         log.info("取消关注用户 OPENID: " + openId);
         // TODO 可以更新本地数据库为取消关注状态
 
-        MpAccountDO wxAccountDO = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
+        MpAccountDO wxAccountDO = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
         if (wxAccountDO != null) {
             WxAccountFansDO wxAccountFansDO = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, openId);
             if (wxAccountFansDO != null) {