Commit 977cc19fe31c9874aeec3e7f7dbfbff99f3ebd64
1 parent
93dfee8e
fix(公众号账号管理): 多公众号账号初始化配置加载
Showing
10 changed files
with
197 additions
and
207 deletions
yudao-module-wechat/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/config/WxMpConfig.java deleted
| 1 | -package cn.iocoder.yudao.module.mp.config; | |
| 2 | - | |
| 3 | - | |
| 4 | -import cn.hutool.extra.spring.SpringUtil; | |
| 5 | -import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountExportReqVO; | |
| 6 | -import cn.iocoder.yudao.module.mp.dal.dataobject.account.WxAccountDO; | |
| 7 | -import cn.iocoder.yudao.module.mp.handler.*; | |
| 8 | -import cn.iocoder.yudao.module.mp.service.account.WxAccountService; | |
| 9 | -import com.google.common.collect.Maps; | |
| 10 | -import lombok.extern.slf4j.Slf4j; | |
| 11 | -import me.chanjar.weixin.common.api.WxConsts; | |
| 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.WxMpDefaultConfigImpl; | |
| 16 | -import me.chanjar.weixin.mp.constant.WxMpEventConstants; | |
| 17 | -import org.springframework.context.annotation.Configuration; | |
| 18 | -import org.springframework.scheduling.annotation.Scheduled; | |
| 19 | -import org.springframework.util.CollectionUtils; | |
| 20 | - | |
| 21 | -import javax.annotation.PostConstruct; | |
| 22 | -import javax.annotation.Resource; | |
| 23 | -import java.util.List; | |
| 24 | -import java.util.Map; | |
| 25 | -import java.util.stream.Collectors; | |
| 26 | - | |
| 27 | -// TODO @芋艿:思考有没更好的处理方式 | |
| 28 | -@Slf4j | |
| 29 | -@Configuration | |
| 30 | -public class WxMpConfig { | |
| 31 | - | |
| 32 | - private static Map<String, WxMpMessageRouter> routers = Maps.newHashMap(); | |
| 33 | - private static Map<String, WxMpService> mpServices = Maps.newHashMap(); | |
| 34 | - | |
| 35 | - @Resource | |
| 36 | - private WxAccountService wxAccountService; | |
| 37 | - | |
| 38 | - private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; | |
| 39 | - | |
| 40 | - /** | |
| 41 | - * 初始化公众号配置 | |
| 42 | - */ | |
| 43 | - @PostConstruct | |
| 44 | - public synchronized void initWxConfig() { | |
| 45 | - WxAccountExportReqVO req = new WxAccountExportReqVO(); | |
| 46 | - List<WxAccountDO> wxAccountList = wxAccountService.getWxAccountList(req); | |
| 47 | - if (CollectionUtils.isEmpty(wxAccountList)) { | |
| 48 | - return; | |
| 49 | - } | |
| 50 | - WxMpConfig.init(wxAccountList); | |
| 51 | - log.info("加载公众号配置成功"); | |
| 52 | - } | |
| 53 | - | |
| 54 | - | |
| 55 | - @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | |
| 56 | - public void schedulePeriodicRefresh() { | |
| 57 | - initWxConfig(); | |
| 58 | - } | |
| 59 | - | |
| 60 | - public static void init(List<WxAccountDO> wxAccountDOS) { | |
| 61 | - mpServices = wxAccountDOS.stream().map(wxAccountDO -> { | |
| 62 | - // TODO 亚洲:使用 WxMpInMemoryConfigStorage 的话,多节点会不会存在 accessToken 冲突 | |
| 63 | - | |
| 64 | - WxMpDefaultConfigImpl configStorage; | |
| 65 | - configStorage = new WxMpDefaultConfigImpl(); | |
| 66 | - | |
| 67 | - configStorage.setAppId(wxAccountDO.getAppId()); | |
| 68 | - configStorage.setSecret(wxAccountDO.getAppSecret()); | |
| 69 | - configStorage.setToken(wxAccountDO.getToken()); | |
| 70 | - configStorage.setAesKey(wxAccountDO.getAesKey()); | |
| 71 | - | |
| 72 | - WxMpService service = new WxMpServiceImpl(); | |
| 73 | - service.setWxMpConfigStorage(configStorage); | |
| 74 | - routers.put(wxAccountDO.getAppId(), newRouter(service)); | |
| 75 | - return service; | |
| 76 | - }).collect(Collectors.toMap(s -> s.getWxMpConfigStorage().getAppId(), a -> a, (o, n) -> o)); | |
| 77 | - } | |
| 78 | - | |
| 79 | - public static Map<String, WxMpMessageRouter> getRouters() { | |
| 80 | - return routers; | |
| 81 | - } | |
| 82 | - | |
| 83 | - public static Map<String, WxMpService> getMpServices() { | |
| 84 | - return mpServices; | |
| 85 | - } | |
| 86 | - | |
| 87 | - private static WxMpMessageRouter newRouter(WxMpService wxMpService) { | |
| 88 | - final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService); | |
| 89 | - // 记录所有事件的日志 (异步执行) | |
| 90 | - newRouter.rule().handler(SpringUtil.getBean(LogHandler.class)).next(); | |
| 91 | - | |
| 92 | - // 接收客服会话管理事件 | |
| 93 | - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | |
| 94 | - .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION) | |
| 95 | - .handler(SpringUtil.getBean(KfSessionHandler.class)).end(); | |
| 96 | - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | |
| 97 | - .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION) | |
| 98 | - .handler(SpringUtil.getBean(KfSessionHandler.class)) | |
| 99 | - .end(); | |
| 100 | - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | |
| 101 | - .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION) | |
| 102 | - .handler(SpringUtil.getBean(KfSessionHandler.class)).end(); | |
| 103 | - | |
| 104 | - // 门店审核事件 | |
| 105 | - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | |
| 106 | - .event(WxMpEventConstants.POI_CHECK_NOTIFY) | |
| 107 | - .handler(SpringUtil.getBean(StoreCheckNotifyHandler.class)).end(); | |
| 108 | - | |
| 109 | - // 自定义菜单事件 | |
| 110 | - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | |
| 111 | - .event(WxConsts.MenuButtonType.CLICK).handler(SpringUtil.getBean(MenuHandler.class)).end(); | |
| 112 | - | |
| 113 | - // 点击菜单连接事件 | |
| 114 | - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | |
| 115 | - .event(WxConsts.MenuButtonType.VIEW).handler(SpringUtil.getBean(NullHandler.class)).end(); | |
| 116 | - | |
| 117 | - // 关注事件 | |
| 118 | - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | |
| 119 | - .event(WxConsts.EventType.SUBSCRIBE).handler(SpringUtil.getBean(SubscribeHandler.class)) | |
| 120 | - .end(); | |
| 121 | - | |
| 122 | - // 取消关注事件 | |
| 123 | - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | |
| 124 | - .event(WxConsts.EventType.UNSUBSCRIBE) | |
| 125 | - .handler(SpringUtil.getBean(UnsubscribeHandler.class)).end(); | |
| 126 | - | |
| 127 | - // 上报地理位置事件 | |
| 128 | - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | |
| 129 | - .event(WxConsts.EventType.LOCATION).handler(SpringUtil.getBean(LocationHandler.class)) | |
| 130 | - .end(); | |
| 131 | - | |
| 132 | - // 接收地理位置消息 | |
| 133 | - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION) | |
| 134 | - .handler(SpringUtil.getBean(LocationHandler.class)).end(); | |
| 135 | - | |
| 136 | - // 扫码事件 | |
| 137 | - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | |
| 138 | - .event(WxConsts.EventType.SCAN).handler(SpringUtil.getBean(ScanHandler.class)).end(); | |
| 139 | - | |
| 140 | - // 默认 | |
| 141 | - newRouter.rule().async(false).handler(SpringUtil.getBean(MsgHandler.class)).end(); | |
| 142 | - | |
| 143 | - return newRouter; | |
| 144 | - } | |
| 145 | -} |
yudao-module-wechat/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/config/WxMpProperties.java deleted
| 1 | -package cn.iocoder.yudao.module.mp.config; | |
| 2 | - | |
| 3 | -import lombok.Data; | |
| 4 | -import org.springframework.boot.context.properties.ConfigurationProperties; | |
| 5 | - | |
| 6 | -/** | |
| 7 | - * wechat mp properties | |
| 8 | - */ | |
| 9 | -@Data | |
| 10 | -//@ConfigurationProperties(prefix = "wx.mp") | |
| 11 | -public class WxMpProperties { | |
| 12 | - /** | |
| 13 | - * 是否使用redis存储access token | |
| 14 | - */ | |
| 15 | - private boolean useRedis; | |
| 16 | - | |
| 17 | - private String defaultContent; | |
| 18 | - | |
| 19 | - /** | |
| 20 | - * redis 配置 | |
| 21 | - */ | |
| 22 | - private RedisConfig redisConfig; | |
| 23 | - | |
| 24 | - @Data | |
| 25 | - public static class RedisConfig { | |
| 26 | - /** | |
| 27 | - * redis服务器 主机地址 | |
| 28 | - */ | |
| 29 | - private String host; | |
| 30 | - | |
| 31 | - /** | |
| 32 | - * redis服务器 端口号 | |
| 33 | - */ | |
| 34 | - private Integer port; | |
| 35 | - | |
| 36 | - /** | |
| 37 | - * redis服务器 密码 | |
| 38 | - */ | |
| 39 | - private String password; | |
| 40 | - | |
| 41 | - /** | |
| 42 | - * redis 服务连接超时时间 | |
| 43 | - */ | |
| 44 | - private Integer timeout; | |
| 45 | - } | |
| 46 | - | |
| 47 | -} |
yudao-module-wechat/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/account/WxAccountDO.java
| ... | ... | @@ -4,7 +4,11 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | 4 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 5 | 5 | import com.baomidou.mybatisplus.annotation.TableId; |
| 6 | 6 | import com.baomidou.mybatisplus.annotation.TableName; |
| 7 | +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; | |
| 7 | 8 | import lombok.*; |
| 9 | +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; | |
| 10 | +import me.chanjar.weixin.mp.config.WxMpConfigStorage; | |
| 11 | +import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl; | |
| 8 | 12 | |
| 9 | 13 | // TODO 亚洲:这个模块的相关类,使用 Mp 作为前缀哈 |
| 10 | 14 | /** |
| ... | ... | @@ -64,4 +68,12 @@ public class WxAccountDO extends BaseDO { |
| 64 | 68 | */ |
| 65 | 69 | private String remark; |
| 66 | 70 | |
| 71 | + public WxMpConfigStorage toWxMpConfigStorage(RedisTemplateWxRedisOps redisTemplateWxRedisOps, WxMpProperties wxMpProperties) { | |
| 72 | + WxMpRedisConfigImpl wxMpRedisConfig = new WxMpRedisConfigImpl(redisTemplateWxRedisOps, wxMpProperties.getConfigStorage().getKeyPrefix()); | |
| 73 | + wxMpRedisConfig.setAppId(appId); | |
| 74 | + wxMpRedisConfig.setSecret(appSecret); | |
| 75 | + wxMpRedisConfig.setToken(token); | |
| 76 | + wxMpRedisConfig.setAesKey(aesKey); | |
| 77 | + return wxMpRedisConfig; | |
| 78 | + } | |
| 67 | 79 | } | ... | ... |
yudao-module-wechat/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/weixin/WxMpMessageRouterConfiguration.java
0 → 100644
| 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-wechat/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MsgHandler.java
| ... | ... | @@ -6,13 +6,10 @@ import cn.hutool.http.HttpUtil; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 7 | 7 | import cn.iocoder.yudao.module.infra.api.file.FileApi; |
| 8 | 8 | import cn.iocoder.yudao.module.mp.builder.TextBuilder; |
| 9 | -import cn.iocoder.yudao.module.mp.config.WxMpProperties; | |
| 10 | 9 | import cn.iocoder.yudao.module.mp.controller.admin.fansmsg.vo.WxFansMsgCreateReqVO; |
| 11 | 10 | import cn.iocoder.yudao.module.mp.dal.dataobject.account.WxAccountDO; |
| 12 | 11 | import cn.iocoder.yudao.module.mp.service.account.WxAccountService; |
| 13 | 12 | import cn.iocoder.yudao.module.mp.service.fansmsg.WxFansMsgService; |
| 14 | -import cn.iocoder.yudao.module.mp.service.receivetext.WxReceiveTextService; | |
| 15 | -import cn.iocoder.yudao.module.mp.service.texttemplate.WxTextTemplateService; | |
| 16 | 13 | import lombok.extern.slf4j.Slf4j; |
| 17 | 14 | import me.chanjar.weixin.common.api.WxConsts; |
| 18 | 15 | import me.chanjar.weixin.common.error.WxErrorException; |
| ... | ... | @@ -102,7 +99,7 @@ public class MsgHandler implements WxMpMessageHandler { |
| 102 | 99 | if (!downloadDir.exists()) { |
| 103 | 100 | downloadDir.mkdirs(); |
| 104 | 101 | } |
| 105 | - String filepath = downloadDirStr + String.valueOf(System.currentTimeMillis()) + ".png"; | |
| 102 | + String filepath = downloadDirStr + System.currentTimeMillis() + ".png"; | |
| 106 | 103 | //微信pic url下载到本地,防止失效 |
| 107 | 104 | long size = HttpUtil.downloadFile(wxMessage.getPicUrl(), FileUtil.file(filepath)); |
| 108 | 105 | log.info("download pic size : {}", size); | ... | ... |
yudao-module-wechat/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/WxConfigDataRefreshConsumer.java
| 1 | -package cn.iocoder.yudao.module.mp.mq.costomer.dict; | |
| 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.config.WxMpConfig; | |
| 5 | -import cn.iocoder.yudao.module.mp.mq.message.dict.WxConfigDataRefreshMessage; | |
| 4 | +import cn.iocoder.yudao.module.mp.mq.message.WxConfigDataRefreshMessage; | |
| 5 | +import cn.iocoder.yudao.module.mp.service.account.WxAccountService; | |
| 6 | 6 | import lombok.extern.slf4j.Slf4j; |
| 7 | 7 | import org.springframework.stereotype.Component; |
| 8 | 8 | |
| ... | ... | @@ -18,12 +18,12 @@ import javax.annotation.Resource; |
| 18 | 18 | public class WxConfigDataRefreshConsumer extends AbstractChannelMessageListener<WxConfigDataRefreshMessage> { |
| 19 | 19 | |
| 20 | 20 | @Resource |
| 21 | - private WxMpConfig wxMpConfig; | |
| 21 | + private WxAccountService wxAccountService; | |
| 22 | 22 | |
| 23 | 23 | @Override |
| 24 | 24 | public void onMessage(WxConfigDataRefreshMessage message) { |
| 25 | 25 | log.info("[onMessage][收到 WxConfigData 刷新消息]"); |
| 26 | - wxMpConfig.initWxConfig(); | |
| 26 | + wxAccountService.initLoadWxMpConfigStorages(); | |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | } | ... | ... |
yudao-module-wechat/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/WxConfigDataRefreshMessage.java
yudao-module-wechat/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/WxMpConfigDataProducer.java
| 1 | -package cn.iocoder.yudao.module.mp.mq.producer.dict; | |
| 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.dict.WxConfigDataRefreshMessage; | |
| 4 | +import cn.iocoder.yudao.module.mp.mq.message.WxConfigDataRefreshMessage; | |
| 5 | 5 | import org.springframework.stereotype.Component; |
| 6 | 6 | |
| 7 | 7 | import javax.annotation.Resource; | ... | ... |
yudao-module-wechat/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountService.java
yudao-module-wechat/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountServiceImpl.java
| ... | ... | @@ -2,6 +2,7 @@ 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 | 6 | import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountCreateReqVO; |
| 6 | 7 | import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountExportReqVO; |
| 7 | 8 | import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountPageReqVO; |
| ... | ... | @@ -10,30 +11,52 @@ import cn.iocoder.yudao.module.mp.convert.account.WxAccountConvert; |
| 10 | 11 | import cn.iocoder.yudao.module.mp.dal.dataobject.account.WxAccountDO; |
| 11 | 12 | import cn.iocoder.yudao.module.mp.dal.mysql.account.WxAccountMapper; |
| 12 | 13 | import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants; |
| 13 | -import cn.iocoder.yudao.module.mp.mq.producer.dict.WxMpConfigDataProducer; | |
| 14 | +import cn.iocoder.yudao.module.mp.mq.producer.WxMpConfigDataProducer; | |
| 14 | 15 | import com.baomidou.mybatisplus.core.toolkit.support.SFunction; |
| 16 | +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; | |
| 17 | +import lombok.extern.slf4j.Slf4j; | |
| 18 | +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; | |
| 19 | +import me.chanjar.weixin.mp.api.WxMpService; | |
| 20 | +import me.chanjar.weixin.mp.config.WxMpConfigStorage; | |
| 21 | +import org.springframework.context.annotation.Lazy; | |
| 22 | +import org.springframework.data.redis.core.StringRedisTemplate; | |
| 23 | +import org.springframework.scheduling.annotation.Scheduled; | |
| 15 | 24 | import org.springframework.stereotype.Service; |
| 25 | +import org.springframework.util.CollectionUtils; | |
| 16 | 26 | import org.springframework.validation.annotation.Validated; |
| 17 | 27 | |
| 28 | +import javax.annotation.PostConstruct; | |
| 18 | 29 | import javax.annotation.Resource; |
| 19 | 30 | import java.util.Collection; |
| 31 | +import java.util.HashMap; | |
| 20 | 32 | import java.util.List; |
| 33 | +import java.util.Map; | |
| 21 | 34 | |
| 22 | 35 | |
| 23 | 36 | /** |
| 24 | 37 | * 公众号账户 Service 实现类 |
| 25 | 38 | * |
| 26 | - * @author 芋道源码 | |
| 39 | + * @author fengdan | |
| 27 | 40 | */ |
| 41 | +@Slf4j | |
| 28 | 42 | @Service |
| 29 | 43 | @Validated |
| 30 | 44 | public class WxAccountServiceImpl implements WxAccountService { |
| 31 | 45 | |
| 46 | + private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; | |
| 32 | 47 | @Resource |
| 33 | 48 | private WxAccountMapper wxAccountMapper; |
| 34 | - | |
| 35 | 49 | @Resource |
| 36 | 50 | private WxMpConfigDataProducer wxMpConfigDataProducer; |
| 51 | + @Resource | |
| 52 | + private StringRedisTemplate stringRedisTemplate; | |
| 53 | + @Resource | |
| 54 | + private WxMpService wxMpService; | |
| 55 | + @Resource | |
| 56 | + private WxMpProperties wxMpProperties; | |
| 57 | + @Resource | |
| 58 | + @Lazy // 注入自己,所以延迟加载 | |
| 59 | + private WxAccountService self; | |
| 37 | 60 | |
| 38 | 61 | @Override |
| 39 | 62 | public Long createWxAccount(WxAccountCreateReqVO createReqVO) { |
| ... | ... | @@ -94,4 +117,43 @@ public class WxAccountServiceImpl implements WxAccountService { |
| 94 | 117 | public WxAccountDO findBy(SFunction<WxAccountDO, ?> field, Object val) { |
| 95 | 118 | return wxAccountMapper.selectOne(field, val); |
| 96 | 119 | } |
| 120 | + | |
| 121 | + @PostConstruct | |
| 122 | + @TenantIgnore | |
| 123 | + @Override | |
| 124 | + public void initLoadWxMpConfigStorages() { | |
| 125 | + List<WxAccountDO> wxAccountList = this.wxAccountMapper.selectList(); | |
| 126 | + if (CollectionUtils.isEmpty(wxAccountList)) { | |
| 127 | + log.info("未读取到公众号配置,请在管理后台添加"); | |
| 128 | + return; | |
| 129 | + } | |
| 130 | + log.info("加载到{}条公众号配置", wxAccountList.size()); | |
| 131 | + wxAccountList.forEach(account -> addAccountToRuntime(account, new RedisTemplateWxRedisOps(stringRedisTemplate))); | |
| 132 | + log.info("公众号配置加载完成"); | |
| 133 | + } | |
| 134 | + | |
| 135 | + /** | |
| 136 | + * 添加账号到当前程序,如首次添加需初始化configStorageMap | |
| 137 | + * | |
| 138 | + * @param account 公众号 | |
| 139 | + */ | |
| 140 | + private synchronized void addAccountToRuntime(WxAccountDO account, RedisTemplateWxRedisOps redisOps) { | |
| 141 | + String appId = account.getAppId(); | |
| 142 | + WxMpConfigStorage wxMpRedisConfig = account.toWxMpConfigStorage(redisOps, wxMpProperties); | |
| 143 | + try { | |
| 144 | + wxMpService.addConfigStorage(appId, wxMpRedisConfig); | |
| 145 | + } catch (NullPointerException e) { | |
| 146 | + log.info("需初始化configStorageMap..."); | |
| 147 | + Map<String, WxMpConfigStorage> configStorages = new HashMap<>(4); | |
| 148 | + configStorages.put(appId, wxMpRedisConfig); | |
| 149 | + wxMpService.setMultiConfigStorages(configStorages, appId); | |
| 150 | + } | |
| 151 | + } | |
| 152 | + | |
| 153 | + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | |
| 154 | + public void schedulePeriodicRefresh() { | |
| 155 | + self.initLoadWxMpConfigStorages(); | |
| 156 | + } | |
| 157 | + | |
| 158 | + | |
| 97 | 159 | } | ... | ... |