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,7 +4,11 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||
| 4 | import com.baomidou.mybatisplus.annotation.KeySequence; | 4 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 5 | import com.baomidou.mybatisplus.annotation.TableId; | 5 | import com.baomidou.mybatisplus.annotation.TableId; |
| 6 | import com.baomidou.mybatisplus.annotation.TableName; | 6 | import com.baomidou.mybatisplus.annotation.TableName; |
| 7 | +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; | ||
| 7 | import lombok.*; | 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 | // TODO 亚洲:这个模块的相关类,使用 Mp 作为前缀哈 | 13 | // TODO 亚洲:这个模块的相关类,使用 Mp 作为前缀哈 |
| 10 | /** | 14 | /** |
| @@ -64,4 +68,12 @@ public class WxAccountDO extends BaseDO { | @@ -64,4 +68,12 @@ public class WxAccountDO extends BaseDO { | ||
| 64 | */ | 68 | */ |
| 65 | private String remark; | 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,13 +6,10 @@ import cn.hutool.http.HttpUtil; | ||
| 6 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 6 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 7 | import cn.iocoder.yudao.module.infra.api.file.FileApi; | 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.config.WxMpProperties; | ||
| 10 | import cn.iocoder.yudao.module.mp.controller.admin.fansmsg.vo.WxFansMsgCreateReqVO; | 9 | import cn.iocoder.yudao.module.mp.controller.admin.fansmsg.vo.WxFansMsgCreateReqVO; |
| 11 | import cn.iocoder.yudao.module.mp.dal.dataobject.account.WxAccountDO; | 10 | import cn.iocoder.yudao.module.mp.dal.dataobject.account.WxAccountDO; |
| 12 | import cn.iocoder.yudao.module.mp.service.account.WxAccountService; | 11 | import cn.iocoder.yudao.module.mp.service.account.WxAccountService; |
| 13 | import cn.iocoder.yudao.module.mp.service.fansmsg.WxFansMsgService; | 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 | import lombok.extern.slf4j.Slf4j; | 13 | import lombok.extern.slf4j.Slf4j; |
| 17 | import me.chanjar.weixin.common.api.WxConsts; | 14 | import me.chanjar.weixin.common.api.WxConsts; |
| 18 | import me.chanjar.weixin.common.error.WxErrorException; | 15 | import me.chanjar.weixin.common.error.WxErrorException; |
| @@ -102,7 +99,7 @@ public class MsgHandler implements WxMpMessageHandler { | @@ -102,7 +99,7 @@ public class MsgHandler implements WxMpMessageHandler { | ||
| 102 | if (!downloadDir.exists()) { | 99 | if (!downloadDir.exists()) { |
| 103 | downloadDir.mkdirs(); | 100 | downloadDir.mkdirs(); |
| 104 | } | 101 | } |
| 105 | - String filepath = downloadDirStr + String.valueOf(System.currentTimeMillis()) + ".png"; | 102 | + String filepath = downloadDirStr + System.currentTimeMillis() + ".png"; |
| 106 | //微信pic url下载到本地,防止失效 | 103 | //微信pic url下载到本地,防止失效 |
| 107 | long size = HttpUtil.downloadFile(wxMessage.getPicUrl(), FileUtil.file(filepath)); | 104 | long size = HttpUtil.downloadFile(wxMessage.getPicUrl(), FileUtil.file(filepath)); |
| 108 | log.info("download pic size : {}", size); | 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 | 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.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 | 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 | ||
| @@ -18,12 +18,12 @@ import javax.annotation.Resource; | @@ -18,12 +18,12 @@ import javax.annotation.Resource; | ||
| 18 | public class WxConfigDataRefreshConsumer extends AbstractChannelMessageListener<WxConfigDataRefreshMessage> { | 18 | public class WxConfigDataRefreshConsumer extends AbstractChannelMessageListener<WxConfigDataRefreshMessage> { |
| 19 | 19 | ||
| 20 | @Resource | 20 | @Resource |
| 21 | - private WxMpConfig wxMpConfig; | 21 | + private WxAccountService wxAccountService; |
| 22 | 22 | ||
| 23 | @Override | 23 | @Override |
| 24 | public void onMessage(WxConfigDataRefreshMessage message) { | 24 | public void onMessage(WxConfigDataRefreshMessage message) { |
| 25 | log.info("[onMessage][收到 WxConfigData 刷新消息]"); | 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
| 1 | -package cn.iocoder.yudao.module.mp.mq.message.dict; | 1 | +package cn.iocoder.yudao.module.mp.mq.message; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage; | 3 | import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage; |
| 4 | import lombok.Data; | 4 | import lombok.Data; |
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 | 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.dict.WxConfigDataRefreshMessage; | 4 | +import cn.iocoder.yudao.module.mp.mq.message.WxConfigDataRefreshMessage; |
| 5 | import org.springframework.stereotype.Component; | 5 | import org.springframework.stereotype.Component; |
| 6 | 6 | ||
| 7 | import javax.annotation.Resource; | 7 | import javax.annotation.Resource; |
yudao-module-wechat/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountService.java
| @@ -81,4 +81,9 @@ public interface WxAccountService { | @@ -81,4 +81,9 @@ public interface WxAccountService { | ||
| 81 | * @return | 81 | * @return |
| 82 | */ | 82 | */ |
| 83 | WxAccountDO findBy(SFunction<WxAccountDO, ?> field, Object val); | 83 | WxAccountDO findBy(SFunction<WxAccountDO, ?> field, Object val); |
| 84 | + | ||
| 85 | + /** | ||
| 86 | + * 初始化 | ||
| 87 | + */ | ||
| 88 | + void initLoadWxMpConfigStorages(); | ||
| 84 | } | 89 | } |
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,6 +2,7 @@ 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.module.mp.controller.admin.account.vo.WxAccountCreateReqVO; | 6 | import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountCreateReqVO; |
| 6 | import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountExportReqVO; | 7 | import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountExportReqVO; |
| 7 | import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountPageReqVO; | 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,30 +11,52 @@ import cn.iocoder.yudao.module.mp.convert.account.WxAccountConvert; | ||
| 10 | import cn.iocoder.yudao.module.mp.dal.dataobject.account.WxAccountDO; | 11 | import cn.iocoder.yudao.module.mp.dal.dataobject.account.WxAccountDO; |
| 11 | import cn.iocoder.yudao.module.mp.dal.mysql.account.WxAccountMapper; | 12 | import cn.iocoder.yudao.module.mp.dal.mysql.account.WxAccountMapper; |
| 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.dict.WxMpConfigDataProducer; | 14 | +import cn.iocoder.yudao.module.mp.mq.producer.WxMpConfigDataProducer; |
| 14 | import com.baomidou.mybatisplus.core.toolkit.support.SFunction; | 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 | import org.springframework.stereotype.Service; | 24 | import org.springframework.stereotype.Service; |
| 25 | +import org.springframework.util.CollectionUtils; | ||
| 16 | import org.springframework.validation.annotation.Validated; | 26 | import org.springframework.validation.annotation.Validated; |
| 17 | 27 | ||
| 28 | +import javax.annotation.PostConstruct; | ||
| 18 | import javax.annotation.Resource; | 29 | import javax.annotation.Resource; |
| 19 | import java.util.Collection; | 30 | import java.util.Collection; |
| 31 | +import java.util.HashMap; | ||
| 20 | import java.util.List; | 32 | import java.util.List; |
| 33 | +import java.util.Map; | ||
| 21 | 34 | ||
| 22 | 35 | ||
| 23 | /** | 36 | /** |
| 24 | * 公众号账户 Service 实现类 | 37 | * 公众号账户 Service 实现类 |
| 25 | * | 38 | * |
| 26 | - * @author 芋道源码 | 39 | + * @author fengdan |
| 27 | */ | 40 | */ |
| 41 | +@Slf4j | ||
| 28 | @Service | 42 | @Service |
| 29 | @Validated | 43 | @Validated |
| 30 | public class WxAccountServiceImpl implements WxAccountService { | 44 | public class WxAccountServiceImpl implements WxAccountService { |
| 31 | 45 | ||
| 46 | + private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; | ||
| 32 | @Resource | 47 | @Resource |
| 33 | private WxAccountMapper wxAccountMapper; | 48 | private WxAccountMapper wxAccountMapper; |
| 34 | - | ||
| 35 | @Resource | 49 | @Resource |
| 36 | private WxMpConfigDataProducer wxMpConfigDataProducer; | 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 | @Override | 61 | @Override |
| 39 | public Long createWxAccount(WxAccountCreateReqVO createReqVO) { | 62 | public Long createWxAccount(WxAccountCreateReqVO createReqVO) { |
| @@ -94,4 +117,43 @@ public class WxAccountServiceImpl implements WxAccountService { | @@ -94,4 +117,43 @@ public class WxAccountServiceImpl implements WxAccountService { | ||
| 94 | public WxAccountDO findBy(SFunction<WxAccountDO, ?> field, Object val) { | 117 | public WxAccountDO findBy(SFunction<WxAccountDO, ?> field, Object val) { |
| 95 | return wxAccountMapper.selectOne(field, val); | 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 | } |