mp:增加 MpServiceFactory 管理创建的 MpService~
This commit is contained in:
parent
627cb39517
commit
275a1b10f6
|
@ -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("创建公众号账户")
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<MpAccountDO> {
|
||||
|
@ -18,4 +21,7 @@ public interface MpAccountMapper extends BaseMapperX<MpAccountDO> {
|
|||
.orderByDesc(MpAccountDO::getId));
|
||||
}
|
||||
|
||||
@Select("SELECT COUNT(*) FROM mp_account WHERE update_time > #{maxUpdateTime}")
|
||||
Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<String, WxMpService> mpServices;
|
||||
/**
|
||||
* 微信 appId 与 WxMpMessageRouter 的映射
|
||||
*/
|
||||
private volatile Map<String, WxMpMessageRouter> 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<MpAccountDO> list) {
|
||||
Map<String, WxMpService> mpServices = Maps.newHashMap();
|
||||
Map<String, WxMpMessageRouter> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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<MpAccountDO> list);
|
||||
|
||||
/**
|
||||
* 获得 appId 对应的 WxMpService 实例
|
||||
*
|
||||
* @param appId 微信公众号 appId
|
||||
* @return WxMpService 实例
|
||||
*/
|
||||
WxMpService getMpService(String appId);
|
||||
|
||||
/**
|
||||
* 获得 appId 对应的 WxMpMessageRouter 实例
|
||||
*
|
||||
* @param appId 微信公众号 appId
|
||||
* @return WxMpMessageRouter 实例
|
||||
*/
|
||||
WxMpMessageRouter getMpMessageRouter(String appId);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @date 2022/6/20
|
||||
* @author feng-dan
|
||||
* @version 1.0
|
||||
* 属于 mp 模块的 framework 封装
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
package cn.iocoder.yudao.module.mp.framework;
|
||||
package cn.iocoder.yudao.module.mp.framework;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<MpConfigRefreshMessage> {
|
||||
|
||||
@Resource
|
||||
private MpAccountService wxAccountService;
|
||||
|
||||
@Override
|
||||
public void onMessage(MpConfigRefreshMessage message) {
|
||||
log.info("[onMessage][收到 MpConfig 刷新消息]");
|
||||
wxAccountService.initLocalCache();
|
||||
}
|
||||
|
||||
}
|
|
@ -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<WxConfigDataRefreshMessage> {
|
||||
|
||||
@Resource
|
||||
private WxAccountService wxAccountService;
|
||||
|
||||
@Override
|
||||
public void onMessage(WxConfigDataRefreshMessage message) {
|
||||
log.info("[onMessage][收到 WxConfigData 刷新消息]");
|
||||
wxAccountService.initLoadWxMpConfigStorages();
|
||||
}
|
||||
|
||||
}
|
|
@ -9,11 +9,11 @@ import lombok.EqualsAndHashCode;
|
|||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class WxConfigDataRefreshMessage extends AbstractChannelMessage {
|
||||
public class MpConfigRefreshMessage extends AbstractChannelMessage {
|
||||
|
||||
@Override
|
||||
public String getChannel() {
|
||||
return "wechat-mp.wx-config-data.refresh";
|
||||
return "mp.config-data.refresh";
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
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 cn.iocoder.yudao.module.mp.mq.message.MpConfigRefreshMessage;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
@ -10,16 +10,16 @@ import javax.annotation.Resource;
|
|||
* 微信配置数据相关消息的 Producer
|
||||
*/
|
||||
@Component
|
||||
public class WxMpConfigDataProducer {
|
||||
public class MpConfigProducer {
|
||||
|
||||
@Resource
|
||||
private RedisMQTemplate redisMQTemplate;
|
||||
|
||||
/**
|
||||
* 发送 {@link WxConfigDataRefreshMessage} 消息
|
||||
* 发送 {@link MpConfigRefreshMessage} 消息
|
||||
*/
|
||||
public void sendDictDataRefreshMessage() {
|
||||
WxConfigDataRefreshMessage message = new WxConfigDataRefreshMessage();
|
||||
MpConfigRefreshMessage message = new MpConfigRefreshMessage();
|
||||
redisMQTemplate.send(message);
|
||||
}
|
||||
|
|
@ -14,7 +14,12 @@ import javax.validation.Valid;
|
|||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface WxAccountService {
|
||||
public interface MpAccountService {
|
||||
|
||||
/**
|
||||
* 初始化缓存
|
||||
*/
|
||||
void initLocalCache();
|
||||
|
||||
/**
|
||||
* 创建公众号账户
|
||||
|
@ -64,8 +69,4 @@ public interface WxAccountService {
|
|||
*/
|
||||
MpAccountDO findBy(SFunction<MpAccountDO, ?> field, Object val);
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
void initLoadWxMpConfigStorages();
|
||||
}
|
|
@ -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<MpAccountDO> 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<MpAccountDO> getAccountPage(MpAccountPageReqVO pageReqVO) {
|
||||
return mpAccountMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MpAccountDO findBy(SFunction<MpAccountDO, ?> field, Object val) {
|
||||
return mpAccountMapper.selectOne(field, val);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<MpAccountDO> getAccountPage(MpAccountPageReqVO pageReqVO) {
|
||||
return wxAccountMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MpAccountDO findBy(SFunction<MpAccountDO, ?> field, Object val) {
|
||||
return wxAccountMapper.selectOne(field, val);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
@TenantIgnore
|
||||
@Override
|
||||
public void initLoadWxMpConfigStorages() {
|
||||
// TODO 芋艿:刷新的方式
|
||||
List<MpAccountDO> 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<String, WxMpConfigStorage> configStorages = new HashMap<>(4);
|
||||
configStorages.put(appId, wxMpRedisConfig);
|
||||
wxMpService.setMultiConfigStorages(configStorages, appId);
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
|
||||
public void schedulePeriodicRefresh() {
|
||||
self.initLoadWxMpConfigStorages();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.yudao.module.mp.handler;
|
||||
package cn.iocoder.yudao.module.mp.service.fansmsgres;
|
||||
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
|
||||
|
@ -9,13 +9,15 @@ import org.springframework.stereotype.Component;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 点击菜单连接的事件处理器
|
||||
*/
|
||||
@Component
|
||||
public class NullHandler implements WxMpMessageHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
|
||||
WxMpService wxMpService, WxSessionManager sessionManager) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.yudao.module.mp.handler;
|
||||
package cn.iocoder.yudao.module.mp.service.handler;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.http.HtmlUtil;
|
||||
|
@ -8,7 +8,7 @@ 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.account.MpAccountService;
|
||||
import cn.iocoder.yudao.module.mp.service.fansmsg.WxFansMsgService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
|
@ -21,6 +21,7 @@ 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;
|
||||
|
@ -28,11 +29,18 @@ import java.io.File;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 默认所有消息的事件处理器
|
||||
*
|
||||
* // TODO 芋艿:待实现
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MsgHandler implements WxMpMessageHandler {
|
||||
@Autowired
|
||||
private WxAccountService wxAccountService;
|
||||
public class DefaultMessageHandler implements WxMpMessageHandler {
|
||||
|
||||
@Resource
|
||||
@Lazy // 延迟加载,解决循环依赖的问题
|
||||
private MpAccountService mpAccountService;
|
||||
|
||||
@Autowired
|
||||
private WxFansMsgService wxFansMsgService;
|
||||
|
@ -55,7 +63,7 @@ public class MsgHandler implements WxMpMessageHandler {
|
|||
WxMpUser wxmpUser = weixinService.getUserService()
|
||||
.userInfo(wxMessage.getFromUser(), null);
|
||||
if (wxmpUser != null) {
|
||||
MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
|
||||
MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
|
||||
if (wxAccount != null) {
|
||||
|
||||
if (wxMessage.getMsgType().equals(WxConsts.XmlMsgType.TEXT)) {
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.yudao.module.mp.handler;
|
||||
package cn.iocoder.yudao.module.mp.service.handler;
|
||||
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
|
||||
|
@ -9,14 +9,18 @@ import org.springframework.stereotype.Component;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 接收客服会话管理的事件处理器
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
public class KfSessionHandler implements WxMpMessageHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
//TODO 对会话做处理
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
|
||||
WxMpService wxMpService, WxSessionManager sessionManager) {
|
||||
// TODO 对会话做处理
|
||||
return null;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.yudao.module.mp.handler;
|
||||
package cn.iocoder.yudao.module.mp.service.handler;
|
||||
|
||||
import cn.iocoder.yudao.module.mp.builder.TextBuilder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -13,14 +13,18 @@ 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<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
|
||||
WxMpService wxMpService, WxSessionManager sessionManager) {
|
||||
if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
|
||||
//TODO 接收处理用户发送的地理位置消息
|
||||
try {
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.yudao.module.mp.handler;
|
||||
package cn.iocoder.yudao.module.mp.service.handler;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -11,13 +11,18 @@ import org.springframework.stereotype.Component;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 保存微信消息的事件处理器
|
||||
*
|
||||
* // TODO 芋艿:实现一下
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class LogHandler implements WxMpMessageHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
|
||||
WxMpService wxMpService, WxSessionManager sessionManager) {
|
||||
log.info("接收到请求消息,内容:{}", JsonUtils.toJsonString(wxMessage));
|
||||
return null;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.yudao.module.mp.handler;
|
||||
package cn.iocoder.yudao.module.mp.service.handler;
|
||||
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
|
||||
|
@ -11,6 +11,11 @@ import java.util.Map;
|
|||
|
||||
import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
|
||||
|
||||
/**
|
||||
* 自定义菜单的事件处理器
|
||||
*
|
||||
* // TODO 芋艿:待实现
|
||||
*/
|
||||
@Component
|
||||
public class MenuHandler implements WxMpMessageHandler {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.yudao.module.mp.handler;
|
||||
package cn.iocoder.yudao.module.mp.service.handler;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
|
@ -10,6 +10,9 @@ import org.springframework.stereotype.Component;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 扫码的事件处理器
|
||||
*/
|
||||
@Component
|
||||
public class ScanHandler implements WxMpMessageHandler {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.yudao.module.mp.handler;
|
||||
package cn.iocoder.yudao.module.mp.service.handler;
|
||||
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
|
||||
|
@ -10,8 +10,7 @@ import org.springframework.stereotype.Component;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 门店审核事件处理
|
||||
*
|
||||
* 门店审核事件的事件处理器
|
||||
*/
|
||||
@Component
|
||||
public class StoreCheckNotifyHandler implements WxMpMessageHandler {
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.yudao.module.mp.handler;
|
||||
package cn.iocoder.yudao.module.mp.service.handler;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
|
@ -9,7 +9,7 @@ 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.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;
|
||||
|
@ -23,11 +23,18 @@ 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 {
|
||||
|
@ -35,8 +42,9 @@ public class SubscribeHandler implements WxMpMessageHandler {
|
|||
@Autowired
|
||||
private WxTextTemplateService wxTextTemplateService;
|
||||
|
||||
@Autowired
|
||||
private WxAccountService wxAccountService;
|
||||
@Resource
|
||||
@Lazy // 延迟加载,解决循环依赖的问题
|
||||
private MpAccountService mpAccountService;
|
||||
|
||||
@Autowired
|
||||
private WxSubscribeTextService wxSubscribeTextService;
|
||||
|
@ -60,7 +68,7 @@ public class SubscribeHandler implements WxMpMessageHandler {
|
|||
.userInfo(wxMessage.getFromUser(), null);
|
||||
if (wxmpUser != null) {
|
||||
// 可以添加关注用户到本地数据库
|
||||
MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
|
||||
MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
|
||||
if (wxAccount != null) {
|
||||
WxAccountFansDO wxAccountFans = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, wxmpUser.getOpenId());
|
||||
if (wxAccountFans == null) {//insert
|
||||
|
@ -128,7 +136,7 @@ public class SubscribeHandler implements WxMpMessageHandler {
|
|||
|
||||
try {
|
||||
String content = "感谢关注!";//默认
|
||||
MpAccountDO wxAccount = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
|
||||
MpAccountDO wxAccount = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
|
||||
if (wxAccount != null) {
|
||||
WxSubscribeTextDO wxSubscribeText = wxSubscribeTextService.findBy(WxSubscribeTextDO::getWxAccountId, String.valueOf(wxAccount.getId()));
|
||||
if (wxSubscribeText != null) {
|
|
@ -1,9 +1,9 @@
|
|||
package cn.iocoder.yudao.module.mp.handler;
|
||||
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.WxAccountService;
|
||||
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;
|
||||
|
@ -12,16 +12,24 @@ 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 {
|
||||
|
||||
@Autowired
|
||||
private WxAccountService wxAccountService;
|
||||
@Resource
|
||||
@Lazy // 延迟加载,解决循环依赖的问题
|
||||
private MpAccountService mpAccountService;
|
||||
|
||||
@Autowired
|
||||
private WxAccountFansService wxAccountFansService;
|
||||
|
@ -34,7 +42,7 @@ public class UnsubscribeHandler implements WxMpMessageHandler {
|
|||
log.info("取消关注用户 OPENID: " + openId);
|
||||
// TODO 可以更新本地数据库为取消关注状态
|
||||
|
||||
MpAccountDO wxAccountDO = wxAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
|
||||
MpAccountDO wxAccountDO = mpAccountService.findBy(MpAccountDO::getAccount, wxMessage.getToUser());
|
||||
if (wxAccountDO != null) {
|
||||
WxAccountFansDO wxAccountFansDO = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, openId);
|
||||
if (wxAccountFansDO != null) {
|
Loading…
Reference in New Issue