From 275a1b10f671cedbb72d0170f3a68a1ed4efa9dd Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 1 Jan 2023 21:58:26 +0800 Subject: [PATCH] mp:增加 MpServiceFactory 管理创建的 MpService~ --- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/MpAccountController.java | 4 ++-- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/account/MpAccountDO.java | 9 --------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/account/MpAccountMapper.java | 6 ++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/MpConfiguration.java | 46 ++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java | 38 ++++++++++++++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/package-info.java | 8 ++++---- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/weixin/WxMpMessageRouterConfiguration.java | 106 ---------------------------------------------------------------------------------------------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/KfSessionHandler.java | 23 ----------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LocationHandler.java | 44 -------------------------------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LogHandler.java | 25 ------------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MenuHandler.java | 32 -------------------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MsgHandler.java | 172 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/NullHandler.java | 22 ---------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/ScanHandler.java | 22 ---------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/StoreCheckNotifyHandler.java | 27 --------------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/SubscribeHandler.java | 159 --------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/UnsubscribeHandler.java | 52 ---------------------------------------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/MpConfigRefreshConsumer.java | 29 +++++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/WxConfigDataRefreshConsumer.java | 29 ----------------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/MpConfigRefreshMessage.java | 19 +++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/WxConfigDataRefreshMessage.java | 19 ------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/MpConfigProducer.java | 26 ++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/WxMpConfigDataProducer.java | 26 -------------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountService.java | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountService.java | 71 ----------------------------------------------------------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountServiceImpl.java | 157 ------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/fansmsgres/NullHandler.java | 24 ++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/DefaultMessageHandler.java | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/KfSessionHandler.java | 27 +++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LocationHandler.java | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LogHandler.java | 30 ++++++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/MenuHandler.java | 37 +++++++++++++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/ScanHandler.java | 25 +++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/StoreCheckNotifyHandler.java | 26 ++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/SubscribeHandler.java | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/UnsubscribeHandler.java | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 38 files changed, 1183 insertions(+), 1001 deletions(-) create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/MpConfiguration.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/weixin/WxMpMessageRouterConfiguration.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/KfSessionHandler.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LocationHandler.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LogHandler.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MenuHandler.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MsgHandler.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/NullHandler.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/ScanHandler.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/StoreCheckNotifyHandler.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/SubscribeHandler.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/UnsubscribeHandler.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/MpConfigRefreshConsumer.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/WxConfigDataRefreshConsumer.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/MpConfigRefreshMessage.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/WxConfigDataRefreshMessage.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/MpConfigProducer.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/WxMpConfigDataProducer.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountService.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountService.java delete mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountServiceImpl.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/fansmsgres/NullHandler.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/DefaultMessageHandler.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/KfSessionHandler.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LocationHandler.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LogHandler.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/MenuHandler.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/ScanHandler.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/StoreCheckNotifyHandler.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/SubscribeHandler.java create mode 100644 yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/UnsubscribeHandler.java diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/MpAccountController.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/MpAccountController.java index a044e88..34ff08d 100644 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/MpAccountController.java +++ b/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; import cn.iocoder.yudao.module.mp.controller.admin.account.vo.*; import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert; import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; -import cn.iocoder.yudao.module.mp.service.account.WxAccountService; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; @@ -25,7 +25,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; public class MpAccountController { @Resource - private WxAccountService wxAccountService; + private MpAccountService wxAccountService; @PostMapping("/create") @ApiOperation("创建公众号账户") diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/account/MpAccountDO.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/account/MpAccountDO.java index adefbfc..8770275 100644 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/account/MpAccountDO.java +++ b/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 { */ private String remark; - // TODO 芋艿:需要迁移走 - 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; - } } diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/account/MpAccountMapper.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/account/MpAccountMapper.java index 7f03c2c..268bacc 100644 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/account/MpAccountMapper.java +++ b/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; import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.time.LocalDateTime; @Mapper public interface MpAccountMapper extends BaseMapperX { @@ -18,4 +21,7 @@ public interface MpAccountMapper extends BaseMapperX { .orderByDesc(MpAccountDO::getId)); } + @Select("SELECT COUNT(*) FROM mp_account WHERE update_time > #{maxUpdateTime}") + Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime); + } diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/MpConfiguration.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/MpConfiguration.java new file mode 100644 index 0000000..c568a3a --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/MpConfiguration.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.mp.framework.mp.config; + +import cn.iocoder.yudao.module.mp.framework.mp.core.DefaultMpServiceFactory; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import cn.iocoder.yudao.module.mp.service.fansmsgres.NullHandler; +import cn.iocoder.yudao.module.mp.service.handler.*; +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.StringRedisTemplate; + +/** + * 微信公众号的配置类 + * + * @author 芋道源码 + */ +@Configuration +public class MpConfiguration { + + @Bean + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + public RedisTemplateWxRedisOps redisTemplateWxRedisOps(StringRedisTemplate stringRedisTemplate) { + return new RedisTemplateWxRedisOps(stringRedisTemplate); + } + + @Bean + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + public MpServiceFactory mpServiceFactory(RedisTemplateWxRedisOps redisTemplateWxRedisOps, + WxMpProperties wxMpProperties, + LogHandler logHandler, + KfSessionHandler kfSessionHandler, + StoreCheckNotifyHandler storeCheckNotifyHandler, + MenuHandler menuHandler, + NullHandler nullHandler, + SubscribeHandler subscribeHandler, + UnsubscribeHandler unsubscribeHandler, + LocationHandler locationHandler, + ScanHandler scanHandler, + DefaultMessageHandler msgHandler) { + return new DefaultMpServiceFactory(redisTemplateWxRedisOps, wxMpProperties, + logHandler, kfSessionHandler, storeCheckNotifyHandler, menuHandler, + nullHandler, subscribeHandler, unsubscribeHandler, locationHandler, scanHandler, msgHandler); + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java new file mode 100644 index 0000000..09ff871 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java @@ -0,0 +1,158 @@ +package cn.iocoder.yudao.module.mp.framework.mp.core; + +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.service.fansmsgres.NullHandler; +import cn.iocoder.yudao.module.mp.service.handler.*; +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; +import com.google.common.collect.Maps; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; +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.WxMpRedisConfigImpl; +import me.chanjar.weixin.mp.constant.WxMpEventConstants; + +import java.util.List; +import java.util.Map; + +/** + * 默认的 {@link MpServiceFactory} 实现类 + * + * @author 芋道源码 + */ +@Slf4j +@RequiredArgsConstructor +public class DefaultMpServiceFactory implements MpServiceFactory { + + /** + * 微信 appId 与 WxMpService 的映射 + */ + private volatile Map mpServices; + /** + * 微信 appId 与 WxMpMessageRouter 的映射 + */ + private volatile Map mpMessageRouters; + + private final RedisTemplateWxRedisOps redisTemplateWxRedisOps; + private final WxMpProperties mpProperties; + + // ========== 各种 Handler ========== + + private final LogHandler logHandler; + private final KfSessionHandler kfSessionHandler; + private final StoreCheckNotifyHandler storeCheckNotifyHandler; + private final MenuHandler menuHandler; + private final NullHandler nullHandler; + private final SubscribeHandler subscribeHandler; + private final UnsubscribeHandler unsubscribeHandler; + private final LocationHandler locationHandler; + private final ScanHandler scanHandler; + private final DefaultMessageHandler msgHandler; + + @Override + public void init(List list) { + Map mpServices = Maps.newHashMap(); + Map mpMessageRouters = Maps.newHashMap(); + // 处理 list + list.forEach(account -> { + // 构建 WxMpService 对象 + WxMpService mpService = buildMpService(account); + mpServices.put(account.getAppId(), mpService); + // 构建 WxMpMessageRouter 对象 + WxMpMessageRouter mpMessageRouter = buildMpMessageRouter(mpService); + mpMessageRouters.put(account.getAppId(), mpMessageRouter); + }); + + // 设置到缓存 + this.mpServices = mpServices; + this.mpMessageRouters = mpMessageRouters; + } + + @Override + public WxMpService getMpService(String appId) { + return mpServices.get(appId); + } + + @Override + public WxMpMessageRouter getMpMessageRouter(String appId) { + return mpMessageRouters.get(appId); + } + + private WxMpService buildMpService(MpAccountDO account) { + // 第一步,创建 WxMpRedisConfigImpl 对象 + // TODO 芋艿:需要确认下,redis key 的存储结构 + WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl( + redisTemplateWxRedisOps, mpProperties.getConfigStorage().getKeyPrefix()); + configStorage.setAppId(account.getAppId()); + configStorage.setSecret(account.getAppSecret()); + configStorage.setToken(account.getToken()); + configStorage.setAesKey(account.getAesKey()); + + // 第二步,创建 WxMpService 对象 + WxMpService service = new WxMpServiceImpl(); + service.setWxMpConfigStorage(configStorage); + return null; + } + + private WxMpMessageRouter buildMpMessageRouter(WxMpService mpService) { + final WxMpMessageRouter newRouter = new WxMpMessageRouter(mpService); + // 记录所有事件的日志(异步执行) + 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; + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java new file mode 100644 index 0000000..ba8dd87 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.mp.framework.mp.core; + +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import me.chanjar.weixin.mp.api.WxMpMessageRouter; +import me.chanjar.weixin.mp.api.WxMpService; + +import java.util.List; + +/** + * {@link WxMpService} 工厂接口 + * + * @author 芋道源码 + */ +public interface MpServiceFactory { + + /** + * 基于微信公众号的账号,初始化对应的 WxMpService 与 WxMpMessageRouter 实例 + * + * @param list 公众号的账号列表 + */ + void init(List list); + + /** + * 获得 appId 对应的 WxMpService 实例 + * + * @param appId 微信公众号 appId + * @return WxMpService 实例 + */ + WxMpService getMpService(String appId); + + /** + * 获得 appId 对应的 WxMpMessageRouter 实例 + * + * @param appId 微信公众号 appId + * @return WxMpMessageRouter 实例 + */ + WxMpMessageRouter getMpMessageRouter(String appId); +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/package-info.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/package-info.java index f4ed18f..112ecdd 100644 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/package-info.java +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/package-info.java @@ -1,6 +1,6 @@ /** - * @date 2022/6/20 - * @author feng-dan - * @version 1.0 + * 属于 mp 模块的 framework 封装 + * + * @author 芋道源码 */ -package cn.iocoder.yudao.module.mp.framework; \ No newline at end of file +package cn.iocoder.yudao.module.mp.framework; diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/weixin/WxMpMessageRouterConfiguration.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/weixin/WxMpMessageRouterConfiguration.java deleted file mode 100644 index 3fc8d37..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/weixin/WxMpMessageRouterConfiguration.java +++ /dev/null @@ -1,106 +0,0 @@ -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; - } -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/KfSessionHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/KfSessionHandler.java deleted file mode 100644 index 47150d4..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/KfSessionHandler.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.yudao.module.mp.handler; - -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.mp.api.WxMpMessageHandler; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; -import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; -import org.springframework.stereotype.Component; - -import java.util.Map; - -@Component -public class KfSessionHandler implements WxMpMessageHandler { - - @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, - Map context, WxMpService wxMpService, - WxSessionManager sessionManager) { - //TODO 对会话做处理 - return null; - } - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LocationHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LocationHandler.java deleted file mode 100644 index af5a22b..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LocationHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -package cn.iocoder.yudao.module.mp.handler; - -import cn.iocoder.yudao.module.mp.builder.TextBuilder; -import lombok.extern.slf4j.Slf4j; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.mp.api.WxMpMessageHandler; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; -import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; -import org.springframework.stereotype.Component; - -import java.util.Map; - -import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType; - -@Component -@Slf4j -public class LocationHandler implements WxMpMessageHandler { - - @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, - Map context, WxMpService wxMpService, - WxSessionManager sessionManager) { - if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) { - //TODO 接收处理用户发送的地理位置消息 - try { - String content = "感谢反馈,您的的地理位置已收到!"; - return new TextBuilder().build(content, wxMessage, null); - } catch (Exception e) { - log.error("位置消息接收处理失败", e); - return null; - } - } - - //上报地理位置事件 - log.info("上报地理位置,纬度 : {},经度 : {},精度 : {}", - wxMessage.getLatitude(), wxMessage.getLongitude(), String.valueOf(wxMessage.getPrecision())); - - //TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用 - - return null; - } - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LogHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LogHandler.java deleted file mode 100644 index 58ae131..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/LogHandler.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.yudao.module.mp.handler; - -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import lombok.extern.slf4j.Slf4j; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.mp.api.WxMpMessageHandler; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; -import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; -import org.springframework.stereotype.Component; - -import java.util.Map; - -@Component -@Slf4j -public class LogHandler implements WxMpMessageHandler { - @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, - Map context, WxMpService wxMpService, - WxSessionManager sessionManager) { - log.info("接收到请求消息,内容:{}", JsonUtils.toJsonString(wxMessage)); - return null; - } - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MenuHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MenuHandler.java deleted file mode 100644 index 2eacfb0..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MenuHandler.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.mp.handler; - -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.mp.api.WxMpMessageHandler; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; -import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; -import org.springframework.stereotype.Component; - -import java.util.Map; - -import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType; - -@Component -public class MenuHandler implements WxMpMessageHandler { - - @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, - Map context, WxMpService weixinService, - WxSessionManager sessionManager) { - - String msg = wxMessage.getEventKey(); - if (MenuButtonType.VIEW.equals(wxMessage.getEvent())) { - return null; - } - - return WxMpXmlOutMessage.TEXT().content(msg) - .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()) - .build(); - } - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MsgHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MsgHandler.java deleted file mode 100644 index 87d2b2c..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/MsgHandler.java +++ /dev/null @@ -1,172 +0,0 @@ -package cn.iocoder.yudao.module.mp.handler; - -import cn.hutool.core.io.FileUtil; -import cn.hutool.http.HtmlUtil; -import cn.hutool.http.HttpUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.module.infra.api.file.FileApi; -import cn.iocoder.yudao.module.mp.builder.TextBuilder; -import cn.iocoder.yudao.module.mp.controller.admin.fansmsg.vo.WxFansMsgCreateReqVO; -import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; -import cn.iocoder.yudao.module.mp.service.account.WxAccountService; -import cn.iocoder.yudao.module.mp.service.fansmsg.WxFansMsgService; -import lombok.extern.slf4j.Slf4j; -import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.mp.api.WxMpMessageHandler; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; -import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; -import me.chanjar.weixin.mp.bean.result.WxMpUser; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.io.File; -import java.io.UnsupportedEncodingException; -import java.util.Map; - -@Component -@Slf4j -public class MsgHandler implements WxMpMessageHandler { - @Autowired - private WxAccountService wxAccountService; - - @Autowired - private WxFansMsgService wxFansMsgService; - - @Resource - private FileApi fileApi; - - @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, - Map context, WxMpService weixinService, - WxSessionManager sessionManager) { - log.info("收到信息内容:{}", JsonUtils.toJsonString(wxMessage)); - log.info("关键字:{}", wxMessage.getContent()); - - if (!wxMessage.getMsgType().equals(WxConsts.XmlMsgType.EVENT)) { - //可以选择将消息保存到本地 - - // 获取微信用户基本信息 - try { - WxMpUser wxmpUser = weixinService.getUserService() - .userInfo(wxMessage.getFromUser(), null); - if (wxmpUser != null) { - MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser()); - if (wxAccount != null) { - - if (wxMessage.getMsgType().equals(WxConsts.XmlMsgType.TEXT)) { - WxFansMsgCreateReqVO wxFansMsg = new WxFansMsgCreateReqVO(); - wxFansMsg.setOpenid(wxmpUser.getOpenId()); - try { - wxFansMsg.setNickname(wxmpUser.getNickname().getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - wxFansMsg.setHeadimgUrl(wxmpUser.getHeadImgUrl()); - wxFansMsg.setWxAccountId(String.valueOf(wxAccount.getId())); - wxFansMsg.setMsgType(wxMessage.getMsgType()); - wxFansMsg.setContent(wxMessage.getContent()); - wxFansMsg.setIsRes("1"); - - //组装回复消息 - String content = processContent(wxMessage); - content = HtmlUtil.escape(content); - wxFansMsg.setResContent(content); - - wxFansMsgService.createWxFansMsg(wxFansMsg); - return new TextBuilder().build(content, wxMessage, weixinService); - - } - if (wxMessage.getMsgType().equals(WxConsts.XmlMsgType.IMAGE)) { - WxFansMsgCreateReqVO wxFansMsg = new WxFansMsgCreateReqVO(); - wxFansMsg.setOpenid(wxmpUser.getOpenId()); - try { - wxFansMsg.setNickname(wxmpUser.getNickname().getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - wxFansMsg.setHeadimgUrl(wxmpUser.getHeadImgUrl()); - wxFansMsg.setWxAccountId(String.valueOf(wxAccount.getId())); - wxFansMsg.setMsgType(wxMessage.getMsgType()); - wxFansMsg.setMediaId(wxMessage.getMediaId()); - wxFansMsg.setPicUrl(wxMessage.getPicUrl()); - String downloadDirStr = fileApi.createFile(HttpUtil.downloadBytes(wxMessage.getPicUrl())); - File downloadDir = new File(downloadDirStr); - if (!downloadDir.exists()) { - downloadDir.mkdirs(); - } - String filepath = downloadDirStr + System.currentTimeMillis() + ".png"; - //微信pic url下载到本地,防止失效 - long size = HttpUtil.downloadFile(wxMessage.getPicUrl(), FileUtil.file(filepath)); - log.info("download pic size : {}", size); - wxFansMsg.setPicPath(filepath); - wxFansMsg.setIsRes("0"); - wxFansMsgService.createWxFansMsg(wxFansMsg); - } - - } - } - } catch (WxErrorException e) { - if (e.getError().getErrorCode() == 48001) { - log.info("该公众号没有获取用户信息权限!"); - } - } catch (Exception e) { - e.printStackTrace(); - } - - } - - //当用户输入关键词如“你好”,“客服”等,并且有客服在线时,把消息转发给在线客服 - try { - if (StringUtils.startsWithAny(wxMessage.getContent(), "你好", "客服") - && weixinService.getKefuService().kfOnlineList() - .getKfOnlineList().size() > 0) { - return WxMpXmlOutMessage.TRANSFER_CUSTOMER_SERVICE() - .fromUser(wxMessage.getToUser()) - .toUser(wxMessage.getFromUser()).build(); - } - } catch (WxErrorException e) { - e.printStackTrace(); - } - - //组装默认回复消息 - return new TextBuilder().build("测试", wxMessage, weixinService); - } - - - //处理回复信息,优先级,关键字、智能机器人、默认值 - String processContent(WxMpXmlMessage wxMessage) { - String content = ""; - /* content = processReceiveTextContent(wxMessage); - if(StringUtils.isNotBlank( content )){ - return content; - } - - content = defaultResponseContent;*/ - return content; - } - - //处理关键字 - String processReceiveTextContent(WxMpXmlMessage wxMessage) { - String content = ""; - /* WxAccountDO wxAccount = wxAccountService.findBy( WxAccountDO::getAccount,wxMessage.getToUser()); - if(wxAccount != null){ - WxReceiveText wxReceiveTextTpl = new WxReceiveText(); - wxReceiveTextTpl.setWxAccountId( String.valueOf( wxAccount.getId() ) ); - wxReceiveTextTpl.setReceiveText( wxMessage.getContent() ); - List wxReceiveTextList = wxReceiveTextService.findListByReceiveTest( wxReceiveTextTpl ); - if(wxReceiveTextList != null && wxReceiveTextList.size() > 0){ - WxReceiveText wxReceiveText = wxReceiveTextList.get( 0 ); - WxTextTemplate wxTextTemplate = wxTextTemplateService.findById( Integer.parseInt( wxReceiveText.getTplId() ) ); - content = wxTextTemplate.getContent(); - } - }*/ - return content; - } - - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/NullHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/NullHandler.java deleted file mode 100644 index abc9076..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/NullHandler.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.mp.handler; - -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.mp.api.WxMpMessageHandler; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; -import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; -import org.springframework.stereotype.Component; - -import java.util.Map; - -@Component -public class NullHandler implements WxMpMessageHandler { - - @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, - Map context, WxMpService wxMpService, - WxSessionManager sessionManager) { - return null; - } - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/ScanHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/ScanHandler.java deleted file mode 100644 index 20d0c0e..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/ScanHandler.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.mp.handler; - -import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.mp.api.WxMpMessageHandler; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; -import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; -import org.springframework.stereotype.Component; - -import java.util.Map; - -@Component -public class ScanHandler implements WxMpMessageHandler { - - @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map map, - WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException { - // 扫码事件处理 - return null; - } -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/StoreCheckNotifyHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/StoreCheckNotifyHandler.java deleted file mode 100644 index 52715c5..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/StoreCheckNotifyHandler.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.iocoder.yudao.module.mp.handler; - -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.mp.api.WxMpMessageHandler; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; -import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; -import org.springframework.stereotype.Component; - -import java.util.Map; - -/** - * 门店审核事件处理 - * - */ -@Component -public class StoreCheckNotifyHandler implements WxMpMessageHandler { - - @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, - Map context, WxMpService wxMpService, - WxSessionManager sessionManager) { - // TODO 处理门店审核事件 - return null; - } - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/SubscribeHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/SubscribeHandler.java deleted file mode 100644 index 606fa32..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/SubscribeHandler.java +++ /dev/null @@ -1,159 +0,0 @@ -package cn.iocoder.yudao.module.mp.handler; - -import cn.hutool.core.date.DateUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.module.mp.builder.TextBuilder; -import cn.iocoder.yudao.module.mp.controller.admin.accountfans.vo.WxAccountFansCreateReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.accountfans.vo.WxAccountFansUpdateReqVO; -import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; -import cn.iocoder.yudao.module.mp.dal.dataobject.accountfans.WxAccountFansDO; -import cn.iocoder.yudao.module.mp.dal.dataobject.subscribetext.WxSubscribeTextDO; -import cn.iocoder.yudao.module.mp.dal.dataobject.texttemplate.WxTextTemplateDO; -import cn.iocoder.yudao.module.mp.service.account.WxAccountService; -import cn.iocoder.yudao.module.mp.service.accountfans.WxAccountFansService; -import cn.iocoder.yudao.module.mp.service.accountfanstag.WxAccountFansTagService; -import cn.iocoder.yudao.module.mp.service.subscribetext.WxSubscribeTextService; -import cn.iocoder.yudao.module.mp.service.texttemplate.WxTextTemplateService; -import lombok.extern.slf4j.Slf4j; -import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.mp.api.WxMpMessageHandler; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; -import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; -import me.chanjar.weixin.mp.bean.result.WxMpUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.io.UnsupportedEncodingException; -import java.util.Map; - -@Component -@Slf4j -public class SubscribeHandler implements WxMpMessageHandler { - - @Autowired - private WxTextTemplateService wxTextTemplateService; - - @Autowired - private WxAccountService wxAccountService; - - @Autowired - private WxSubscribeTextService wxSubscribeTextService; - - @Autowired - private WxAccountFansService wxAccountFansService; - - @Autowired - private WxAccountFansTagService wxAccountFansTagService; - - @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, - Map context, WxMpService weixinService, - WxSessionManager sessionManager) throws WxErrorException { - - log.info("新关注用户 OPENID: " + wxMessage.getFromUser()); - - // 获取微信用户基本信息 - try { - WxMpUser wxmpUser = weixinService.getUserService() - .userInfo(wxMessage.getFromUser(), null); - if (wxmpUser != null) { - // 可以添加关注用户到本地数据库 - MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser()); - if (wxAccount != null) { - WxAccountFansDO wxAccountFans = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, wxmpUser.getOpenId()); - if (wxAccountFans == null) {//insert - WxAccountFansCreateReqVO wxAccountFansCreateReqVO = new WxAccountFansCreateReqVO(); - wxAccountFansCreateReqVO.setOpenid(wxmpUser.getOpenId()); - wxAccountFansCreateReqVO.setSubscribeStatus(wxmpUser.getSubscribe() ? "1" : "0"); - wxAccountFansCreateReqVO.setSubscribeTime(DateUtil.date(wxmpUser.getSubscribeTime() * 1000L)); - try { - wxAccountFansCreateReqVO.setNickname(wxmpUser.getNickname().getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - wxAccountFansCreateReqVO.setLanguage(wxmpUser.getLanguage()); - wxAccountFansCreateReqVO.setHeadimgUrl(wxmpUser.getHeadImgUrl()); - wxAccountFansCreateReqVO.setRemark(wxmpUser.getRemark()); - wxAccountFansCreateReqVO.setWxAccountId(String.valueOf(wxAccount.getId())); - wxAccountFansCreateReqVO.setWxAccountAppid(wxAccount.getAppId()); - wxAccountFansService.createWxAccountFans(wxAccountFansCreateReqVO); - - //process tags - wxAccountFansTagService.processFansTags(wxAccount, wxmpUser); - - } else {//update - WxAccountFansUpdateReqVO wxAccountFansUpdateReqVO = new WxAccountFansUpdateReqVO(); - wxAccountFansUpdateReqVO.setId(wxAccountFans.getId()); - wxAccountFansUpdateReqVO.setOpenid(wxmpUser.getOpenId()); - wxAccountFansUpdateReqVO.setSubscribeStatus(wxmpUser.getSubscribe() ? "1" : "0"); - wxAccountFansUpdateReqVO.setSubscribeTime(DateUtil.date(wxmpUser.getSubscribeTime() * 1000L)); - try { - wxAccountFans.setNickname(wxmpUser.getNickname().getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - wxAccountFansUpdateReqVO.setLanguage(wxmpUser.getLanguage()); - wxAccountFansUpdateReqVO.setHeadimgUrl(wxmpUser.getHeadImgUrl()); - wxAccountFansUpdateReqVO.setRemark(wxmpUser.getRemark()); - wxAccountFansUpdateReqVO.setWxAccountId(String.valueOf(wxAccount.getId())); - wxAccountFansUpdateReqVO.setWxAccountAppid(wxAccount.getAppId()); - wxAccountFansService.updateWxAccountFans(wxAccountFansUpdateReqVO); - - //process tags - wxAccountFansTagService.processFansTags(wxAccount, wxmpUser); - - } - } - - } - } catch (WxErrorException e) { - if (e.getError().getErrorCode() == 48001) { - log.info("该公众号没有获取用户信息权限!"); - } - } - - - WxMpXmlOutMessage responseResult = null; - try { - responseResult = this.handleSpecial(wxMessage); - } catch (Exception e) { - log.error(e.getMessage(), e); - } - - if (responseResult != null) { - return responseResult; - } - - try { - String content = "感谢关注!";//默认 - MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser()); - if (wxAccount != null) { - WxSubscribeTextDO wxSubscribeText = wxSubscribeTextService.findBy(WxSubscribeTextDO::getWxAccountId, String.valueOf(wxAccount.getId())); - if (wxSubscribeText != null) { - WxTextTemplateDO wxTextTemplate = wxTextTemplateService.getWxTextTemplate(Integer.parseInt(wxSubscribeText.getTplId())); - if (wxTextTemplate != null) { - content = wxTextTemplate.getContent(); - } - } - } - log.info("wxMessage : {}", JsonUtils.toJsonString(wxMessage)); - return new TextBuilder().build(content, wxMessage, weixinService); - } catch (Exception e) { - log.error(e.getMessage(), e); - } - - return null; - } - - /** - * 处理特殊请求,比如如果是扫码进来的,可以做相应处理 - */ - private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage) - throws Exception { - //TODO - return null; - } - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/UnsubscribeHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/UnsubscribeHandler.java deleted file mode 100644 index b9d81f4..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/handler/UnsubscribeHandler.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.yudao.module.mp.handler; - -import cn.iocoder.yudao.module.mp.controller.admin.accountfans.vo.WxAccountFansUpdateReqVO; -import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; -import cn.iocoder.yudao.module.mp.dal.dataobject.accountfans.WxAccountFansDO; -import cn.iocoder.yudao.module.mp.service.account.WxAccountService; -import cn.iocoder.yudao.module.mp.service.accountfans.WxAccountFansService; -import lombok.extern.slf4j.Slf4j; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.mp.api.WxMpMessageHandler; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; -import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.Map; - -@Component -@Slf4j -public class UnsubscribeHandler implements WxMpMessageHandler { - - @Autowired - private WxAccountService wxAccountService; - - @Autowired - private WxAccountFansService wxAccountFansService; - - @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, - Map context, WxMpService wxMpService, - WxSessionManager sessionManager) { - String openId = wxMessage.getFromUser(); - log.info("取消关注用户 OPENID: " + openId); - // TODO 可以更新本地数据库为取消关注状态 - - MpAccountDO wxAccountDO = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser()); - if (wxAccountDO != null) { - WxAccountFansDO wxAccountFansDO = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, openId); - if (wxAccountFansDO != null) { - WxAccountFansUpdateReqVO wxAccountFansUpdateReqVO = new WxAccountFansUpdateReqVO(); - wxAccountFansUpdateReqVO.setId(wxAccountDO.getId()); - wxAccountFansDO.setSubscribeStatus("0");//取消订阅 - wxAccountFansService.updateWxAccountFans(wxAccountFansUpdateReqVO); - } - } - - - return null; - } - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/MpConfigRefreshConsumer.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/MpConfigRefreshConsumer.java new file mode 100644 index 0000000..1b9caed --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/MpConfigRefreshConsumer.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.mp.mq.costomer; + +import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; +import cn.iocoder.yudao.module.mp.mq.message.MpConfigRefreshMessage; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 针对 {@link MpConfigRefreshMessage} 的消费者 + * + * @author lyz + */ +@Component +@Slf4j +public class MpConfigRefreshConsumer extends AbstractChannelMessageListener { + + @Resource + private MpAccountService wxAccountService; + + @Override + public void onMessage(MpConfigRefreshMessage message) { + log.info("[onMessage][收到 MpConfig 刷新消息]"); + wxAccountService.initLocalCache(); + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/WxConfigDataRefreshConsumer.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/WxConfigDataRefreshConsumer.java deleted file mode 100644 index 2f0863b..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/costomer/WxConfigDataRefreshConsumer.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.mp.mq.costomer; - -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.yudao.module.mp.mq.message.WxConfigDataRefreshMessage; -import cn.iocoder.yudao.module.mp.service.account.WxAccountService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * 针对 {@link WxConfigDataRefreshMessage} 的消费者 - * - * @author lyz - */ -@Component -@Slf4j -public class WxConfigDataRefreshConsumer extends AbstractChannelMessageListener { - - @Resource - private WxAccountService wxAccountService; - - @Override - public void onMessage(WxConfigDataRefreshMessage message) { - log.info("[onMessage][收到 WxConfigData 刷新消息]"); - wxAccountService.initLoadWxMpConfigStorages(); - } - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/MpConfigRefreshMessage.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/MpConfigRefreshMessage.java new file mode 100644 index 0000000..13bcc73 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/MpConfigRefreshMessage.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.mp.mq.message; + +import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 微信配置数据刷新 Message + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class MpConfigRefreshMessage extends AbstractChannelMessage { + + @Override + public String getChannel() { + return "mp.config-data.refresh"; + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/WxConfigDataRefreshMessage.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/WxConfigDataRefreshMessage.java deleted file mode 100644 index 4838260..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/WxConfigDataRefreshMessage.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.module.mp.mq.message; - -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 微信配置数据刷新 Message - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class WxConfigDataRefreshMessage extends AbstractChannelMessage { - - @Override - public String getChannel() { - return "wechat-mp.wx-config-data.refresh"; - } - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/MpConfigProducer.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/MpConfigProducer.java new file mode 100644 index 0000000..f64d33c --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/MpConfigProducer.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.mp.mq.producer; + +import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; +import cn.iocoder.yudao.module.mp.mq.message.MpConfigRefreshMessage; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 微信配置数据相关消息的 Producer + */ +@Component +public class MpConfigProducer { + + @Resource + private RedisMQTemplate redisMQTemplate; + + /** + * 发送 {@link MpConfigRefreshMessage} 消息 + */ + public void sendDictDataRefreshMessage() { + MpConfigRefreshMessage message = new MpConfigRefreshMessage(); + redisMQTemplate.send(message); + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/WxMpConfigDataProducer.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/WxMpConfigDataProducer.java deleted file mode 100644 index d765b9a..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/WxMpConfigDataProducer.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.mp.mq.producer; - -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; -import cn.iocoder.yudao.module.mp.mq.message.WxConfigDataRefreshMessage; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * 微信配置数据相关消息的 Producer - */ -@Component -public class WxMpConfigDataProducer { - - @Resource - private RedisMQTemplate redisMQTemplate; - - /** - * 发送 {@link WxConfigDataRefreshMessage} 消息 - */ - public void sendDictDataRefreshMessage() { - WxConfigDataRefreshMessage message = new WxConfigDataRefreshMessage(); - redisMQTemplate.send(message); - } - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountService.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountService.java new file mode 100644 index 0000000..b242c30 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountService.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.mp.service.account; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountUpdateReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; + +import javax.validation.Valid; + +/** + * 公众号账户 Service 接口 + * + * @author 芋道源码 + */ +public interface MpAccountService { + + /** + * 初始化缓存 + */ + void initLocalCache(); + + /** + * 创建公众号账户 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createAccount(@Valid MpAccountCreateReqVO createReqVO); + + /** + * 更新公众号账户 + * + * @param updateReqVO 更新信息 + */ + void updateAccount(@Valid MpAccountUpdateReqVO updateReqVO); + + /** + * 删除公众号账户 + * + * @param id 编号 + */ + void deleteAccount(Long id); + + /** + * 获得公众号账户 + * + * @param id 编号 + * @return 公众号账户 + */ + MpAccountDO getAccount(Long id); + + /** + * 获得公众号账户分页 + * + * @param pageReqVO 分页查询 + * @return 公众号账户分页 + */ + PageResult getAccountPage(MpAccountPageReqVO pageReqVO); + + // TODO 芋艿:去除这样的方法 + /** + * 查询账户 + * + * @param field + * @param val + * @return + */ + MpAccountDO findBy(SFunction field, Object val); + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java new file mode 100644 index 0000000..e6b6b77 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java @@ -0,0 +1,159 @@ +package cn.iocoder.yudao.module.mp.service.account; + +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountUpdateReqVO; +import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper; +import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import cn.iocoder.yudao.module.mp.mq.producer.MpConfigProducer; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + + +/** + * 公众号账户 Service 实现类 + * + * @author fengdan + */ +@Slf4j +@Service +@Validated +public class MpAccountServiceImpl implements MpAccountService { + + /** + * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 + * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 + */ + private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; + + /** + * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新 + */ + @Getter + private volatile LocalDateTime maxUpdateTime; + + @Resource + private MpAccountMapper mpAccountMapper; + + @Resource + @Lazy // 延迟加载,解决循环依赖的问题 + private MpServiceFactory mpServiceFactory; + + @Resource + private MpConfigProducer mpConfigDataProducer; + + @Override + @PostConstruct + public void initLocalCache() { + initLocalCacheIfUpdate(null); + } + + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) + public void schedulePeriodicRefresh() { + initLocalCacheIfUpdate(this.maxUpdateTime); + } + + /** + * 刷新本地缓存 + * + * @param maxUpdateTime 最大更新时间 + * 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存 + * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存 + */ + private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) { + // 注意:忽略自动多租户,因为要全局初始化缓存 + TenantUtils.executeIgnore(() -> { + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。 + // 如果没有增量的数据变化,则不进行本地缓存的刷新 + if (maxUpdateTime != null + && mpAccountMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) { + log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime); + return; + } + List accounts = mpAccountMapper.selectList(); + log.info("[initLocalCacheIfUpdate][缓存公众号账号,数量为:{}]", accounts.size()); + + // 第二步:构建缓存。创建或更新支付 Client + mpServiceFactory.init(accounts); + + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。 + this.maxUpdateTime = CollectionUtils.getMaxValue(accounts, MpAccountDO::getUpdateTime); + }); + } + + @Override + public Long createAccount(MpAccountCreateReqVO createReqVO) { + // TODO 芋艿:校验唯一性 + // 插入 + MpAccountDO wxAccount = MpAccountConvert.INSTANCE.convert(createReqVO); + mpAccountMapper.insert(wxAccount); + + // TODO 芋艿:刷新的方式 + mpConfigDataProducer.sendDictDataRefreshMessage(); + // 返回 + return wxAccount.getId(); + } + + @Override + public void updateAccount(MpAccountUpdateReqVO updateReqVO) { + // TODO 芋艿:校验唯一性 + // 校验存在 + validateWxAccountExists(updateReqVO.getId()); + // 更新 + MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO); + mpAccountMapper.updateById(updateObj); + + // TODO 芋艿:刷新的方式 + mpConfigDataProducer.sendDictDataRefreshMessage(); + } + + @Override + public void deleteAccount(Long id) { + // 校验存在 + validateWxAccountExists(id); + // 删除 + mpAccountMapper.deleteById(id); + + // TODO 芋艿:刷新的方式 + mpConfigDataProducer.sendDictDataRefreshMessage(); + } + + private void validateWxAccountExists(Long id) { + if (mpAccountMapper.selectById(id) == null) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.WX_ACCOUNT_NOT_EXISTS); + } + } + + @Override + public MpAccountDO getAccount(Long id) { + return mpAccountMapper.selectById(id); + } + + @Override + public PageResult getAccountPage(MpAccountPageReqVO pageReqVO) { + return mpAccountMapper.selectPage(pageReqVO); + } + + @Override + public MpAccountDO findBy(SFunction field, Object val) { + return mpAccountMapper.selectOne(field, val); + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountService.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountService.java deleted file mode 100644 index c832e69..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountService.java +++ /dev/null @@ -1,71 +0,0 @@ -package cn.iocoder.yudao.module.mp.service.account; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountUpdateReqVO; -import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; -import com.baomidou.mybatisplus.core.toolkit.support.SFunction; - -import javax.validation.Valid; - -/** - * 公众号账户 Service 接口 - * - * @author 芋道源码 - */ -public interface WxAccountService { - - /** - * 创建公众号账户 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createAccount(@Valid MpAccountCreateReqVO createReqVO); - - /** - * 更新公众号账户 - * - * @param updateReqVO 更新信息 - */ - void updateAccount(@Valid MpAccountUpdateReqVO updateReqVO); - - /** - * 删除公众号账户 - * - * @param id 编号 - */ - void deleteAccount(Long id); - - /** - * 获得公众号账户 - * - * @param id 编号 - * @return 公众号账户 - */ - MpAccountDO getAccount(Long id); - - /** - * 获得公众号账户分页 - * - * @param pageReqVO 分页查询 - * @return 公众号账户分页 - */ - PageResult getAccountPage(MpAccountPageReqVO pageReqVO); - - // TODO 芋艿:去除这样的方法 - /** - * 查询账户 - * - * @param field - * @param val - * @return - */ - MpAccountDO findBy(SFunction field, Object val); - - /** - * 初始化 - */ - void initLoadWxMpConfigStorages(); -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountServiceImpl.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountServiceImpl.java deleted file mode 100644 index 094d5b3..0000000 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/WxAccountServiceImpl.java +++ /dev/null @@ -1,157 +0,0 @@ -package cn.iocoder.yudao.module.mp.service.account; - -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; -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.MpAccountCreateReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountUpdateReqVO; -import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert; -import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; -import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper; -import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants; -import cn.iocoder.yudao.module.mp.mq.producer.WxMpConfigDataProducer; -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.util.CollectionUtils; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.PostConstruct; -import javax.annotation.Resource; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - - -/** - * 公众号账户 Service 实现类 - * - * @author fengdan - */ -@Slf4j -@Service -@Validated -public class WxAccountServiceImpl implements WxAccountService { - - private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; - - @Resource - private MpAccountMapper wxAccountMapper; - @Resource - private WxMpConfigDataProducer wxMpConfigDataProducer; - @Resource - private StringRedisTemplate stringRedisTemplate; - @Resource - private WxMpService wxMpService; - @Resource - private WxMpProperties wxMpProperties; - @Resource - @Lazy // 注入自己,所以延迟加载 - private WxAccountService self; - - @Override - public Long createAccount(MpAccountCreateReqVO createReqVO) { - // TODO 芋艿:校验唯一性 - // 插入 - MpAccountDO wxAccount = MpAccountConvert.INSTANCE.convert(createReqVO); - wxAccountMapper.insert(wxAccount); - - // TODO 芋艿:刷新的方式 - wxMpConfigDataProducer.sendDictDataRefreshMessage(); - // 返回 - return wxAccount.getId(); - } - - @Override - public void updateAccount(MpAccountUpdateReqVO updateReqVO) { - // TODO 芋艿:校验唯一性 - // 校验存在 - validateWxAccountExists(updateReqVO.getId()); - // 更新 - MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO); - wxAccountMapper.updateById(updateObj); - - // TODO 芋艿:刷新的方式 - wxMpConfigDataProducer.sendDictDataRefreshMessage(); - } - - @Override - public void deleteAccount(Long id) { - // 校验存在 - validateWxAccountExists(id); - // 删除 - wxAccountMapper.deleteById(id); - - // TODO 芋艿:刷新的方式 - wxMpConfigDataProducer.sendDictDataRefreshMessage(); - } - - private void validateWxAccountExists(Long id) { - if (wxAccountMapper.selectById(id) == null) { - throw ServiceExceptionUtil.exception(ErrorCodeConstants.WX_ACCOUNT_NOT_EXISTS); - } - } - - @Override - public MpAccountDO getAccount(Long id) { - return wxAccountMapper.selectById(id); - } - - @Override - public PageResult getAccountPage(MpAccountPageReqVO pageReqVO) { - return wxAccountMapper.selectPage(pageReqVO); - } - - @Override - public MpAccountDO findBy(SFunction field, Object val) { - return wxAccountMapper.selectOne(field, val); - } - - @PostConstruct - @TenantIgnore - @Override - public void initLoadWxMpConfigStorages() { - // TODO 芋艿:刷新的方式 - List 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(MpAccountDO 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 configStorages = new HashMap<>(4); - configStorages.put(appId, wxMpRedisConfig); - wxMpService.setMultiConfigStorages(configStorages, appId); - } - } - - @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) - public void schedulePeriodicRefresh() { - self.initLoadWxMpConfigStorages(); - } - - -} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/fansmsgres/NullHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/fansmsgres/NullHandler.java new file mode 100644 index 0000000..82e9b89 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/fansmsgres/NullHandler.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.mp.service.fansmsgres; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 点击菜单连接的事件处理器 + */ +@Component +public class NullHandler implements WxMpMessageHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService wxMpService, WxSessionManager sessionManager) { + return null; + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/DefaultMessageHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/DefaultMessageHandler.java new file mode 100644 index 0000000..6bd8766 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/DefaultMessageHandler.java @@ -0,0 +1,180 @@ +package cn.iocoder.yudao.module.mp.service.handler; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.http.HtmlUtil; +import cn.hutool.http.HttpUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.infra.api.file.FileApi; +import cn.iocoder.yudao.module.mp.builder.TextBuilder; +import cn.iocoder.yudao.module.mp.controller.admin.fansmsg.vo.WxFansMsgCreateReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import cn.iocoder.yudao.module.mp.service.fansmsg.WxFansMsgService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.util.Map; + +/** + * 默认所有消息的事件处理器 + * + * // TODO 芋艿:待实现 + */ +@Component +@Slf4j +public class DefaultMessageHandler implements WxMpMessageHandler { + + @Resource + @Lazy // 延迟加载,解决循环依赖的问题 + private MpAccountService mpAccountService; + + @Autowired + private WxFansMsgService wxFansMsgService; + + @Resource + private FileApi fileApi; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService weixinService, + WxSessionManager sessionManager) { + log.info("收到信息内容:{}", JsonUtils.toJsonString(wxMessage)); + log.info("关键字:{}", wxMessage.getContent()); + + if (!wxMessage.getMsgType().equals(WxConsts.XmlMsgType.EVENT)) { + //可以选择将消息保存到本地 + + // 获取微信用户基本信息 + try { + WxMpUser wxmpUser = weixinService.getUserService() + .userInfo(wxMessage.getFromUser(), null); + if (wxmpUser != null) { + MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser()); + if (wxAccount != null) { + + if (wxMessage.getMsgType().equals(WxConsts.XmlMsgType.TEXT)) { + WxFansMsgCreateReqVO wxFansMsg = new WxFansMsgCreateReqVO(); + wxFansMsg.setOpenid(wxmpUser.getOpenId()); + try { + wxFansMsg.setNickname(wxmpUser.getNickname().getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + wxFansMsg.setHeadimgUrl(wxmpUser.getHeadImgUrl()); + wxFansMsg.setWxAccountId(String.valueOf(wxAccount.getId())); + wxFansMsg.setMsgType(wxMessage.getMsgType()); + wxFansMsg.setContent(wxMessage.getContent()); + wxFansMsg.setIsRes("1"); + + //组装回复消息 + String content = processContent(wxMessage); + content = HtmlUtil.escape(content); + wxFansMsg.setResContent(content); + + wxFansMsgService.createWxFansMsg(wxFansMsg); + return new TextBuilder().build(content, wxMessage, weixinService); + + } + if (wxMessage.getMsgType().equals(WxConsts.XmlMsgType.IMAGE)) { + WxFansMsgCreateReqVO wxFansMsg = new WxFansMsgCreateReqVO(); + wxFansMsg.setOpenid(wxmpUser.getOpenId()); + try { + wxFansMsg.setNickname(wxmpUser.getNickname().getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + wxFansMsg.setHeadimgUrl(wxmpUser.getHeadImgUrl()); + wxFansMsg.setWxAccountId(String.valueOf(wxAccount.getId())); + wxFansMsg.setMsgType(wxMessage.getMsgType()); + wxFansMsg.setMediaId(wxMessage.getMediaId()); + wxFansMsg.setPicUrl(wxMessage.getPicUrl()); + String downloadDirStr = fileApi.createFile(HttpUtil.downloadBytes(wxMessage.getPicUrl())); + File downloadDir = new File(downloadDirStr); + if (!downloadDir.exists()) { + downloadDir.mkdirs(); + } + String filepath = downloadDirStr + System.currentTimeMillis() + ".png"; + //微信pic url下载到本地,防止失效 + long size = HttpUtil.downloadFile(wxMessage.getPicUrl(), FileUtil.file(filepath)); + log.info("download pic size : {}", size); + wxFansMsg.setPicPath(filepath); + wxFansMsg.setIsRes("0"); + wxFansMsgService.createWxFansMsg(wxFansMsg); + } + + } + } + } catch (WxErrorException e) { + if (e.getError().getErrorCode() == 48001) { + log.info("该公众号没有获取用户信息权限!"); + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + + //当用户输入关键词如“你好”,“客服”等,并且有客服在线时,把消息转发给在线客服 + try { + if (StringUtils.startsWithAny(wxMessage.getContent(), "你好", "客服") + && weixinService.getKefuService().kfOnlineList() + .getKfOnlineList().size() > 0) { + return WxMpXmlOutMessage.TRANSFER_CUSTOMER_SERVICE() + .fromUser(wxMessage.getToUser()) + .toUser(wxMessage.getFromUser()).build(); + } + } catch (WxErrorException e) { + e.printStackTrace(); + } + + //组装默认回复消息 + return new TextBuilder().build("测试", wxMessage, weixinService); + } + + + //处理回复信息,优先级,关键字、智能机器人、默认值 + String processContent(WxMpXmlMessage wxMessage) { + String content = ""; + /* content = processReceiveTextContent(wxMessage); + if(StringUtils.isNotBlank( content )){ + return content; + } + + content = defaultResponseContent;*/ + return content; + } + + //处理关键字 + String processReceiveTextContent(WxMpXmlMessage wxMessage) { + String content = ""; + /* WxAccountDO wxAccount = wxAccountService.findBy( WxAccountDO::getAccount,wxMessage.getToUser()); + if(wxAccount != null){ + WxReceiveText wxReceiveTextTpl = new WxReceiveText(); + wxReceiveTextTpl.setWxAccountId( String.valueOf( wxAccount.getId() ) ); + wxReceiveTextTpl.setReceiveText( wxMessage.getContent() ); + List wxReceiveTextList = wxReceiveTextService.findListByReceiveTest( wxReceiveTextTpl ); + if(wxReceiveTextList != null && wxReceiveTextList.size() > 0){ + WxReceiveText wxReceiveText = wxReceiveTextList.get( 0 ); + WxTextTemplate wxTextTemplate = wxTextTemplateService.findById( Integer.parseInt( wxReceiveText.getTplId() ) ); + content = wxTextTemplate.getContent(); + } + }*/ + return content; + } + + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/KfSessionHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/KfSessionHandler.java new file mode 100644 index 0000000..a432fcb --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/KfSessionHandler.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.mp.service.handler; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 接收客服会话管理的事件处理器 + * + * @author 芋道源码 + */ +@Component +public class KfSessionHandler implements WxMpMessageHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService wxMpService, WxSessionManager sessionManager) { + // TODO 对会话做处理 + return null; + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LocationHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LocationHandler.java new file mode 100644 index 0000000..3cfefbb --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LocationHandler.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.mp.service.handler; + +import cn.iocoder.yudao.module.mp.builder.TextBuilder; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType; + +/** + * 上报地理位置的事件处理器 + * + * // TODO @芋艿:需要实现一下~ + */ +@Component +@Slf4j +public class LocationHandler implements WxMpMessageHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService wxMpService, WxSessionManager sessionManager) { + if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) { + //TODO 接收处理用户发送的地理位置消息 + try { + String content = "感谢反馈,您的的地理位置已收到!"; + return new TextBuilder().build(content, wxMessage, null); + } catch (Exception e) { + log.error("位置消息接收处理失败", e); + return null; + } + } + + //上报地理位置事件 + log.info("上报地理位置,纬度 : {},经度 : {},精度 : {}", + wxMessage.getLatitude(), wxMessage.getLongitude(), String.valueOf(wxMessage.getPrecision())); + + //TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用 + + return null; + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LogHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LogHandler.java new file mode 100644 index 0000000..4e08f3c --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/LogHandler.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.mp.service.handler; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 保存微信消息的事件处理器 + * + * // TODO 芋艿:实现一下 + */ +@Component +@Slf4j +public class LogHandler implements WxMpMessageHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService wxMpService, WxSessionManager sessionManager) { + log.info("接收到请求消息,内容:{}", JsonUtils.toJsonString(wxMessage)); + return null; + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/MenuHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/MenuHandler.java new file mode 100644 index 0000000..9146b7f --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/MenuHandler.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.mp.service.handler; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType; + +/** + * 自定义菜单的事件处理器 + * + * // TODO 芋艿:待实现 + */ +@Component +public class MenuHandler implements WxMpMessageHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService weixinService, + WxSessionManager sessionManager) { + + String msg = wxMessage.getEventKey(); + if (MenuButtonType.VIEW.equals(wxMessage.getEvent())) { + return null; + } + + return WxMpXmlOutMessage.TEXT().content(msg) + .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()) + .build(); + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/ScanHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/ScanHandler.java new file mode 100644 index 0000000..030e857 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/ScanHandler.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.mp.service.handler; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 扫码的事件处理器 + */ +@Component +public class ScanHandler implements WxMpMessageHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map map, + WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException { + // 扫码事件处理 + return null; + } +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/StoreCheckNotifyHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/StoreCheckNotifyHandler.java new file mode 100644 index 0000000..9eb838e --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/StoreCheckNotifyHandler.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.mp.service.handler; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 门店审核事件的事件处理器 + */ +@Component +public class StoreCheckNotifyHandler implements WxMpMessageHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + // TODO 处理门店审核事件 + return null; + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/SubscribeHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/SubscribeHandler.java new file mode 100644 index 0000000..d189187 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/SubscribeHandler.java @@ -0,0 +1,167 @@ +package cn.iocoder.yudao.module.mp.service.handler; + +import cn.hutool.core.date.DateUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.mp.builder.TextBuilder; +import cn.iocoder.yudao.module.mp.controller.admin.accountfans.vo.WxAccountFansCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.accountfans.vo.WxAccountFansUpdateReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.accountfans.WxAccountFansDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.subscribetext.WxSubscribeTextDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.texttemplate.WxTextTemplateDO; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import cn.iocoder.yudao.module.mp.service.accountfans.WxAccountFansService; +import cn.iocoder.yudao.module.mp.service.accountfanstag.WxAccountFansTagService; +import cn.iocoder.yudao.module.mp.service.subscribetext.WxSubscribeTextService; +import cn.iocoder.yudao.module.mp.service.texttemplate.WxTextTemplateService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.io.UnsupportedEncodingException; +import java.util.Map; + +/** + * 关注的事件处理器 + * + * // TODO 芋艿:待实现 + */ +@Component +@Slf4j +public class SubscribeHandler implements WxMpMessageHandler { + + @Autowired + private WxTextTemplateService wxTextTemplateService; + + @Resource + @Lazy // 延迟加载,解决循环依赖的问题 + private MpAccountService mpAccountService; + + @Autowired + private WxSubscribeTextService wxSubscribeTextService; + + @Autowired + private WxAccountFansService wxAccountFansService; + + @Autowired + private WxAccountFansTagService wxAccountFansTagService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService weixinService, + WxSessionManager sessionManager) throws WxErrorException { + + log.info("新关注用户 OPENID: " + wxMessage.getFromUser()); + + // 获取微信用户基本信息 + try { + WxMpUser wxmpUser = weixinService.getUserService() + .userInfo(wxMessage.getFromUser(), null); + if (wxmpUser != null) { + // 可以添加关注用户到本地数据库 + MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser()); + if (wxAccount != null) { + WxAccountFansDO wxAccountFans = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, wxmpUser.getOpenId()); + if (wxAccountFans == null) {//insert + WxAccountFansCreateReqVO wxAccountFansCreateReqVO = new WxAccountFansCreateReqVO(); + wxAccountFansCreateReqVO.setOpenid(wxmpUser.getOpenId()); + wxAccountFansCreateReqVO.setSubscribeStatus(wxmpUser.getSubscribe() ? "1" : "0"); + wxAccountFansCreateReqVO.setSubscribeTime(DateUtil.date(wxmpUser.getSubscribeTime() * 1000L)); + try { + wxAccountFansCreateReqVO.setNickname(wxmpUser.getNickname().getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + wxAccountFansCreateReqVO.setLanguage(wxmpUser.getLanguage()); + wxAccountFansCreateReqVO.setHeadimgUrl(wxmpUser.getHeadImgUrl()); + wxAccountFansCreateReqVO.setRemark(wxmpUser.getRemark()); + wxAccountFansCreateReqVO.setWxAccountId(String.valueOf(wxAccount.getId())); + wxAccountFansCreateReqVO.setWxAccountAppid(wxAccount.getAppId()); + wxAccountFansService.createWxAccountFans(wxAccountFansCreateReqVO); + + //process tags + wxAccountFansTagService.processFansTags(wxAccount, wxmpUser); + + } else {//update + WxAccountFansUpdateReqVO wxAccountFansUpdateReqVO = new WxAccountFansUpdateReqVO(); + wxAccountFansUpdateReqVO.setId(wxAccountFans.getId()); + wxAccountFansUpdateReqVO.setOpenid(wxmpUser.getOpenId()); + wxAccountFansUpdateReqVO.setSubscribeStatus(wxmpUser.getSubscribe() ? "1" : "0"); + wxAccountFansUpdateReqVO.setSubscribeTime(DateUtil.date(wxmpUser.getSubscribeTime() * 1000L)); + try { + wxAccountFans.setNickname(wxmpUser.getNickname().getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + wxAccountFansUpdateReqVO.setLanguage(wxmpUser.getLanguage()); + wxAccountFansUpdateReqVO.setHeadimgUrl(wxmpUser.getHeadImgUrl()); + wxAccountFansUpdateReqVO.setRemark(wxmpUser.getRemark()); + wxAccountFansUpdateReqVO.setWxAccountId(String.valueOf(wxAccount.getId())); + wxAccountFansUpdateReqVO.setWxAccountAppid(wxAccount.getAppId()); + wxAccountFansService.updateWxAccountFans(wxAccountFansUpdateReqVO); + + //process tags + wxAccountFansTagService.processFansTags(wxAccount, wxmpUser); + + } + } + + } + } catch (WxErrorException e) { + if (e.getError().getErrorCode() == 48001) { + log.info("该公众号没有获取用户信息权限!"); + } + } + + + WxMpXmlOutMessage responseResult = null; + try { + responseResult = this.handleSpecial(wxMessage); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + + if (responseResult != null) { + return responseResult; + } + + try { + String content = "感谢关注!";//默认 + MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser()); + if (wxAccount != null) { + WxSubscribeTextDO wxSubscribeText = wxSubscribeTextService.findBy(WxSubscribeTextDO::getWxAccountId, String.valueOf(wxAccount.getId())); + if (wxSubscribeText != null) { + WxTextTemplateDO wxTextTemplate = wxTextTemplateService.getWxTextTemplate(Integer.parseInt(wxSubscribeText.getTplId())); + if (wxTextTemplate != null) { + content = wxTextTemplate.getContent(); + } + } + } + log.info("wxMessage : {}", JsonUtils.toJsonString(wxMessage)); + return new TextBuilder().build(content, wxMessage, weixinService); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + + return null; + } + + /** + * 处理特殊请求,比如如果是扫码进来的,可以做相应处理 + */ + private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage) + throws Exception { + //TODO + return null; + } + +} diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/UnsubscribeHandler.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/UnsubscribeHandler.java new file mode 100644 index 0000000..74e1b63 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/UnsubscribeHandler.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.mp.service.handler; + +import cn.iocoder.yudao.module.mp.controller.admin.accountfans.vo.WxAccountFansUpdateReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.accountfans.WxAccountFansDO; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import cn.iocoder.yudao.module.mp.service.accountfans.WxAccountFansService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 取消关注的事件处理器 + * + * // TODO 芋艿:待实现 + */ +@Component +@Slf4j +public class UnsubscribeHandler implements WxMpMessageHandler { + + @Resource + @Lazy // 延迟加载,解决循环依赖的问题 + private MpAccountService mpAccountService; + + @Autowired + private WxAccountFansService wxAccountFansService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + String openId = wxMessage.getFromUser(); + log.info("取消关注用户 OPENID: " + openId); + // TODO 可以更新本地数据库为取消关注状态 + + MpAccountDO wxAccountDO = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser()); + if (wxAccountDO != null) { + WxAccountFansDO wxAccountFansDO = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, openId); + if (wxAccountFansDO != null) { + WxAccountFansUpdateReqVO wxAccountFansUpdateReqVO = new WxAccountFansUpdateReqVO(); + wxAccountFansUpdateReqVO.setId(wxAccountDO.getId()); + wxAccountFansDO.setSubscribeStatus("0");//取消订阅 + wxAccountFansService.updateWxAccountFans(wxAccountFansUpdateReqVO); + } + } + + + return null; + } + +} -- libgit2 0.21.4