Commit 275a1b10f671cedbb72d0170f3a68a1ed4efa9dd

Authored by YunaiV
1 parent 627cb395

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

Showing 23 changed files with 431 additions and 249 deletions
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;
5 5 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.*;
6 6 import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert;
7 7 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
8   -import cn.iocoder.yudao.module.mp.service.account.WxAccountService;
  8 +import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
9 9 import io.swagger.annotations.Api;
10 10 import io.swagger.annotations.ApiImplicitParam;
11 11 import io.swagger.annotations.ApiOperation;
... ... @@ -25,7 +25,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
25 25 public class MpAccountController {
26 26  
27 27 @Resource
28   - private WxAccountService wxAccountService;
  28 + private MpAccountService wxAccountService;
29 29  
30 30 @PostMapping("/create")
31 31 @ApiOperation("创建公众号账户")
... ...
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 {
63 63 */
64 64 private String remark;
65 65  
66   - // TODO 芋艿:需要迁移走
67   - public WxMpConfigStorage toWxMpConfigStorage(RedisTemplateWxRedisOps redisTemplateWxRedisOps, WxMpProperties wxMpProperties) {
68   - WxMpRedisConfigImpl wxMpRedisConfig = new WxMpRedisConfigImpl(redisTemplateWxRedisOps, wxMpProperties.getConfigStorage().getKeyPrefix());
69   - wxMpRedisConfig.setAppId(appId);
70   - wxMpRedisConfig.setSecret(appSecret);
71   - wxMpRedisConfig.setToken(token);
72   - wxMpRedisConfig.setAesKey(aesKey);
73   - return wxMpRedisConfig;
74   - }
75 66 }
... ...
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;
6 6 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO;
7 7 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
8 8 import org.apache.ibatis.annotations.Mapper;
  9 +import org.apache.ibatis.annotations.Select;
  10 +
  11 +import java.time.LocalDateTime;
9 12  
10 13 @Mapper
11 14 public interface MpAccountMapper extends BaseMapperX<MpAccountDO> {
... ... @@ -18,4 +21,7 @@ public interface MpAccountMapper extends BaseMapperX&lt;MpAccountDO&gt; {
18 21 .orderByDesc(MpAccountDO::getId));
19 22 }
20 23  
  24 + @Select("SELECT COUNT(*) FROM mp_account WHERE update_time > #{maxUpdateTime}")
  25 + Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
  26 +
21 27 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/MpConfiguration.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mp.framework.mp.config;
  2 +
  3 +import cn.iocoder.yudao.module.mp.framework.mp.core.DefaultMpServiceFactory;
  4 +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
  5 +import cn.iocoder.yudao.module.mp.service.fansmsgres.NullHandler;
  6 +import cn.iocoder.yudao.module.mp.service.handler.*;
  7 +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
  8 +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
  9 +import org.springframework.context.annotation.Bean;
  10 +import org.springframework.context.annotation.Configuration;
  11 +import org.springframework.data.redis.core.StringRedisTemplate;
  12 +
  13 +/**
  14 + * 微信公众号的配置类
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@Configuration
  19 +public class MpConfiguration {
  20 +
  21 + @Bean
  22 + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
  23 + public RedisTemplateWxRedisOps redisTemplateWxRedisOps(StringRedisTemplate stringRedisTemplate) {
  24 + return new RedisTemplateWxRedisOps(stringRedisTemplate);
  25 + }
  26 +
  27 + @Bean
  28 + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
  29 + public MpServiceFactory mpServiceFactory(RedisTemplateWxRedisOps redisTemplateWxRedisOps,
  30 + WxMpProperties wxMpProperties,
  31 + LogHandler logHandler,
  32 + KfSessionHandler kfSessionHandler,
  33 + StoreCheckNotifyHandler storeCheckNotifyHandler,
  34 + MenuHandler menuHandler,
  35 + NullHandler nullHandler,
  36 + SubscribeHandler subscribeHandler,
  37 + UnsubscribeHandler unsubscribeHandler,
  38 + LocationHandler locationHandler,
  39 + ScanHandler scanHandler,
  40 + DefaultMessageHandler msgHandler) {
  41 + return new DefaultMpServiceFactory(redisTemplateWxRedisOps, wxMpProperties,
  42 + logHandler, kfSessionHandler, storeCheckNotifyHandler, menuHandler,
  43 + nullHandler, subscribeHandler, unsubscribeHandler, locationHandler, scanHandler, msgHandler);
  44 + }
  45 +
  46 +}
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mp.framework.mp.core;
  2 +
  3 +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
  4 +import cn.iocoder.yudao.module.mp.service.fansmsgres.NullHandler;
  5 +import cn.iocoder.yudao.module.mp.service.handler.*;
  6 +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
  7 +import com.google.common.collect.Maps;
  8 +import lombok.RequiredArgsConstructor;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import me.chanjar.weixin.common.api.WxConsts;
  11 +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
  12 +import me.chanjar.weixin.mp.api.WxMpMessageRouter;
  13 +import me.chanjar.weixin.mp.api.WxMpService;
  14 +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
  15 +import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
  16 +import me.chanjar.weixin.mp.constant.WxMpEventConstants;
  17 +
  18 +import java.util.List;
  19 +import java.util.Map;
  20 +
  21 +/**
  22 + * 默认的 {@link MpServiceFactory} 实现类
  23 + *
  24 + * @author 芋道源码
  25 + */
  26 +@Slf4j
  27 +@RequiredArgsConstructor
  28 +public class DefaultMpServiceFactory implements MpServiceFactory {
  29 +
  30 + /**
  31 + * 微信 appId 与 WxMpService 的映射
  32 + */
  33 + private volatile Map<String, WxMpService> mpServices;
  34 + /**
  35 + * 微信 appId 与 WxMpMessageRouter 的映射
  36 + */
  37 + private volatile Map<String, WxMpMessageRouter> mpMessageRouters;
  38 +
  39 + private final RedisTemplateWxRedisOps redisTemplateWxRedisOps;
  40 + private final WxMpProperties mpProperties;
  41 +
  42 + // ========== 各种 Handler ==========
  43 +
  44 + private final LogHandler logHandler;
  45 + private final KfSessionHandler kfSessionHandler;
  46 + private final StoreCheckNotifyHandler storeCheckNotifyHandler;
  47 + private final MenuHandler menuHandler;
  48 + private final NullHandler nullHandler;
  49 + private final SubscribeHandler subscribeHandler;
  50 + private final UnsubscribeHandler unsubscribeHandler;
  51 + private final LocationHandler locationHandler;
  52 + private final ScanHandler scanHandler;
  53 + private final DefaultMessageHandler msgHandler;
  54 +
  55 + @Override
  56 + public void init(List<MpAccountDO> list) {
  57 + Map<String, WxMpService> mpServices = Maps.newHashMap();
  58 + Map<String, WxMpMessageRouter> mpMessageRouters = Maps.newHashMap();
  59 + // 处理 list
  60 + list.forEach(account -> {
  61 + // 构建 WxMpService 对象
  62 + WxMpService mpService = buildMpService(account);
  63 + mpServices.put(account.getAppId(), mpService);
  64 + // 构建 WxMpMessageRouter 对象
  65 + WxMpMessageRouter mpMessageRouter = buildMpMessageRouter(mpService);
  66 + mpMessageRouters.put(account.getAppId(), mpMessageRouter);
  67 + });
  68 +
  69 + // 设置到缓存
  70 + this.mpServices = mpServices;
  71 + this.mpMessageRouters = mpMessageRouters;
  72 + }
  73 +
  74 + @Override
  75 + public WxMpService getMpService(String appId) {
  76 + return mpServices.get(appId);
  77 + }
  78 +
  79 + @Override
  80 + public WxMpMessageRouter getMpMessageRouter(String appId) {
  81 + return mpMessageRouters.get(appId);
  82 + }
  83 +
  84 + private WxMpService buildMpService(MpAccountDO account) {
  85 + // 第一步,创建 WxMpRedisConfigImpl 对象
  86 + // TODO 芋艿:需要确认下,redis key 的存储结构
  87 + WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl(
  88 + redisTemplateWxRedisOps, mpProperties.getConfigStorage().getKeyPrefix());
  89 + configStorage.setAppId(account.getAppId());
  90 + configStorage.setSecret(account.getAppSecret());
  91 + configStorage.setToken(account.getToken());
  92 + configStorage.setAesKey(account.getAesKey());
  93 +
  94 + // 第二步,创建 WxMpService 对象
  95 + WxMpService service = new WxMpServiceImpl();
  96 + service.setWxMpConfigStorage(configStorage);
  97 + return null;
  98 + }
  99 +
  100 + private WxMpMessageRouter buildMpMessageRouter(WxMpService mpService) {
  101 + final WxMpMessageRouter newRouter = new WxMpMessageRouter(mpService);
  102 + // 记录所有事件的日志(异步执行)
  103 + newRouter.rule().handler(logHandler).next();
  104 +
  105 + // 接收客服会话管理事件
  106 + newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  107 + .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION)
  108 + .handler(kfSessionHandler).end();
  109 + newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  110 + .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION)
  111 + .handler(kfSessionHandler)
  112 + .end();
  113 + newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  114 + .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION)
  115 + .handler(kfSessionHandler).end();
  116 +
  117 + // 门店审核事件
  118 + newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  119 + .event(WxMpEventConstants.POI_CHECK_NOTIFY)
  120 + .handler(storeCheckNotifyHandler).end();
  121 +
  122 + // 自定义菜单事件
  123 + newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  124 + .event(WxConsts.MenuButtonType.CLICK).handler(menuHandler).end();
  125 +
  126 + // 点击菜单连接事件
  127 + newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  128 + .event(WxConsts.MenuButtonType.VIEW).handler(nullHandler).end();
  129 +
  130 + // 关注事件
  131 + newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  132 + .event(WxConsts.EventType.SUBSCRIBE).handler(subscribeHandler)
  133 + .end();
  134 +
  135 + // 取消关注事件
  136 + newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  137 + .event(WxConsts.EventType.UNSUBSCRIBE)
  138 + .handler(unsubscribeHandler).end();
  139 +
  140 + // 上报地理位置事件
  141 + newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  142 + .event(WxConsts.EventType.LOCATION).handler(locationHandler)
  143 + .end();
  144 +
  145 + // 接收地理位置消息
  146 + newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION)
  147 + .handler(locationHandler).end();
  148 +
  149 + // 扫码事件
  150 + newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  151 + .event(WxConsts.EventType.SCAN).handler(scanHandler).end();
  152 +
  153 + // 默认
  154 + newRouter.rule().async(false).handler(msgHandler).end();
  155 + return newRouter;
  156 + }
  157 +
  158 +}
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mp.framework.mp.core;
  2 +
  3 +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
  4 +import me.chanjar.weixin.mp.api.WxMpMessageRouter;
  5 +import me.chanjar.weixin.mp.api.WxMpService;
  6 +
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * {@link WxMpService} 工厂接口
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +public interface MpServiceFactory {
  15 +
  16 + /**
  17 + * 基于微信公众号的账号,初始化对应的 WxMpService 与 WxMpMessageRouter 实例
  18 + *
  19 + * @param list 公众号的账号列表
  20 + */
  21 + void init(List<MpAccountDO> list);
  22 +
  23 + /**
  24 + * 获得 appId 对应的 WxMpService 实例
  25 + *
  26 + * @param appId 微信公众号 appId
  27 + * @return WxMpService 实例
  28 + */
  29 + WxMpService getMpService(String appId);
  30 +
  31 + /**
  32 + * 获得 appId 对应的 WxMpMessageRouter 实例
  33 + *
  34 + * @param appId 微信公众号 appId
  35 + * @return WxMpMessageRouter 实例
  36 + */
  37 + WxMpMessageRouter getMpMessageRouter(String appId);
  38 +}
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/package-info.java
1 1 /**
2   - * @date 2022/6/20
3   - * @author feng-dan
4   - * @version 1.0
  2 + * 属于 mp 模块的 framework 封装
  3 + *
  4 + * @author 芋道源码
5 5 */
6   -package cn.iocoder.yudao.module.mp.framework;
7 6 \ No newline at end of file
  7 +package cn.iocoder.yudao.module.mp.framework;
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/weixin/WxMpMessageRouterConfiguration.java deleted
1   -package cn.iocoder.yudao.module.mp.framework.weixin;
2   -
3   -
4   -import cn.iocoder.yudao.module.mp.handler.*;
5   -import lombok.RequiredArgsConstructor;
6   -import lombok.extern.slf4j.Slf4j;
7   -import me.chanjar.weixin.common.api.WxConsts;
8   -import me.chanjar.weixin.mp.api.WxMpMessageRouter;
9   -import me.chanjar.weixin.mp.api.WxMpService;
10   -import me.chanjar.weixin.mp.constant.WxMpEventConstants;
11   -import org.springframework.context.annotation.Bean;
12   -import org.springframework.stereotype.Component;
13   -
14   -import javax.annotation.Resource;
15   -
16   -/**
17   - * @author fengdan
18   - */
19   -@Slf4j
20   -@Component
21   -@RequiredArgsConstructor
22   -public class WxMpMessageRouterConfiguration {
23   -
24   - @Resource
25   - private WxMpService wxMpService;
26   - @Resource
27   - private LogHandler logHandler;
28   - @Resource
29   - private KfSessionHandler kfSessionHandler;
30   - @Resource
31   - private StoreCheckNotifyHandler storeCheckNotifyHandler;
32   - @Resource
33   - private MenuHandler menuHandler;
34   - @Resource
35   - private NullHandler nullHandler;
36   - @Resource
37   - private SubscribeHandler subscribeHandler;
38   - @Resource
39   - private UnsubscribeHandler unsubscribeHandler;
40   - @Resource
41   - private LocationHandler locationHandler;
42   - @Resource
43   - private ScanHandler scanHandler;
44   - @Resource
45   - private MsgHandler msgHandler;
46   -
47   - @Bean
48   - public WxMpMessageRouter messageRouter() {
49   - final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);
50   - // 记录所有事件的日志 (异步执行)
51   - newRouter.rule().handler(logHandler).next();
52   -
53   - // 接收客服会话管理事件
54   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
55   - .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION)
56   - .handler(kfSessionHandler).end();
57   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
58   - .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION)
59   - .handler(kfSessionHandler)
60   - .end();
61   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
62   - .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION)
63   - .handler(kfSessionHandler).end();
64   -
65   - // 门店审核事件
66   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
67   - .event(WxMpEventConstants.POI_CHECK_NOTIFY)
68   - .handler(storeCheckNotifyHandler).end();
69   -
70   - // 自定义菜单事件
71   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
72   - .event(WxConsts.MenuButtonType.CLICK).handler(menuHandler).end();
73   -
74   - // 点击菜单连接事件
75   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
76   - .event(WxConsts.MenuButtonType.VIEW).handler(nullHandler).end();
77   -
78   - // 关注事件
79   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
80   - .event(WxConsts.EventType.SUBSCRIBE).handler(subscribeHandler)
81   - .end();
82   -
83   - // 取消关注事件
84   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
85   - .event(WxConsts.EventType.UNSUBSCRIBE)
86   - .handler(unsubscribeHandler).end();
87   -
88   - // 上报地理位置事件
89   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
90   - .event(WxConsts.EventType.LOCATION).handler(locationHandler)
91   - .end();
92   -
93   - // 接收地理位置消息
94   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION)
95   - .handler(locationHandler).end();
96   -
97   - // 扫码事件
98   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
99   - .event(WxConsts.EventType.SCAN).handler(scanHandler).end();
100   -
101   - // 默认
102   - newRouter.rule().async(false).handler(msgHandler).end();
103   -
104   - return newRouter;
105   - }
106   -}
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/WxConfigDataRefreshConsumer.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/MpConfigRefreshConsumer.java
1 1 package cn.iocoder.yudao.module.mp.mq.costomer;
2 2  
3 3 import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
4   -import cn.iocoder.yudao.module.mp.mq.message.WxConfigDataRefreshMessage;
5   -import cn.iocoder.yudao.module.mp.service.account.WxAccountService;
  4 +import cn.iocoder.yudao.module.mp.mq.message.MpConfigRefreshMessage;
  5 +import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
6 6 import lombok.extern.slf4j.Slf4j;
7 7 import org.springframework.stereotype.Component;
8 8  
9 9 import javax.annotation.Resource;
10 10  
11 11 /**
12   - * 针对 {@link WxConfigDataRefreshMessage} 的消费者
  12 + * 针对 {@link MpConfigRefreshMessage} 的消费者
13 13 *
14 14 * @author lyz
15 15 */
16 16 @Component
17 17 @Slf4j
18   -public class WxConfigDataRefreshConsumer extends AbstractChannelMessageListener<WxConfigDataRefreshMessage> {
  18 +public class MpConfigRefreshConsumer extends AbstractChannelMessageListener<MpConfigRefreshMessage> {
19 19  
20 20 @Resource
21   - private WxAccountService wxAccountService;
  21 + private MpAccountService wxAccountService;
22 22  
23 23 @Override
24   - public void onMessage(WxConfigDataRefreshMessage message) {
25   - log.info("[onMessage][收到 WxConfigData 刷新消息]");
26   - wxAccountService.initLoadWxMpConfigStorages();
  24 + public void onMessage(MpConfigRefreshMessage message) {
  25 + log.info("[onMessage][收到 MpConfig 刷新消息]");
  26 + wxAccountService.initLocalCache();
27 27 }
28 28  
29 29 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/WxConfigDataRefreshMessage.java renamed to 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;
9 9 */
10 10 @Data
11 11 @EqualsAndHashCode(callSuper = true)
12   -public class WxConfigDataRefreshMessage extends AbstractChannelMessage {
  12 +public class MpConfigRefreshMessage extends AbstractChannelMessage {
13 13  
14 14 @Override
15 15 public String getChannel() {
16   - return "wechat-mp.wx-config-data.refresh";
  16 + return "mp.config-data.refresh";
17 17 }
18 18  
19 19 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/WxMpConfigDataProducer.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/MpConfigProducer.java
1 1 package cn.iocoder.yudao.module.mp.mq.producer;
2 2  
3 3 import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
4   -import cn.iocoder.yudao.module.mp.mq.message.WxConfigDataRefreshMessage;
  4 +import cn.iocoder.yudao.module.mp.mq.message.MpConfigRefreshMessage;
5 5 import org.springframework.stereotype.Component;
6 6  
7 7 import javax.annotation.Resource;
... ... @@ -10,16 +10,16 @@ import javax.annotation.Resource;
10 10 * 微信配置数据相关消息的 Producer
11 11 */
12 12 @Component
13   -public class WxMpConfigDataProducer {
  13 +public class MpConfigProducer {
14 14  
15 15 @Resource
16 16 private RedisMQTemplate redisMQTemplate;
17 17  
18 18 /**
19   - * 发送 {@link WxConfigDataRefreshMessage} 消息
  19 + * 发送 {@link MpConfigRefreshMessage} 消息
20 20 */
21 21 public void sendDictDataRefreshMessage() {
22   - WxConfigDataRefreshMessage message = new WxConfigDataRefreshMessage();
  22 + MpConfigRefreshMessage message = new MpConfigRefreshMessage();
23 23 redisMQTemplate.send(message);
24 24 }
25 25  
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountService.java renamed to 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;
14 14 *
15 15 * @author 芋道源码
16 16 */
17   -public interface WxAccountService {
  17 +public interface MpAccountService {
  18 +
  19 + /**
  20 + * 初始化缓存
  21 + */
  22 + void initLocalCache();
18 23  
19 24 /**
20 25 * 创建公众号账户
... ... @@ -64,8 +69,4 @@ public interface WxAccountService {
64 69 */
65 70 MpAccountDO findBy(SFunction<MpAccountDO, ?> field, Object val);
66 71  
67   - /**
68   - * 初始化
69   - */
70   - void initLoadWxMpConfigStorages();
71 72 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountServiceImpl.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java
... ... @@ -2,7 +2,8 @@ package cn.iocoder.yudao.module.mp.service.account;
2 2  
3 3 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  6 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
6 7 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO;
7 8 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO;
8 9 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountUpdateReqVO;
... ... @@ -10,25 +11,20 @@ import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert;
10 11 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
11 12 import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper;
12 13 import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants;
13   -import cn.iocoder.yudao.module.mp.mq.producer.WxMpConfigDataProducer;
  14 +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
  15 +import cn.iocoder.yudao.module.mp.mq.producer.MpConfigProducer;
14 16 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
15   -import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
  17 +import lombok.Getter;
16 18 import lombok.extern.slf4j.Slf4j;
17   -import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
18   -import me.chanjar.weixin.mp.api.WxMpService;
19   -import me.chanjar.weixin.mp.config.WxMpConfigStorage;
20 19 import org.springframework.context.annotation.Lazy;
21   -import org.springframework.data.redis.core.StringRedisTemplate;
22 20 import org.springframework.scheduling.annotation.Scheduled;
23 21 import org.springframework.stereotype.Service;
24   -import org.springframework.util.CollectionUtils;
25 22 import org.springframework.validation.annotation.Validated;
26 23  
27 24 import javax.annotation.PostConstruct;
28 25 import javax.annotation.Resource;
29   -import java.util.HashMap;
  26 +import java.time.LocalDateTime;
30 27 import java.util.List;
31   -import java.util.Map;
32 28  
33 29  
34 30 /**
... ... @@ -39,33 +35,78 @@ import java.util.Map;
39 35 @Slf4j
40 36 @Service
41 37 @Validated
42   -public class WxAccountServiceImpl implements WxAccountService {
  38 +public class MpAccountServiceImpl implements MpAccountService {
43 39  
  40 + /**
  41 + * 定时执行 {@link #schedulePeriodicRefresh()} 的周期
  42 + * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高
  43 + */
44 44 private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
45 45  
  46 + /**
  47 + * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新
  48 + */
  49 + @Getter
  50 + private volatile LocalDateTime maxUpdateTime;
  51 +
46 52 @Resource
47   - private MpAccountMapper wxAccountMapper;
48   - @Resource
49   - private WxMpConfigDataProducer wxMpConfigDataProducer;
50   - @Resource
51   - private StringRedisTemplate stringRedisTemplate;
52   - @Resource
53   - private WxMpService wxMpService;
  53 + private MpAccountMapper mpAccountMapper;
  54 +
54 55 @Resource
55   - private WxMpProperties wxMpProperties;
  56 + @Lazy // 延迟加载,解决循环依赖的问题
  57 + private MpServiceFactory mpServiceFactory;
  58 +
56 59 @Resource
57   - @Lazy // 注入自己,所以延迟加载
58   - private WxAccountService self;
  60 + private MpConfigProducer mpConfigDataProducer;
  61 +
  62 + @Override
  63 + @PostConstruct
  64 + public void initLocalCache() {
  65 + initLocalCacheIfUpdate(null);
  66 + }
  67 +
  68 + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
  69 + public void schedulePeriodicRefresh() {
  70 + initLocalCacheIfUpdate(this.maxUpdateTime);
  71 + }
  72 +
  73 + /**
  74 + * 刷新本地缓存
  75 + *
  76 + * @param maxUpdateTime 最大更新时间
  77 + * 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
  78 + * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
  79 + */
  80 + private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
  81 + // 注意:忽略自动多租户,因为要全局初始化缓存
  82 + TenantUtils.executeIgnore(() -> {
  83 + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。
  84 + // 如果没有增量的数据变化,则不进行本地缓存的刷新
  85 + if (maxUpdateTime != null
  86 + && mpAccountMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
  87 + log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
  88 + return;
  89 + }
  90 + List<MpAccountDO> accounts = mpAccountMapper.selectList();
  91 + log.info("[initLocalCacheIfUpdate][缓存公众号账号,数量为:{}]", accounts.size());
  92 +
  93 + // 第二步:构建缓存。创建或更新支付 Client
  94 + mpServiceFactory.init(accounts);
  95 +
  96 + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
  97 + this.maxUpdateTime = CollectionUtils.getMaxValue(accounts, MpAccountDO::getUpdateTime);
  98 + });
  99 + }
59 100  
60 101 @Override
61 102 public Long createAccount(MpAccountCreateReqVO createReqVO) {
62 103 // TODO 芋艿:校验唯一性
63 104 // 插入
64 105 MpAccountDO wxAccount = MpAccountConvert.INSTANCE.convert(createReqVO);
65   - wxAccountMapper.insert(wxAccount);
  106 + mpAccountMapper.insert(wxAccount);
66 107  
67 108 // TODO 芋艿:刷新的方式
68   - wxMpConfigDataProducer.sendDictDataRefreshMessage();
  109 + mpConfigDataProducer.sendDictDataRefreshMessage();
69 110 // 返回
70 111 return wxAccount.getId();
71 112 }
... ... @@ -77,10 +118,10 @@ public class WxAccountServiceImpl implements WxAccountService {
77 118 validateWxAccountExists(updateReqVO.getId());
78 119 // 更新
79 120 MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO);
80   - wxAccountMapper.updateById(updateObj);
  121 + mpAccountMapper.updateById(updateObj);
81 122  
82 123 // TODO 芋艿:刷新的方式
83   - wxMpConfigDataProducer.sendDictDataRefreshMessage();
  124 + mpConfigDataProducer.sendDictDataRefreshMessage();
84 125 }
85 126  
86 127 @Override
... ... @@ -88,70 +129,31 @@ public class WxAccountServiceImpl implements WxAccountService {
88 129 // 校验存在
89 130 validateWxAccountExists(id);
90 131 // 删除
91   - wxAccountMapper.deleteById(id);
  132 + mpAccountMapper.deleteById(id);
92 133  
93 134 // TODO 芋艿:刷新的方式
94   - wxMpConfigDataProducer.sendDictDataRefreshMessage();
  135 + mpConfigDataProducer.sendDictDataRefreshMessage();
95 136 }
96 137  
97 138 private void validateWxAccountExists(Long id) {
98   - if (wxAccountMapper.selectById(id) == null) {
  139 + if (mpAccountMapper.selectById(id) == null) {
99 140 throw ServiceExceptionUtil.exception(ErrorCodeConstants.WX_ACCOUNT_NOT_EXISTS);
100 141 }
101 142 }
102 143  
103 144 @Override
104 145 public MpAccountDO getAccount(Long id) {
105   - return wxAccountMapper.selectById(id);
  146 + return mpAccountMapper.selectById(id);
106 147 }
107 148  
108 149 @Override
109 150 public PageResult<MpAccountDO> getAccountPage(MpAccountPageReqVO pageReqVO) {
110   - return wxAccountMapper.selectPage(pageReqVO);
  151 + return mpAccountMapper.selectPage(pageReqVO);
111 152 }
112 153  
113 154 @Override
114 155 public MpAccountDO findBy(SFunction<MpAccountDO, ?> field, Object val) {
115   - return wxAccountMapper.selectOne(field, val);
116   - }
117   -
118   - @PostConstruct
119   - @TenantIgnore
120   - @Override
121   - public void initLoadWxMpConfigStorages() {
122   - // TODO 芋艿:刷新的方式
123   - List<MpAccountDO> wxAccountList = this.wxAccountMapper.selectList();
124   - if (CollectionUtils.isEmpty(wxAccountList)) {
125   - log.info("未读取到公众号配置,请在管理后台添加");
126   - return;
127   - }
128   - log.info("加载到{}条公众号配置", wxAccountList.size());
129   - wxAccountList.forEach(account -> addAccountToRuntime(account, new RedisTemplateWxRedisOps(stringRedisTemplate)));
130   - log.info("公众号配置加载完成");
131   - }
132   -
133   - /**
134   - * 添加账号到当前程序,如首次添加需初始化configStorageMap
135   - *
136   - * @param account 公众号
137   - */
138   - private synchronized void addAccountToRuntime(MpAccountDO account, RedisTemplateWxRedisOps redisOps) {
139   - String appId = account.getAppId();
140   - WxMpConfigStorage wxMpRedisConfig = account.toWxMpConfigStorage(redisOps, wxMpProperties);
141   - try {
142   - wxMpService.addConfigStorage(appId, wxMpRedisConfig);
143   - } catch (NullPointerException e) {
144   - log.info("需初始化configStorageMap...");
145   - Map<String, WxMpConfigStorage> configStorages = new HashMap<>(4);
146   - configStorages.put(appId, wxMpRedisConfig);
147   - wxMpService.setMultiConfigStorages(configStorages, appId);
148   - }
  156 + return mpAccountMapper.selectOne(field, val);
149 157 }
150 158  
151   - @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
152   - public void schedulePeriodicRefresh() {
153   - self.initLoadWxMpConfigStorages();
154   - }
155   -
156   -
157 159 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/NullHandler.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/fansmsgres/NullHandler.java
1   -package cn.iocoder.yudao.module.mp.handler;
  1 +package cn.iocoder.yudao.module.mp.service.fansmsgres;
2 2  
3 3 import me.chanjar.weixin.common.session.WxSessionManager;
4 4 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
... ... @@ -9,13 +9,15 @@ import org.springframework.stereotype.Component;
9 9  
10 10 import java.util.Map;
11 11  
  12 +/**
  13 + * 点击菜单连接的事件处理器
  14 + */
12 15 @Component
13 16 public class NullHandler implements WxMpMessageHandler {
14 17  
15 18 @Override
16   - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
17   - Map<String, Object> context, WxMpService wxMpService,
18   - WxSessionManager sessionManager) {
  19 + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
  20 + WxMpService wxMpService, WxSessionManager sessionManager) {
19 21 return null;
20 22 }
21 23  
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MsgHandler.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/DefaultMessageHandler.java
1   -package cn.iocoder.yudao.module.mp.handler;
  1 +package cn.iocoder.yudao.module.mp.service.handler;
2 2  
3 3 import cn.hutool.core.io.FileUtil;
4 4 import cn.hutool.http.HtmlUtil;
... ... @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.infra.api.file.FileApi;
8 8 import cn.iocoder.yudao.module.mp.builder.TextBuilder;
9 9 import cn.iocoder.yudao.module.mp.controller.admin.fansmsg.vo.WxFansMsgCreateReqVO;
10 10 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
11   -import cn.iocoder.yudao.module.mp.service.account.WxAccountService;
  11 +import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
12 12 import cn.iocoder.yudao.module.mp.service.fansmsg.WxFansMsgService;
13 13 import lombok.extern.slf4j.Slf4j;
14 14 import me.chanjar.weixin.common.api.WxConsts;
... ... @@ -21,6 +21,7 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
21 21 import me.chanjar.weixin.mp.bean.result.WxMpUser;
22 22 import org.apache.commons.lang3.StringUtils;
23 23 import org.springframework.beans.factory.annotation.Autowired;
  24 +import org.springframework.context.annotation.Lazy;
24 25 import org.springframework.stereotype.Component;
25 26  
26 27 import javax.annotation.Resource;
... ... @@ -28,11 +29,18 @@ import java.io.File;
28 29 import java.io.UnsupportedEncodingException;
29 30 import java.util.Map;
30 31  
  32 +/**
  33 + * 默认所有消息的事件处理器
  34 + *
  35 + * // TODO 芋艿:待实现
  36 + */
31 37 @Component
32 38 @Slf4j
33   -public class MsgHandler implements WxMpMessageHandler {
34   - @Autowired
35   - private WxAccountService wxAccountService;
  39 +public class DefaultMessageHandler implements WxMpMessageHandler {
  40 +
  41 + @Resource
  42 + @Lazy // 延迟加载,解决循环依赖的问题
  43 + private MpAccountService mpAccountService;
36 44  
37 45 @Autowired
38 46 private WxFansMsgService wxFansMsgService;
... ... @@ -55,7 +63,7 @@ public class MsgHandler implements WxMpMessageHandler {
55 63 WxMpUser wxmpUser = weixinService.getUserService()
56 64 .userInfo(wxMessage.getFromUser(), null);
57 65 if (wxmpUser != null) {
58   - MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
  66 + MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
59 67 if (wxAccount != null) {
60 68  
61 69 if (wxMessage.getMsgType().equals(WxConsts.XmlMsgType.TEXT)) {
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/KfSessionHandler.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/KfSessionHandler.java
1   -package cn.iocoder.yudao.module.mp.handler;
  1 +package cn.iocoder.yudao.module.mp.service.handler;
2 2  
3 3 import me.chanjar.weixin.common.session.WxSessionManager;
4 4 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
... ... @@ -9,14 +9,18 @@ import org.springframework.stereotype.Component;
9 9  
10 10 import java.util.Map;
11 11  
  12 +/**
  13 + * 接收客服会话管理的事件处理器
  14 + *
  15 + * @author 芋道源码
  16 + */
12 17 @Component
13 18 public class KfSessionHandler implements WxMpMessageHandler {
14 19  
15 20 @Override
16   - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
17   - Map<String, Object> context, WxMpService wxMpService,
18   - WxSessionManager sessionManager) {
19   - //TODO 对会话做处理
  21 + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
  22 + WxMpService wxMpService, WxSessionManager sessionManager) {
  23 + // TODO 对会话做处理
20 24 return null;
21 25 }
22 26  
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LocationHandler.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LocationHandler.java
1   -package cn.iocoder.yudao.module.mp.handler;
  1 +package cn.iocoder.yudao.module.mp.service.handler;
2 2  
3 3 import cn.iocoder.yudao.module.mp.builder.TextBuilder;
4 4 import lombok.extern.slf4j.Slf4j;
... ... @@ -13,14 +13,18 @@ import java.util.Map;
13 13  
14 14 import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
15 15  
  16 +/**
  17 + * 上报地理位置的事件处理器
  18 + *
  19 + * // TODO @芋艿:需要实现一下~
  20 + */
16 21 @Component
17 22 @Slf4j
18 23 public class LocationHandler implements WxMpMessageHandler {
19 24  
20 25 @Override
21   - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
22   - Map<String, Object> context, WxMpService wxMpService,
23   - WxSessionManager sessionManager) {
  26 + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
  27 + WxMpService wxMpService, WxSessionManager sessionManager) {
24 28 if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
25 29 //TODO 接收处理用户发送的地理位置消息
26 30 try {
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LogHandler.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LogHandler.java
1   -package cn.iocoder.yudao.module.mp.handler;
  1 +package cn.iocoder.yudao.module.mp.service.handler;
2 2  
3 3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
4 4 import lombok.extern.slf4j.Slf4j;
... ... @@ -11,13 +11,18 @@ import org.springframework.stereotype.Component;
11 11  
12 12 import java.util.Map;
13 13  
  14 +/**
  15 + * 保存微信消息的事件处理器
  16 + *
  17 + * // TODO 芋艿:实现一下
  18 + */
14 19 @Component
15 20 @Slf4j
16 21 public class LogHandler implements WxMpMessageHandler {
  22 +
17 23 @Override
18   - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
19   - Map<String, Object> context, WxMpService wxMpService,
20   - WxSessionManager sessionManager) {
  24 + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
  25 + WxMpService wxMpService, WxSessionManager sessionManager) {
21 26 log.info("接收到请求消息,内容:{}", JsonUtils.toJsonString(wxMessage));
22 27 return null;
23 28 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MenuHandler.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/MenuHandler.java
1   -package cn.iocoder.yudao.module.mp.handler;
  1 +package cn.iocoder.yudao.module.mp.service.handler;
2 2  
3 3 import me.chanjar.weixin.common.session.WxSessionManager;
4 4 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
... ... @@ -11,6 +11,11 @@ import java.util.Map;
11 11  
12 12 import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
13 13  
  14 +/**
  15 + * 自定义菜单的事件处理器
  16 + *
  17 + * // TODO 芋艿:待实现
  18 + */
14 19 @Component
15 20 public class MenuHandler implements WxMpMessageHandler {
16 21  
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/ScanHandler.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/ScanHandler.java
1   -package cn.iocoder.yudao.module.mp.handler;
  1 +package cn.iocoder.yudao.module.mp.service.handler;
2 2  
3 3 import me.chanjar.weixin.common.error.WxErrorException;
4 4 import me.chanjar.weixin.common.session.WxSessionManager;
... ... @@ -10,6 +10,9 @@ import org.springframework.stereotype.Component;
10 10  
11 11 import java.util.Map;
12 12  
  13 +/**
  14 + * 扫码的事件处理器
  15 + */
13 16 @Component
14 17 public class ScanHandler implements WxMpMessageHandler {
15 18  
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/StoreCheckNotifyHandler.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/StoreCheckNotifyHandler.java
1   -package cn.iocoder.yudao.module.mp.handler;
  1 +package cn.iocoder.yudao.module.mp.service.handler;
2 2  
3 3 import me.chanjar.weixin.common.session.WxSessionManager;
4 4 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
... ... @@ -10,8 +10,7 @@ import org.springframework.stereotype.Component;
10 10 import java.util.Map;
11 11  
12 12 /**
13   - * 门店审核事件处理
14   - *
  13 + * 门店审核事件的事件处理器
15 14 */
16 15 @Component
17 16 public class StoreCheckNotifyHandler implements WxMpMessageHandler {
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/SubscribeHandler.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/SubscribeHandler.java
1   -package cn.iocoder.yudao.module.mp.handler;
  1 +package cn.iocoder.yudao.module.mp.service.handler;
2 2  
3 3 import cn.hutool.core.date.DateUtil;
4 4 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
... ... @@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
9 9 import cn.iocoder.yudao.module.mp.dal.dataobject.accountfans.WxAccountFansDO;
10 10 import cn.iocoder.yudao.module.mp.dal.dataobject.subscribetext.WxSubscribeTextDO;
11 11 import cn.iocoder.yudao.module.mp.dal.dataobject.texttemplate.WxTextTemplateDO;
12   -import cn.iocoder.yudao.module.mp.service.account.WxAccountService;
  12 +import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
13 13 import cn.iocoder.yudao.module.mp.service.accountfans.WxAccountFansService;
14 14 import cn.iocoder.yudao.module.mp.service.accountfanstag.WxAccountFansTagService;
15 15 import cn.iocoder.yudao.module.mp.service.subscribetext.WxSubscribeTextService;
... ... @@ -23,11 +23,18 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
23 23 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
24 24 import me.chanjar.weixin.mp.bean.result.WxMpUser;
25 25 import org.springframework.beans.factory.annotation.Autowired;
  26 +import org.springframework.context.annotation.Lazy;
26 27 import org.springframework.stereotype.Component;
27 28  
  29 +import javax.annotation.Resource;
28 30 import java.io.UnsupportedEncodingException;
29 31 import java.util.Map;
30 32  
  33 +/**
  34 + * 关注的事件处理器
  35 + *
  36 + * // TODO 芋艿:待实现
  37 + */
31 38 @Component
32 39 @Slf4j
33 40 public class SubscribeHandler implements WxMpMessageHandler {
... ... @@ -35,8 +42,9 @@ public class SubscribeHandler implements WxMpMessageHandler {
35 42 @Autowired
36 43 private WxTextTemplateService wxTextTemplateService;
37 44  
38   - @Autowired
39   - private WxAccountService wxAccountService;
  45 + @Resource
  46 + @Lazy // 延迟加载,解决循环依赖的问题
  47 + private MpAccountService mpAccountService;
40 48  
41 49 @Autowired
42 50 private WxSubscribeTextService wxSubscribeTextService;
... ... @@ -60,7 +68,7 @@ public class SubscribeHandler implements WxMpMessageHandler {
60 68 .userInfo(wxMessage.getFromUser(), null);
61 69 if (wxmpUser != null) {
62 70 // 可以添加关注用户到本地数据库
63   - MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
  71 + MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
64 72 if (wxAccount != null) {
65 73 WxAccountFansDO wxAccountFans = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, wxmpUser.getOpenId());
66 74 if (wxAccountFans == null) {//insert
... ... @@ -128,7 +136,7 @@ public class SubscribeHandler implements WxMpMessageHandler {
128 136  
129 137 try {
130 138 String content = "感谢关注!";//默认
131   - MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
  139 + MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
132 140 if (wxAccount != null) {
133 141 WxSubscribeTextDO wxSubscribeText = wxSubscribeTextService.findBy(WxSubscribeTextDO::getWxAccountId, String.valueOf(wxAccount.getId()));
134 142 if (wxSubscribeText != null) {
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/UnsubscribeHandler.java renamed to yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/UnsubscribeHandler.java
1   -package cn.iocoder.yudao.module.mp.handler;
  1 +package cn.iocoder.yudao.module.mp.service.handler;
2 2  
3 3 import cn.iocoder.yudao.module.mp.controller.admin.accountfans.vo.WxAccountFansUpdateReqVO;
4 4 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
5 5 import cn.iocoder.yudao.module.mp.dal.dataobject.accountfans.WxAccountFansDO;
6   -import cn.iocoder.yudao.module.mp.service.account.WxAccountService;
  6 +import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
7 7 import cn.iocoder.yudao.module.mp.service.accountfans.WxAccountFansService;
8 8 import lombok.extern.slf4j.Slf4j;
9 9 import me.chanjar.weixin.common.session.WxSessionManager;
... ... @@ -12,16 +12,24 @@ import me.chanjar.weixin.mp.api.WxMpService;
12 12 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
13 13 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
14 14 import org.springframework.beans.factory.annotation.Autowired;
  15 +import org.springframework.context.annotation.Lazy;
15 16 import org.springframework.stereotype.Component;
16 17  
  18 +import javax.annotation.Resource;
17 19 import java.util.Map;
18 20  
  21 +/**
  22 + * 取消关注的事件处理器
  23 + *
  24 + * // TODO 芋艿:待实现
  25 + */
19 26 @Component
20 27 @Slf4j
21 28 public class UnsubscribeHandler implements WxMpMessageHandler {
22 29  
23   - @Autowired
24   - private WxAccountService wxAccountService;
  30 + @Resource
  31 + @Lazy // 延迟加载,解决循环依赖的问题
  32 + private MpAccountService mpAccountService;
25 33  
26 34 @Autowired
27 35 private WxAccountFansService wxAccountFansService;
... ... @@ -34,7 +42,7 @@ public class UnsubscribeHandler implements WxMpMessageHandler {
34 42 log.info("取消关注用户 OPENID: " + openId);
35 43 // TODO 可以更新本地数据库为取消关注状态
36 44  
37   - MpAccountDO wxAccountDO = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
  45 + MpAccountDO wxAccountDO = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
38 46 if (wxAccountDO != null) {
39 47 WxAccountFansDO wxAccountFansDO = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, openId);
40 48 if (wxAccountFansDO != null) {
... ...