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,7 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.*; 5 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.*;
6 import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert; 6 import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert;
7 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; 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 import io.swagger.annotations.Api; 9 import io.swagger.annotations.Api;
10 import io.swagger.annotations.ApiImplicitParam; 10 import io.swagger.annotations.ApiImplicitParam;
11 import io.swagger.annotations.ApiOperation; 11 import io.swagger.annotations.ApiOperation;
@@ -25,7 +25,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -25,7 +25,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
25 public class MpAccountController { 25 public class MpAccountController {
26 26
27 @Resource 27 @Resource
28 - private WxAccountService wxAccountService; 28 + private MpAccountService wxAccountService;
29 29
30 @PostMapping("/create") 30 @PostMapping("/create")
31 @ApiOperation("创建公众号账户") 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,13 +63,4 @@ public class MpAccountDO extends BaseDO {
63 */ 63 */
64 private String remark; 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 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; 6 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO;
7 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; 7 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
  9 +import org.apache.ibatis.annotations.Select;
  10 +
  11 +import java.time.LocalDateTime;
9 12
10 @Mapper 13 @Mapper
11 public interface MpAccountMapper extends BaseMapperX<MpAccountDO> { 14 public interface MpAccountMapper extends BaseMapperX<MpAccountDO> {
@@ -18,4 +21,7 @@ public interface MpAccountMapper extends BaseMapperX&lt;MpAccountDO&gt; { @@ -18,4 +21,7 @@ public interface MpAccountMapper extends BaseMapperX&lt;MpAccountDO&gt; {
18 .orderByDesc(MpAccountDO::getId)); 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 \ No newline at end of file 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 package cn.iocoder.yudao.module.mp.mq.costomer; 1 package cn.iocoder.yudao.module.mp.mq.costomer;
2 2
3 import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; 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 import lombok.extern.slf4j.Slf4j; 6 import lombok.extern.slf4j.Slf4j;
7 import org.springframework.stereotype.Component; 7 import org.springframework.stereotype.Component;
8 8
9 import javax.annotation.Resource; 9 import javax.annotation.Resource;
10 10
11 /** 11 /**
12 - * 针对 {@link WxConfigDataRefreshMessage} 的消费者 12 + * 针对 {@link MpConfigRefreshMessage} 的消费者
13 * 13 *
14 * @author lyz 14 * @author lyz
15 */ 15 */
16 @Component 16 @Component
17 @Slf4j 17 @Slf4j
18 -public class WxConfigDataRefreshConsumer extends AbstractChannelMessageListener<WxConfigDataRefreshMessage> { 18 +public class MpConfigRefreshConsumer extends AbstractChannelMessageListener<MpConfigRefreshMessage> {
19 19
20 @Resource 20 @Resource
21 - private WxAccountService wxAccountService; 21 + private MpAccountService wxAccountService;
22 22
23 @Override 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,11 +9,11 @@ import lombok.EqualsAndHashCode;
9 */ 9 */
10 @Data 10 @Data
11 @EqualsAndHashCode(callSuper = true) 11 @EqualsAndHashCode(callSuper = true)
12 -public class WxConfigDataRefreshMessage extends AbstractChannelMessage { 12 +public class MpConfigRefreshMessage extends AbstractChannelMessage {
13 13
14 @Override 14 @Override
15 public String getChannel() { 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 package cn.iocoder.yudao.module.mp.mq.producer; 1 package cn.iocoder.yudao.module.mp.mq.producer;
2 2
3 import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; 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 import org.springframework.stereotype.Component; 5 import org.springframework.stereotype.Component;
6 6
7 import javax.annotation.Resource; 7 import javax.annotation.Resource;
@@ -10,16 +10,16 @@ import javax.annotation.Resource; @@ -10,16 +10,16 @@ import javax.annotation.Resource;
10 * 微信配置数据相关消息的 Producer 10 * 微信配置数据相关消息的 Producer
11 */ 11 */
12 @Component 12 @Component
13 -public class WxMpConfigDataProducer { 13 +public class MpConfigProducer {
14 14
15 @Resource 15 @Resource
16 private RedisMQTemplate redisMQTemplate; 16 private RedisMQTemplate redisMQTemplate;
17 17
18 /** 18 /**
19 - * 发送 {@link WxConfigDataRefreshMessage} 消息 19 + * 发送 {@link MpConfigRefreshMessage} 消息
20 */ 20 */
21 public void sendDictDataRefreshMessage() { 21 public void sendDictDataRefreshMessage() {
22 - WxConfigDataRefreshMessage message = new WxConfigDataRefreshMessage(); 22 + MpConfigRefreshMessage message = new MpConfigRefreshMessage();
23 redisMQTemplate.send(message); 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,7 +14,12 @@ import javax.validation.Valid;
14 * 14 *
15 * @author 芋道源码 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,8 +69,4 @@ public interface WxAccountService {
64 */ 69 */
65 MpAccountDO findBy(SFunction<MpAccountDO, ?> field, Object val); 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,7 +2,8 @@ package cn.iocoder.yudao.module.mp.service.account;
2 2
3 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; 3 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 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 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO; 7 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO;
7 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; 8 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO;
8 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountUpdateReqVO; 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,25 +11,20 @@ import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert;
10 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; 11 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
11 import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper; 12 import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper;
12 import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants; 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 import com.baomidou.mybatisplus.core.toolkit.support.SFunction; 16 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
15 -import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; 17 +import lombok.Getter;
16 import lombok.extern.slf4j.Slf4j; 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 import org.springframework.context.annotation.Lazy; 19 import org.springframework.context.annotation.Lazy;
21 -import org.springframework.data.redis.core.StringRedisTemplate;  
22 import org.springframework.scheduling.annotation.Scheduled; 20 import org.springframework.scheduling.annotation.Scheduled;
23 import org.springframework.stereotype.Service; 21 import org.springframework.stereotype.Service;
24 -import org.springframework.util.CollectionUtils;  
25 import org.springframework.validation.annotation.Validated; 22 import org.springframework.validation.annotation.Validated;
26 23
27 import javax.annotation.PostConstruct; 24 import javax.annotation.PostConstruct;
28 import javax.annotation.Resource; 25 import javax.annotation.Resource;
29 -import java.util.HashMap; 26 +import java.time.LocalDateTime;
30 import java.util.List; 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,33 +35,78 @@ import java.util.Map;
39 @Slf4j 35 @Slf4j
40 @Service 36 @Service
41 @Validated 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 private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; 44 private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
45 45
  46 + /**
  47 + * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新
  48 + */
  49 + @Getter
  50 + private volatile LocalDateTime maxUpdateTime;
  51 +
46 @Resource 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 @Resource 55 @Resource
55 - private WxMpProperties wxMpProperties; 56 + @Lazy // 延迟加载,解决循环依赖的问题
  57 + private MpServiceFactory mpServiceFactory;
  58 +
56 @Resource 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 @Override 101 @Override
61 public Long createAccount(MpAccountCreateReqVO createReqVO) { 102 public Long createAccount(MpAccountCreateReqVO createReqVO) {
62 // TODO 芋艿:校验唯一性 103 // TODO 芋艿:校验唯一性
63 // 插入 104 // 插入
64 MpAccountDO wxAccount = MpAccountConvert.INSTANCE.convert(createReqVO); 105 MpAccountDO wxAccount = MpAccountConvert.INSTANCE.convert(createReqVO);
65 - wxAccountMapper.insert(wxAccount); 106 + mpAccountMapper.insert(wxAccount);
66 107
67 // TODO 芋艿:刷新的方式 108 // TODO 芋艿:刷新的方式
68 - wxMpConfigDataProducer.sendDictDataRefreshMessage(); 109 + mpConfigDataProducer.sendDictDataRefreshMessage();
69 // 返回 110 // 返回
70 return wxAccount.getId(); 111 return wxAccount.getId();
71 } 112 }
@@ -77,10 +118,10 @@ public class WxAccountServiceImpl implements WxAccountService { @@ -77,10 +118,10 @@ public class WxAccountServiceImpl implements WxAccountService {
77 validateWxAccountExists(updateReqVO.getId()); 118 validateWxAccountExists(updateReqVO.getId());
78 // 更新 119 // 更新
79 MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO); 120 MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO);
80 - wxAccountMapper.updateById(updateObj); 121 + mpAccountMapper.updateById(updateObj);
81 122
82 // TODO 芋艿:刷新的方式 123 // TODO 芋艿:刷新的方式
83 - wxMpConfigDataProducer.sendDictDataRefreshMessage(); 124 + mpConfigDataProducer.sendDictDataRefreshMessage();
84 } 125 }
85 126
86 @Override 127 @Override
@@ -88,70 +129,31 @@ public class WxAccountServiceImpl implements WxAccountService { @@ -88,70 +129,31 @@ public class WxAccountServiceImpl implements WxAccountService {
88 // 校验存在 129 // 校验存在
89 validateWxAccountExists(id); 130 validateWxAccountExists(id);
90 // 删除 131 // 删除
91 - wxAccountMapper.deleteById(id); 132 + mpAccountMapper.deleteById(id);
92 133
93 // TODO 芋艿:刷新的方式 134 // TODO 芋艿:刷新的方式
94 - wxMpConfigDataProducer.sendDictDataRefreshMessage(); 135 + mpConfigDataProducer.sendDictDataRefreshMessage();
95 } 136 }
96 137
97 private void validateWxAccountExists(Long id) { 138 private void validateWxAccountExists(Long id) {
98 - if (wxAccountMapper.selectById(id) == null) { 139 + if (mpAccountMapper.selectById(id) == null) {
99 throw ServiceExceptionUtil.exception(ErrorCodeConstants.WX_ACCOUNT_NOT_EXISTS); 140 throw ServiceExceptionUtil.exception(ErrorCodeConstants.WX_ACCOUNT_NOT_EXISTS);
100 } 141 }
101 } 142 }
102 143
103 @Override 144 @Override
104 public MpAccountDO getAccount(Long id) { 145 public MpAccountDO getAccount(Long id) {
105 - return wxAccountMapper.selectById(id); 146 + return mpAccountMapper.selectById(id);
106 } 147 }
107 148
108 @Override 149 @Override
109 public PageResult<MpAccountDO> getAccountPage(MpAccountPageReqVO pageReqVO) { 150 public PageResult<MpAccountDO> getAccountPage(MpAccountPageReqVO pageReqVO) {
110 - return wxAccountMapper.selectPage(pageReqVO); 151 + return mpAccountMapper.selectPage(pageReqVO);
111 } 152 }
112 153
113 @Override 154 @Override
114 public MpAccountDO findBy(SFunction<MpAccountDO, ?> field, Object val) { 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 import me.chanjar.weixin.common.session.WxSessionManager; 3 import me.chanjar.weixin.common.session.WxSessionManager;
4 import me.chanjar.weixin.mp.api.WxMpMessageHandler; 4 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
@@ -9,13 +9,15 @@ import org.springframework.stereotype.Component; @@ -9,13 +9,15 @@ import org.springframework.stereotype.Component;
9 9
10 import java.util.Map; 10 import java.util.Map;
11 11
  12 +/**
  13 + * 点击菜单连接的事件处理器
  14 + */
12 @Component 15 @Component
13 public class NullHandler implements WxMpMessageHandler { 16 public class NullHandler implements WxMpMessageHandler {
14 17
15 @Override 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 return null; 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 import cn.hutool.core.io.FileUtil; 3 import cn.hutool.core.io.FileUtil;
4 import cn.hutool.http.HtmlUtil; 4 import cn.hutool.http.HtmlUtil;
@@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.infra.api.file.FileApi; @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.infra.api.file.FileApi;
8 import cn.iocoder.yudao.module.mp.builder.TextBuilder; 8 import cn.iocoder.yudao.module.mp.builder.TextBuilder;
9 import cn.iocoder.yudao.module.mp.controller.admin.fansmsg.vo.WxFansMsgCreateReqVO; 9 import cn.iocoder.yudao.module.mp.controller.admin.fansmsg.vo.WxFansMsgCreateReqVO;
10 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; 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 import cn.iocoder.yudao.module.mp.service.fansmsg.WxFansMsgService; 12 import cn.iocoder.yudao.module.mp.service.fansmsg.WxFansMsgService;
13 import lombok.extern.slf4j.Slf4j; 13 import lombok.extern.slf4j.Slf4j;
14 import me.chanjar.weixin.common.api.WxConsts; 14 import me.chanjar.weixin.common.api.WxConsts;
@@ -21,6 +21,7 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; @@ -21,6 +21,7 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
21 import me.chanjar.weixin.mp.bean.result.WxMpUser; 21 import me.chanjar.weixin.mp.bean.result.WxMpUser;
22 import org.apache.commons.lang3.StringUtils; 22 import org.apache.commons.lang3.StringUtils;
23 import org.springframework.beans.factory.annotation.Autowired; 23 import org.springframework.beans.factory.annotation.Autowired;
  24 +import org.springframework.context.annotation.Lazy;
24 import org.springframework.stereotype.Component; 25 import org.springframework.stereotype.Component;
25 26
26 import javax.annotation.Resource; 27 import javax.annotation.Resource;
@@ -28,11 +29,18 @@ import java.io.File; @@ -28,11 +29,18 @@ import java.io.File;
28 import java.io.UnsupportedEncodingException; 29 import java.io.UnsupportedEncodingException;
29 import java.util.Map; 30 import java.util.Map;
30 31
  32 +/**
  33 + * 默认所有消息的事件处理器
  34 + *
  35 + * // TODO 芋艿:待实现
  36 + */
31 @Component 37 @Component
32 @Slf4j 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 @Autowired 45 @Autowired
38 private WxFansMsgService wxFansMsgService; 46 private WxFansMsgService wxFansMsgService;
@@ -55,7 +63,7 @@ public class MsgHandler implements WxMpMessageHandler { @@ -55,7 +63,7 @@ public class MsgHandler implements WxMpMessageHandler {
55 WxMpUser wxmpUser = weixinService.getUserService() 63 WxMpUser wxmpUser = weixinService.getUserService()
56 .userInfo(wxMessage.getFromUser(), null); 64 .userInfo(wxMessage.getFromUser(), null);
57 if (wxmpUser != null) { 65 if (wxmpUser != null) {
58 - MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser()); 66 + MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
59 if (wxAccount != null) { 67 if (wxAccount != null) {
60 68
61 if (wxMessage.getMsgType().equals(WxConsts.XmlMsgType.TEXT)) { 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 import me.chanjar.weixin.common.session.WxSessionManager; 3 import me.chanjar.weixin.common.session.WxSessionManager;
4 import me.chanjar.weixin.mp.api.WxMpMessageHandler; 4 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
@@ -9,14 +9,18 @@ import org.springframework.stereotype.Component; @@ -9,14 +9,18 @@ import org.springframework.stereotype.Component;
9 9
10 import java.util.Map; 10 import java.util.Map;
11 11
  12 +/**
  13 + * 接收客服会话管理的事件处理器
  14 + *
  15 + * @author 芋道源码
  16 + */
12 @Component 17 @Component
13 public class KfSessionHandler implements WxMpMessageHandler { 18 public class KfSessionHandler implements WxMpMessageHandler {
14 19
15 @Override 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 return null; 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 import cn.iocoder.yudao.module.mp.builder.TextBuilder; 3 import cn.iocoder.yudao.module.mp.builder.TextBuilder;
4 import lombok.extern.slf4j.Slf4j; 4 import lombok.extern.slf4j.Slf4j;
@@ -13,14 +13,18 @@ import java.util.Map; @@ -13,14 +13,18 @@ import java.util.Map;
13 13
14 import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType; 14 import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
15 15
  16 +/**
  17 + * 上报地理位置的事件处理器
  18 + *
  19 + * // TODO @芋艿:需要实现一下~
  20 + */
16 @Component 21 @Component
17 @Slf4j 22 @Slf4j
18 public class LocationHandler implements WxMpMessageHandler { 23 public class LocationHandler implements WxMpMessageHandler {
19 24
20 @Override 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 if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) { 28 if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
25 //TODO 接收处理用户发送的地理位置消息 29 //TODO 接收处理用户发送的地理位置消息
26 try { 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 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
4 import lombok.extern.slf4j.Slf4j; 4 import lombok.extern.slf4j.Slf4j;
@@ -11,13 +11,18 @@ import org.springframework.stereotype.Component; @@ -11,13 +11,18 @@ import org.springframework.stereotype.Component;
11 11
12 import java.util.Map; 12 import java.util.Map;
13 13
  14 +/**
  15 + * 保存微信消息的事件处理器
  16 + *
  17 + * // TODO 芋艿:实现一下
  18 + */
14 @Component 19 @Component
15 @Slf4j 20 @Slf4j
16 public class LogHandler implements WxMpMessageHandler { 21 public class LogHandler implements WxMpMessageHandler {
  22 +
17 @Override 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 log.info("接收到请求消息,内容:{}", JsonUtils.toJsonString(wxMessage)); 26 log.info("接收到请求消息,内容:{}", JsonUtils.toJsonString(wxMessage));
22 return null; 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 import me.chanjar.weixin.common.session.WxSessionManager; 3 import me.chanjar.weixin.common.session.WxSessionManager;
4 import me.chanjar.weixin.mp.api.WxMpMessageHandler; 4 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
@@ -11,6 +11,11 @@ import java.util.Map; @@ -11,6 +11,11 @@ import java.util.Map;
11 11
12 import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType; 12 import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
13 13
  14 +/**
  15 + * 自定义菜单的事件处理器
  16 + *
  17 + * // TODO 芋艿:待实现
  18 + */
14 @Component 19 @Component
15 public class MenuHandler implements WxMpMessageHandler { 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 import me.chanjar.weixin.common.error.WxErrorException; 3 import me.chanjar.weixin.common.error.WxErrorException;
4 import me.chanjar.weixin.common.session.WxSessionManager; 4 import me.chanjar.weixin.common.session.WxSessionManager;
@@ -10,6 +10,9 @@ import org.springframework.stereotype.Component; @@ -10,6 +10,9 @@ import org.springframework.stereotype.Component;
10 10
11 import java.util.Map; 11 import java.util.Map;
12 12
  13 +/**
  14 + * 扫码的事件处理器
  15 + */
13 @Component 16 @Component
14 public class ScanHandler implements WxMpMessageHandler { 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 import me.chanjar.weixin.common.session.WxSessionManager; 3 import me.chanjar.weixin.common.session.WxSessionManager;
4 import me.chanjar.weixin.mp.api.WxMpMessageHandler; 4 import me.chanjar.weixin.mp.api.WxMpMessageHandler;
@@ -10,8 +10,7 @@ import org.springframework.stereotype.Component; @@ -10,8 +10,7 @@ import org.springframework.stereotype.Component;
10 import java.util.Map; 10 import java.util.Map;
11 11
12 /** 12 /**
13 - * 门店审核事件处理  
14 - * 13 + * 门店审核事件的事件处理器
15 */ 14 */
16 @Component 15 @Component
17 public class StoreCheckNotifyHandler implements WxMpMessageHandler { 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 import cn.hutool.core.date.DateUtil; 3 import cn.hutool.core.date.DateUtil;
4 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 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,7 +9,7 @@ import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
9 import cn.iocoder.yudao.module.mp.dal.dataobject.accountfans.WxAccountFansDO; 9 import cn.iocoder.yudao.module.mp.dal.dataobject.accountfans.WxAccountFansDO;
10 import cn.iocoder.yudao.module.mp.dal.dataobject.subscribetext.WxSubscribeTextDO; 10 import cn.iocoder.yudao.module.mp.dal.dataobject.subscribetext.WxSubscribeTextDO;
11 import cn.iocoder.yudao.module.mp.dal.dataobject.texttemplate.WxTextTemplateDO; 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 import cn.iocoder.yudao.module.mp.service.accountfans.WxAccountFansService; 13 import cn.iocoder.yudao.module.mp.service.accountfans.WxAccountFansService;
14 import cn.iocoder.yudao.module.mp.service.accountfanstag.WxAccountFansTagService; 14 import cn.iocoder.yudao.module.mp.service.accountfanstag.WxAccountFansTagService;
15 import cn.iocoder.yudao.module.mp.service.subscribetext.WxSubscribeTextService; 15 import cn.iocoder.yudao.module.mp.service.subscribetext.WxSubscribeTextService;
@@ -23,11 +23,18 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; @@ -23,11 +23,18 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
23 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; 23 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
24 import me.chanjar.weixin.mp.bean.result.WxMpUser; 24 import me.chanjar.weixin.mp.bean.result.WxMpUser;
25 import org.springframework.beans.factory.annotation.Autowired; 25 import org.springframework.beans.factory.annotation.Autowired;
  26 +import org.springframework.context.annotation.Lazy;
26 import org.springframework.stereotype.Component; 27 import org.springframework.stereotype.Component;
27 28
  29 +import javax.annotation.Resource;
28 import java.io.UnsupportedEncodingException; 30 import java.io.UnsupportedEncodingException;
29 import java.util.Map; 31 import java.util.Map;
30 32
  33 +/**
  34 + * 关注的事件处理器
  35 + *
  36 + * // TODO 芋艿:待实现
  37 + */
31 @Component 38 @Component
32 @Slf4j 39 @Slf4j
33 public class SubscribeHandler implements WxMpMessageHandler { 40 public class SubscribeHandler implements WxMpMessageHandler {
@@ -35,8 +42,9 @@ public class SubscribeHandler implements WxMpMessageHandler { @@ -35,8 +42,9 @@ public class SubscribeHandler implements WxMpMessageHandler {
35 @Autowired 42 @Autowired
36 private WxTextTemplateService wxTextTemplateService; 43 private WxTextTemplateService wxTextTemplateService;
37 44
38 - @Autowired  
39 - private WxAccountService wxAccountService; 45 + @Resource
  46 + @Lazy // 延迟加载,解决循环依赖的问题
  47 + private MpAccountService mpAccountService;
40 48
41 @Autowired 49 @Autowired
42 private WxSubscribeTextService wxSubscribeTextService; 50 private WxSubscribeTextService wxSubscribeTextService;
@@ -60,7 +68,7 @@ public class SubscribeHandler implements WxMpMessageHandler { @@ -60,7 +68,7 @@ public class SubscribeHandler implements WxMpMessageHandler {
60 .userInfo(wxMessage.getFromUser(), null); 68 .userInfo(wxMessage.getFromUser(), null);
61 if (wxmpUser != null) { 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 if (wxAccount != null) { 72 if (wxAccount != null) {
65 WxAccountFansDO wxAccountFans = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, wxmpUser.getOpenId()); 73 WxAccountFansDO wxAccountFans = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, wxmpUser.getOpenId());
66 if (wxAccountFans == null) {//insert 74 if (wxAccountFans == null) {//insert
@@ -128,7 +136,7 @@ public class SubscribeHandler implements WxMpMessageHandler { @@ -128,7 +136,7 @@ public class SubscribeHandler implements WxMpMessageHandler {
128 136
129 try { 137 try {
130 String content = "感谢关注!";//默认 138 String content = "感谢关注!";//默认
131 - MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser()); 139 + MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
132 if (wxAccount != null) { 140 if (wxAccount != null) {
133 WxSubscribeTextDO wxSubscribeText = wxSubscribeTextService.findBy(WxSubscribeTextDO::getWxAccountId, String.valueOf(wxAccount.getId())); 141 WxSubscribeTextDO wxSubscribeText = wxSubscribeTextService.findBy(WxSubscribeTextDO::getWxAccountId, String.valueOf(wxAccount.getId()));
134 if (wxSubscribeText != null) { 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 import cn.iocoder.yudao.module.mp.controller.admin.accountfans.vo.WxAccountFansUpdateReqVO; 3 import cn.iocoder.yudao.module.mp.controller.admin.accountfans.vo.WxAccountFansUpdateReqVO;
4 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; 4 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
5 import cn.iocoder.yudao.module.mp.dal.dataobject.accountfans.WxAccountFansDO; 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 import cn.iocoder.yudao.module.mp.service.accountfans.WxAccountFansService; 7 import cn.iocoder.yudao.module.mp.service.accountfans.WxAccountFansService;
8 import lombok.extern.slf4j.Slf4j; 8 import lombok.extern.slf4j.Slf4j;
9 import me.chanjar.weixin.common.session.WxSessionManager; 9 import me.chanjar.weixin.common.session.WxSessionManager;
@@ -12,16 +12,24 @@ import me.chanjar.weixin.mp.api.WxMpService; @@ -12,16 +12,24 @@ import me.chanjar.weixin.mp.api.WxMpService;
12 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; 12 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
13 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; 13 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
14 import org.springframework.beans.factory.annotation.Autowired; 14 import org.springframework.beans.factory.annotation.Autowired;
  15 +import org.springframework.context.annotation.Lazy;
15 import org.springframework.stereotype.Component; 16 import org.springframework.stereotype.Component;
16 17
  18 +import javax.annotation.Resource;
17 import java.util.Map; 19 import java.util.Map;
18 20
  21 +/**
  22 + * 取消关注的事件处理器
  23 + *
  24 + * // TODO 芋艿:待实现
  25 + */
19 @Component 26 @Component
20 @Slf4j 27 @Slf4j
21 public class UnsubscribeHandler implements WxMpMessageHandler { 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 @Autowired 34 @Autowired
27 private WxAccountFansService wxAccountFansService; 35 private WxAccountFansService wxAccountFansService;
@@ -34,7 +42,7 @@ public class UnsubscribeHandler implements WxMpMessageHandler { @@ -34,7 +42,7 @@ public class UnsubscribeHandler implements WxMpMessageHandler {
34 log.info("取消关注用户 OPENID: " + openId); 42 log.info("取消关注用户 OPENID: " + openId);
35 // TODO 可以更新本地数据库为取消关注状态 43 // TODO 可以更新本地数据库为取消关注状态
36 44
37 - MpAccountDO wxAccountDO = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser()); 45 + MpAccountDO wxAccountDO = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
38 if (wxAccountDO != null) { 46 if (wxAccountDO != null) {
39 WxAccountFansDO wxAccountFansDO = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, openId); 47 WxAccountFansDO wxAccountFansDO = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, openId);
40 if (wxAccountFansDO != null) { 48 if (wxAccountFansDO != null) {