mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-01 02:38:43 +08:00 
			
		
		
		
	fix(公众号账号管理): 多公众号账号初始化配置加载
This commit is contained in:
		| @@ -1,145 +0,0 @@ | |||||||
| package cn.iocoder.yudao.module.mp.config; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| import cn.hutool.extra.spring.SpringUtil; |  | ||||||
| import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountExportReqVO; |  | ||||||
| import cn.iocoder.yudao.module.mp.dal.dataobject.account.WxAccountDO; |  | ||||||
| import cn.iocoder.yudao.module.mp.handler.*; |  | ||||||
| import cn.iocoder.yudao.module.mp.service.account.WxAccountService; |  | ||||||
| import com.google.common.collect.Maps; |  | ||||||
| import lombok.extern.slf4j.Slf4j; |  | ||||||
| import me.chanjar.weixin.common.api.WxConsts; |  | ||||||
| import me.chanjar.weixin.mp.api.WxMpMessageRouter; |  | ||||||
| import me.chanjar.weixin.mp.api.WxMpService; |  | ||||||
| import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; |  | ||||||
| import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; |  | ||||||
| import me.chanjar.weixin.mp.constant.WxMpEventConstants; |  | ||||||
| import org.springframework.context.annotation.Configuration; |  | ||||||
| import org.springframework.scheduling.annotation.Scheduled; |  | ||||||
| import org.springframework.util.CollectionUtils; |  | ||||||
|  |  | ||||||
| import javax.annotation.PostConstruct; |  | ||||||
| import javax.annotation.Resource; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.stream.Collectors; |  | ||||||
|  |  | ||||||
| // TODO @芋艿:思考有没更好的处理方式 |  | ||||||
| @Slf4j |  | ||||||
| @Configuration |  | ||||||
| public class WxMpConfig { |  | ||||||
|  |  | ||||||
|     private static Map<String, WxMpMessageRouter> routers = Maps.newHashMap(); |  | ||||||
|     private static Map<String, WxMpService> mpServices = Maps.newHashMap(); |  | ||||||
|  |  | ||||||
|     @Resource |  | ||||||
|     private WxAccountService wxAccountService; |  | ||||||
|  |  | ||||||
|     private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 初始化公众号配置 |  | ||||||
|      */ |  | ||||||
|     @PostConstruct |  | ||||||
|     public synchronized void initWxConfig() { |  | ||||||
|         WxAccountExportReqVO req = new WxAccountExportReqVO(); |  | ||||||
|         List<WxAccountDO> wxAccountList = wxAccountService.getWxAccountList(req); |  | ||||||
|         if (CollectionUtils.isEmpty(wxAccountList)) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         WxMpConfig.init(wxAccountList); |  | ||||||
|         log.info("加载公众号配置成功"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) |  | ||||||
|     public void schedulePeriodicRefresh() { |  | ||||||
|         initWxConfig(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static void init(List<WxAccountDO> wxAccountDOS) { |  | ||||||
|         mpServices = wxAccountDOS.stream().map(wxAccountDO -> { |  | ||||||
|             // TODO 亚洲:使用 WxMpInMemoryConfigStorage 的话,多节点会不会存在 accessToken 冲突 |  | ||||||
|  |  | ||||||
|             WxMpDefaultConfigImpl configStorage; |  | ||||||
|             configStorage = new WxMpDefaultConfigImpl(); |  | ||||||
|  |  | ||||||
|             configStorage.setAppId(wxAccountDO.getAppId()); |  | ||||||
|             configStorage.setSecret(wxAccountDO.getAppSecret()); |  | ||||||
|             configStorage.setToken(wxAccountDO.getToken()); |  | ||||||
|             configStorage.setAesKey(wxAccountDO.getAesKey()); |  | ||||||
|  |  | ||||||
|             WxMpService service = new WxMpServiceImpl(); |  | ||||||
|             service.setWxMpConfigStorage(configStorage); |  | ||||||
|             routers.put(wxAccountDO.getAppId(), newRouter(service)); |  | ||||||
|             return service; |  | ||||||
|         }).collect(Collectors.toMap(s -> s.getWxMpConfigStorage().getAppId(), a -> a, (o, n) -> o)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static Map<String, WxMpMessageRouter> getRouters() { |  | ||||||
|         return routers; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static Map<String, WxMpService> getMpServices() { |  | ||||||
|         return mpServices; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private static WxMpMessageRouter newRouter(WxMpService wxMpService) { |  | ||||||
|         final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService); |  | ||||||
|         // 记录所有事件的日志 (异步执行) |  | ||||||
|         newRouter.rule().handler(SpringUtil.getBean(LogHandler.class)).next(); |  | ||||||
|  |  | ||||||
|         // 接收客服会话管理事件 |  | ||||||
|         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) |  | ||||||
|                 .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION) |  | ||||||
|                 .handler(SpringUtil.getBean(KfSessionHandler.class)).end(); |  | ||||||
|         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) |  | ||||||
|                 .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION) |  | ||||||
|                 .handler(SpringUtil.getBean(KfSessionHandler.class)) |  | ||||||
|                 .end(); |  | ||||||
|         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) |  | ||||||
|                 .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION) |  | ||||||
|                 .handler(SpringUtil.getBean(KfSessionHandler.class)).end(); |  | ||||||
|  |  | ||||||
|         // 门店审核事件 |  | ||||||
|         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) |  | ||||||
|                 .event(WxMpEventConstants.POI_CHECK_NOTIFY) |  | ||||||
|                 .handler(SpringUtil.getBean(StoreCheckNotifyHandler.class)).end(); |  | ||||||
|  |  | ||||||
|         // 自定义菜单事件 |  | ||||||
|         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) |  | ||||||
|                 .event(WxConsts.MenuButtonType.CLICK).handler(SpringUtil.getBean(MenuHandler.class)).end(); |  | ||||||
|  |  | ||||||
|         // 点击菜单连接事件 |  | ||||||
|         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) |  | ||||||
|                 .event(WxConsts.MenuButtonType.VIEW).handler(SpringUtil.getBean(NullHandler.class)).end(); |  | ||||||
|  |  | ||||||
|         // 关注事件 |  | ||||||
|         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) |  | ||||||
|                 .event(WxConsts.EventType.SUBSCRIBE).handler(SpringUtil.getBean(SubscribeHandler.class)) |  | ||||||
|                 .end(); |  | ||||||
|  |  | ||||||
|         // 取消关注事件 |  | ||||||
|         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) |  | ||||||
|                 .event(WxConsts.EventType.UNSUBSCRIBE) |  | ||||||
|                 .handler(SpringUtil.getBean(UnsubscribeHandler.class)).end(); |  | ||||||
|  |  | ||||||
|         // 上报地理位置事件 |  | ||||||
|         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) |  | ||||||
|                 .event(WxConsts.EventType.LOCATION).handler(SpringUtil.getBean(LocationHandler.class)) |  | ||||||
|                 .end(); |  | ||||||
|  |  | ||||||
|         // 接收地理位置消息 |  | ||||||
|         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION) |  | ||||||
|                 .handler(SpringUtil.getBean(LocationHandler.class)).end(); |  | ||||||
|  |  | ||||||
|         // 扫码事件 |  | ||||||
|         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) |  | ||||||
|                 .event(WxConsts.EventType.SCAN).handler(SpringUtil.getBean(ScanHandler.class)).end(); |  | ||||||
|  |  | ||||||
|         // 默认 |  | ||||||
|         newRouter.rule().async(false).handler(SpringUtil.getBean(MsgHandler.class)).end(); |  | ||||||
|  |  | ||||||
|         return newRouter; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,47 +0,0 @@ | |||||||
| package cn.iocoder.yudao.module.mp.config; |  | ||||||
|  |  | ||||||
| import lombok.Data; |  | ||||||
| import org.springframework.boot.context.properties.ConfigurationProperties; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * wechat mp properties |  | ||||||
|  */ |  | ||||||
| @Data |  | ||||||
| //@ConfigurationProperties(prefix = "wx.mp") |  | ||||||
| public class WxMpProperties { |  | ||||||
|     /** |  | ||||||
|      * 是否使用redis存储access token |  | ||||||
|      */ |  | ||||||
|     private boolean useRedis; |  | ||||||
|  |  | ||||||
|     private String defaultContent; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * redis 配置 |  | ||||||
|      */ |  | ||||||
|     private RedisConfig redisConfig; |  | ||||||
|  |  | ||||||
|     @Data |  | ||||||
|     public static class RedisConfig { |  | ||||||
|         /** |  | ||||||
|          * redis服务器 主机地址 |  | ||||||
|          */ |  | ||||||
|         private String host; |  | ||||||
|  |  | ||||||
|         /** |  | ||||||
|          * redis服务器 端口号 |  | ||||||
|          */ |  | ||||||
|         private Integer port; |  | ||||||
|  |  | ||||||
|         /** |  | ||||||
|          * redis服务器 密码 |  | ||||||
|          */ |  | ||||||
|         private String password; |  | ||||||
|  |  | ||||||
|         /** |  | ||||||
|          * redis 服务连接超时时间 |  | ||||||
|          */ |  | ||||||
|         private Integer timeout; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -4,7 +4,11 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |||||||
| import com.baomidou.mybatisplus.annotation.KeySequence; | import com.baomidou.mybatisplus.annotation.KeySequence; | ||||||
| import com.baomidou.mybatisplus.annotation.TableId; | import com.baomidou.mybatisplus.annotation.TableId; | ||||||
| import com.baomidou.mybatisplus.annotation.TableName; | import com.baomidou.mybatisplus.annotation.TableName; | ||||||
|  | import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; | ||||||
| import lombok.*; | import lombok.*; | ||||||
|  | import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; | ||||||
|  | import me.chanjar.weixin.mp.config.WxMpConfigStorage; | ||||||
|  | import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl; | ||||||
|  |  | ||||||
| // TODO 亚洲:这个模块的相关类,使用 Mp 作为前缀哈 | // TODO 亚洲:这个模块的相关类,使用 Mp 作为前缀哈 | ||||||
| /** | /** | ||||||
| @@ -64,4 +68,12 @@ public class WxAccountDO extends BaseDO { | |||||||
|      */ |      */ | ||||||
|     private String remark; |     private String remark; | ||||||
|  |  | ||||||
|  |     public WxMpConfigStorage toWxMpConfigStorage(RedisTemplateWxRedisOps redisTemplateWxRedisOps, WxMpProperties wxMpProperties) { | ||||||
|  |         WxMpRedisConfigImpl wxMpRedisConfig = new WxMpRedisConfigImpl(redisTemplateWxRedisOps, wxMpProperties.getConfigStorage().getKeyPrefix()); | ||||||
|  |         wxMpRedisConfig.setAppId(appId); | ||||||
|  |         wxMpRedisConfig.setSecret(appSecret); | ||||||
|  |         wxMpRedisConfig.setToken(token); | ||||||
|  |         wxMpRedisConfig.setAesKey(aesKey); | ||||||
|  |         return wxMpRedisConfig; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,106 @@ | |||||||
|  | package cn.iocoder.yudao.module.mp.framework.weixin; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.module.mp.handler.*; | ||||||
|  | import lombok.RequiredArgsConstructor; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import me.chanjar.weixin.common.api.WxConsts; | ||||||
|  | import me.chanjar.weixin.mp.api.WxMpMessageRouter; | ||||||
|  | import me.chanjar.weixin.mp.api.WxMpService; | ||||||
|  | import me.chanjar.weixin.mp.constant.WxMpEventConstants; | ||||||
|  | import org.springframework.context.annotation.Bean; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  |  | ||||||
|  | import javax.annotation.Resource; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @author fengdan | ||||||
|  |  */ | ||||||
|  | @Slf4j | ||||||
|  | @Component | ||||||
|  | @RequiredArgsConstructor | ||||||
|  | public class WxMpMessageRouterConfiguration { | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private WxMpService wxMpService; | ||||||
|  |     @Resource | ||||||
|  |     private LogHandler logHandler; | ||||||
|  |     @Resource | ||||||
|  |     private KfSessionHandler kfSessionHandler; | ||||||
|  |     @Resource | ||||||
|  |     private StoreCheckNotifyHandler storeCheckNotifyHandler; | ||||||
|  |     @Resource | ||||||
|  |     private MenuHandler menuHandler; | ||||||
|  |     @Resource | ||||||
|  |     private NullHandler nullHandler; | ||||||
|  |     @Resource | ||||||
|  |     private SubscribeHandler subscribeHandler; | ||||||
|  |     @Resource | ||||||
|  |     private UnsubscribeHandler unsubscribeHandler; | ||||||
|  |     @Resource | ||||||
|  |     private LocationHandler locationHandler; | ||||||
|  |     @Resource | ||||||
|  |     private ScanHandler scanHandler; | ||||||
|  |     @Resource | ||||||
|  |     private MsgHandler msgHandler; | ||||||
|  |  | ||||||
|  |     @Bean | ||||||
|  |     public WxMpMessageRouter messageRouter() { | ||||||
|  |         final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService); | ||||||
|  |         // 记录所有事件的日志 (异步执行) | ||||||
|  |         newRouter.rule().handler(logHandler).next(); | ||||||
|  |  | ||||||
|  |         // 接收客服会话管理事件 | ||||||
|  |         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | ||||||
|  |                 .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION) | ||||||
|  |                 .handler(kfSessionHandler).end(); | ||||||
|  |         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | ||||||
|  |                 .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION) | ||||||
|  |                 .handler(kfSessionHandler) | ||||||
|  |                 .end(); | ||||||
|  |         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | ||||||
|  |                 .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION) | ||||||
|  |                 .handler(kfSessionHandler).end(); | ||||||
|  |  | ||||||
|  |         // 门店审核事件 | ||||||
|  |         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | ||||||
|  |                 .event(WxMpEventConstants.POI_CHECK_NOTIFY) | ||||||
|  |                 .handler(storeCheckNotifyHandler).end(); | ||||||
|  |  | ||||||
|  |         // 自定义菜单事件 | ||||||
|  |         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | ||||||
|  |                 .event(WxConsts.MenuButtonType.CLICK).handler(menuHandler).end(); | ||||||
|  |  | ||||||
|  |         // 点击菜单连接事件 | ||||||
|  |         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | ||||||
|  |                 .event(WxConsts.MenuButtonType.VIEW).handler(nullHandler).end(); | ||||||
|  |  | ||||||
|  |         // 关注事件 | ||||||
|  |         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | ||||||
|  |                 .event(WxConsts.EventType.SUBSCRIBE).handler(subscribeHandler) | ||||||
|  |                 .end(); | ||||||
|  |  | ||||||
|  |         // 取消关注事件 | ||||||
|  |         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | ||||||
|  |                 .event(WxConsts.EventType.UNSUBSCRIBE) | ||||||
|  |                 .handler(unsubscribeHandler).end(); | ||||||
|  |  | ||||||
|  |         // 上报地理位置事件 | ||||||
|  |         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | ||||||
|  |                 .event(WxConsts.EventType.LOCATION).handler(locationHandler) | ||||||
|  |                 .end(); | ||||||
|  |  | ||||||
|  |         // 接收地理位置消息 | ||||||
|  |         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION) | ||||||
|  |                 .handler(locationHandler).end(); | ||||||
|  |  | ||||||
|  |         // 扫码事件 | ||||||
|  |         newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) | ||||||
|  |                 .event(WxConsts.EventType.SCAN).handler(scanHandler).end(); | ||||||
|  |  | ||||||
|  |         // 默认 | ||||||
|  |         newRouter.rule().async(false).handler(msgHandler).end(); | ||||||
|  |  | ||||||
|  |         return newRouter; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -6,13 +6,10 @@ import cn.hutool.http.HttpUtil; | |||||||
| import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||||||
| import cn.iocoder.yudao.module.infra.api.file.FileApi; | import cn.iocoder.yudao.module.infra.api.file.FileApi; | ||||||
| import cn.iocoder.yudao.module.mp.builder.TextBuilder; | import cn.iocoder.yudao.module.mp.builder.TextBuilder; | ||||||
| import cn.iocoder.yudao.module.mp.config.WxMpProperties; |  | ||||||
| import cn.iocoder.yudao.module.mp.controller.admin.fansmsg.vo.WxFansMsgCreateReqVO; | import cn.iocoder.yudao.module.mp.controller.admin.fansmsg.vo.WxFansMsgCreateReqVO; | ||||||
| import cn.iocoder.yudao.module.mp.dal.dataobject.account.WxAccountDO; | import cn.iocoder.yudao.module.mp.dal.dataobject.account.WxAccountDO; | ||||||
| import cn.iocoder.yudao.module.mp.service.account.WxAccountService; | import cn.iocoder.yudao.module.mp.service.account.WxAccountService; | ||||||
| import cn.iocoder.yudao.module.mp.service.fansmsg.WxFansMsgService; | import cn.iocoder.yudao.module.mp.service.fansmsg.WxFansMsgService; | ||||||
| import cn.iocoder.yudao.module.mp.service.receivetext.WxReceiveTextService; |  | ||||||
| import cn.iocoder.yudao.module.mp.service.texttemplate.WxTextTemplateService; |  | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import me.chanjar.weixin.common.api.WxConsts; | import me.chanjar.weixin.common.api.WxConsts; | ||||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||||
| @@ -102,7 +99,7 @@ public class MsgHandler implements WxMpMessageHandler { | |||||||
|                             if (!downloadDir.exists()) { |                             if (!downloadDir.exists()) { | ||||||
|                                 downloadDir.mkdirs(); |                                 downloadDir.mkdirs(); | ||||||
|                             } |                             } | ||||||
|                             String filepath = downloadDirStr + String.valueOf(System.currentTimeMillis()) + ".png"; |                             String filepath = downloadDirStr + System.currentTimeMillis() + ".png"; | ||||||
|                             //微信pic url下载到本地,防止失效 |                             //微信pic url下载到本地,防止失效 | ||||||
|                             long size = HttpUtil.downloadFile(wxMessage.getPicUrl(), FileUtil.file(filepath)); |                             long size = HttpUtil.downloadFile(wxMessage.getPicUrl(), FileUtil.file(filepath)); | ||||||
|                             log.info("download pic size : {}", size); |                             log.info("download pic size : {}", size); | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package cn.iocoder.yudao.module.mp.mq.costomer.dict; | package cn.iocoder.yudao.module.mp.mq.costomer; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; | import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; | ||||||
| import cn.iocoder.yudao.module.mp.config.WxMpConfig; | import cn.iocoder.yudao.module.mp.mq.message.WxConfigDataRefreshMessage; | ||||||
| import cn.iocoder.yudao.module.mp.mq.message.dict.WxConfigDataRefreshMessage; | import cn.iocoder.yudao.module.mp.service.account.WxAccountService; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
|  |  | ||||||
| @@ -18,12 +18,12 @@ import javax.annotation.Resource; | |||||||
| public class WxConfigDataRefreshConsumer extends AbstractChannelMessageListener<WxConfigDataRefreshMessage> { | public class WxConfigDataRefreshConsumer extends AbstractChannelMessageListener<WxConfigDataRefreshMessage> { | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private WxMpConfig wxMpConfig; |     private WxAccountService wxAccountService; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void onMessage(WxConfigDataRefreshMessage message) { |     public void onMessage(WxConfigDataRefreshMessage message) { | ||||||
|         log.info("[onMessage][收到 WxConfigData 刷新消息]"); |         log.info("[onMessage][收到 WxConfigData 刷新消息]"); | ||||||
|         wxMpConfig.initWxConfig(); |         wxAccountService.initLoadWxMpConfigStorages(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| package cn.iocoder.yudao.module.mp.mq.message.dict; | package cn.iocoder.yudao.module.mp.mq.message; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage; | import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package cn.iocoder.yudao.module.mp.mq.producer.dict; | package cn.iocoder.yudao.module.mp.mq.producer; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | ||||||
| import cn.iocoder.yudao.module.mp.mq.message.dict.WxConfigDataRefreshMessage; | import cn.iocoder.yudao.module.mp.mq.message.WxConfigDataRefreshMessage; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
|  |  | ||||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||||
|   | |||||||
| @@ -81,4 +81,9 @@ public interface WxAccountService { | |||||||
|      * @return |      * @return | ||||||
|      */ |      */ | ||||||
|     WxAccountDO findBy(SFunction<WxAccountDO, ?> field, Object val); |     WxAccountDO findBy(SFunction<WxAccountDO, ?> field, Object val); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 初始化 | ||||||
|  |      */ | ||||||
|  |     void initLoadWxMpConfigStorages(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.mp.service.account; | |||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; | import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
|  | import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; | ||||||
| import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountCreateReqVO; | import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountCreateReqVO; | ||||||
| import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountExportReqVO; | import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountExportReqVO; | ||||||
| import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountPageReqVO; | import cn.iocoder.yudao.module.mp.controller.admin.account.vo.WxAccountPageReqVO; | ||||||
| @@ -10,30 +11,52 @@ import cn.iocoder.yudao.module.mp.convert.account.WxAccountConvert; | |||||||
| import cn.iocoder.yudao.module.mp.dal.dataobject.account.WxAccountDO; | import cn.iocoder.yudao.module.mp.dal.dataobject.account.WxAccountDO; | ||||||
| import cn.iocoder.yudao.module.mp.dal.mysql.account.WxAccountMapper; | import cn.iocoder.yudao.module.mp.dal.mysql.account.WxAccountMapper; | ||||||
| import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants; | import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants; | ||||||
| import cn.iocoder.yudao.module.mp.mq.producer.dict.WxMpConfigDataProducer; | import cn.iocoder.yudao.module.mp.mq.producer.WxMpConfigDataProducer; | ||||||
| import com.baomidou.mybatisplus.core.toolkit.support.SFunction; | import com.baomidou.mybatisplus.core.toolkit.support.SFunction; | ||||||
|  | import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; | ||||||
|  | import me.chanjar.weixin.mp.api.WxMpService; | ||||||
|  | import me.chanjar.weixin.mp.config.WxMpConfigStorage; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.data.redis.core.StringRedisTemplate; | ||||||
|  | import org.springframework.scheduling.annotation.Scheduled; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
|  | import org.springframework.util.CollectionUtils; | ||||||
| import org.springframework.validation.annotation.Validated; | import org.springframework.validation.annotation.Validated; | ||||||
|  |  | ||||||
|  | import javax.annotation.PostConstruct; | ||||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
|  | import java.util.HashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 公众号账户 Service 实现类 |  * 公众号账户 Service 实现类 | ||||||
|  * |  * | ||||||
|  * @author 芋道源码 |  * @author fengdan | ||||||
|  */ |  */ | ||||||
|  | @Slf4j | ||||||
| @Service | @Service | ||||||
| @Validated | @Validated | ||||||
| public class WxAccountServiceImpl implements WxAccountService { | public class WxAccountServiceImpl implements WxAccountService { | ||||||
|  |  | ||||||
|  |     private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; | ||||||
|     @Resource |     @Resource | ||||||
|     private WxAccountMapper wxAccountMapper; |     private WxAccountMapper wxAccountMapper; | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private WxMpConfigDataProducer wxMpConfigDataProducer; |     private WxMpConfigDataProducer wxMpConfigDataProducer; | ||||||
|  |     @Resource | ||||||
|  |     private StringRedisTemplate stringRedisTemplate; | ||||||
|  |     @Resource | ||||||
|  |     private WxMpService wxMpService; | ||||||
|  |     @Resource | ||||||
|  |     private WxMpProperties wxMpProperties; | ||||||
|  |     @Resource | ||||||
|  |     @Lazy // 注入自己,所以延迟加载 | ||||||
|  |     private WxAccountService self; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public Long createWxAccount(WxAccountCreateReqVO createReqVO) { |     public Long createWxAccount(WxAccountCreateReqVO createReqVO) { | ||||||
| @@ -94,4 +117,43 @@ public class WxAccountServiceImpl implements WxAccountService { | |||||||
|     public WxAccountDO findBy(SFunction<WxAccountDO, ?> field, Object val) { |     public WxAccountDO findBy(SFunction<WxAccountDO, ?> field, Object val) { | ||||||
|         return wxAccountMapper.selectOne(field, val); |         return wxAccountMapper.selectOne(field, val); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @PostConstruct | ||||||
|  |     @TenantIgnore | ||||||
|  |     @Override | ||||||
|  |     public void initLoadWxMpConfigStorages() { | ||||||
|  |         List<WxAccountDO> wxAccountList = this.wxAccountMapper.selectList(); | ||||||
|  |         if (CollectionUtils.isEmpty(wxAccountList)) { | ||||||
|  |             log.info("未读取到公众号配置,请在管理后台添加"); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         log.info("加载到{}条公众号配置", wxAccountList.size()); | ||||||
|  |         wxAccountList.forEach(account -> addAccountToRuntime(account, new RedisTemplateWxRedisOps(stringRedisTemplate))); | ||||||
|  |         log.info("公众号配置加载完成"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 添加账号到当前程序,如首次添加需初始化configStorageMap | ||||||
|  |      * | ||||||
|  |      * @param account 公众号 | ||||||
|  |      */ | ||||||
|  |     private synchronized void addAccountToRuntime(WxAccountDO account, RedisTemplateWxRedisOps redisOps) { | ||||||
|  |         String appId = account.getAppId(); | ||||||
|  |         WxMpConfigStorage wxMpRedisConfig = account.toWxMpConfigStorage(redisOps, wxMpProperties); | ||||||
|  |         try { | ||||||
|  |             wxMpService.addConfigStorage(appId, wxMpRedisConfig); | ||||||
|  |         } catch (NullPointerException e) { | ||||||
|  |             log.info("需初始化configStorageMap..."); | ||||||
|  |             Map<String, WxMpConfigStorage> configStorages = new HashMap<>(4); | ||||||
|  |             configStorages.put(appId, wxMpRedisConfig); | ||||||
|  |             wxMpService.setMultiConfigStorages(configStorages, appId); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | ||||||
|  |     public void schedulePeriodicRefresh() { | ||||||
|  |         self.initLoadWxMpConfigStorages(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 fengdan
					fengdan