mp:location 的自动回复;关注后的自动回复

This commit is contained in:
YunaiV 2023-01-05 19:36:13 +08:00
parent 44f0bcd182
commit 69e653cd94
8 changed files with 81 additions and 55 deletions

View File

@ -34,4 +34,11 @@ public interface MpAutoReplyMapper extends BaseMapperX<MpAutoReplyDO> {
.eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.MESSAGE.getType())
.eq(MpAutoReplyDO::getRequestMessageType, requestMessageType));
}
default List<MpAutoReplyDO> selectListByAppIdAndSubscribe(String appId) {
return selectList(new LambdaQueryWrapperX<MpAutoReplyDO>()
.eq(MpAutoReplyDO::getAppId, appId)
.eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.SUBSCRIBE.getType()));
}
}

View File

@ -36,7 +36,7 @@ public class MpConfiguration {
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
public MpServiceFactory mpServiceFactory(RedisTemplateWxRedisOps redisTemplateWxRedisOps,
WxMpProperties wxMpProperties,
MessageReceiveHandler logHandler,
MessageReceiveHandler messageReceiveHandler,
KfSessionHandler kfSessionHandler,
StoreCheckNotifyHandler storeCheckNotifyHandler,
MenuHandler menuHandler,
@ -45,10 +45,10 @@ public class MpConfiguration {
UnsubscribeHandler unsubscribeHandler,
LocationHandler locationHandler,
ScanHandler scanHandler,
MessageAutoReplyHandler msgHandler) {
MessageAutoReplyHandler messageAutoReplyHandler) {
return new DefaultMpServiceFactory(redisTemplateWxRedisOps, wxMpProperties,
logHandler, kfSessionHandler, storeCheckNotifyHandler, menuHandler,
nullHandler, subscribeHandler, unsubscribeHandler, locationHandler, scanHandler, msgHandler);
messageReceiveHandler, kfSessionHandler, storeCheckNotifyHandler, menuHandler,
nullHandler, subscribeHandler, unsubscribeHandler, locationHandler, scanHandler, messageAutoReplyHandler);
}
}

View File

@ -49,7 +49,7 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
// ========== 各种 Handler ==========
private final MessageReceiveHandler logHandler;
private final MessageReceiveHandler messageReceiveHandler;
private final KfSessionHandler kfSessionHandler;
private final StoreCheckNotifyHandler storeCheckNotifyHandler;
private final MenuHandler menuHandler;
@ -58,7 +58,7 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
private final UnsubscribeHandler unsubscribeHandler;
private final LocationHandler locationHandler;
private final ScanHandler scanHandler;
private final MessageAutoReplyHandler msgHandler;
private final MessageAutoReplyHandler messageAutoReplyHandler;
@Override
public void init(List<MpAccountDO> list) {
@ -108,7 +108,7 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
private WxMpMessageRouter buildMpMessageRouter(WxMpService mpService) {
WxMpMessageRouter router = new WxMpMessageRouter(mpService);
// 记录所有事件的日志异步执行
router.rule().handler(logHandler).next();
router.rule().handler(messageReceiveHandler).next();
// 接收客服会话管理事件
router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
@ -159,7 +159,7 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
.event(WxConsts.EventType.SCAN).handler(scanHandler).end();
// 默认
router.rule().async(false).handler(msgHandler).end();
router.rule().async(false).handler(messageAutoReplyHandler).end();
return router;
}

View File

@ -1,6 +1,11 @@
package cn.iocoder.yudao.module.mp.service.handler.user;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder;
import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
import me.chanjar.weixin.mp.api.WxMpService;
@ -8,38 +13,37 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Map;
/**
* 上报地理位置的事件处理器
*
* // TODO @芋艿需要实现一下~
* 触发操作打开微信公众号 -> 点击 + -> 选择语音
*
* 逻辑用户上传地理位置时也可以触发自动回复
*
* @author 芋道源码
*/
@Component
@Slf4j
public class LocationHandler implements WxMpMessageHandler {
@Resource
private MpAutoReplyService mpAutoReplyService;
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> 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 可以将用户地理位置信息保存到本地数据库以便以后使用
// 防御性编程必须是 LOCATION 消息
if (ObjectUtil.notEqual(wxMessage.getMsgType(), WxConsts.XmlMsgType.LOCATION)) {
return null;
}
log.info("[handle][上报地理位置,纬度({})、经度({})、精度({})", wxMessage.getLatitude(),
wxMessage.getLongitude(), wxMessage.getPrecision());
// 自动回复
return mpAutoReplyService.replyForMessage(MpContextHolder.getAppId(), wxMessage);
}
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.mp.service.handler.user;
import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO;
import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder;
import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService;
import cn.iocoder.yudao.module.mp.service.user.MpUserService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
@ -22,19 +23,15 @@ import java.util.Map;
* 关注的事件处理器
*
* @author 芋道源码
*
* // TODO 芋艿待实现
*/
@Component
@Slf4j
public class SubscribeHandler implements WxMpMessageHandler {
@Resource
@Lazy // 延迟加载解决循环依赖的问题
private MpAccountService mpAccountService;
@Resource
private MpUserService mpUserService;
@Resource
private MpAutoReplyService mpAutoReplyService;
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
@ -49,24 +46,10 @@ public class SubscribeHandler implements WxMpMessageHandler {
}
// 第二步保存用户信息
MpUserDO mpUser = null;
if (wxMpUser != null) {
mpUser = mpUserService.saveUser(MpContextHolder.getAppId(), wxMpUser);
}
mpUserService.saveUser(MpContextHolder.getAppId(), wxMpUser);
// 第三步回复关注的欢迎语 TODO 芋艿关注的欢迎语
// return new TextBuilder().build("感谢关注", wxMessage, weixinService);
return null;
}
/**
* 处理特殊请求比如如果是扫码进来的可以做相应处理
*/
private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage)
throws Exception {
//TODO
return null;
// 第三步回复关注的欢迎语
return mpAutoReplyService.replyForSubscribe(MpContextHolder.getAppId(), wxMessage);
}
}

View File

@ -19,4 +19,13 @@ public interface MpAutoReplyService {
*/
WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage);
/**
* 当用户关注时自动回复
*
* @param appId 微信公众号 appId
* @param wxMessage 消息
* @return 回复的消息
*/
WxMpXmlOutMessage replyForSubscribe(String appId, WxMpXmlMessage wxMessage);
}

View File

@ -1,13 +1,16 @@
package cn.iocoder.yudao.module.mp.service.message;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.mp.builder.TextBuilder;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO;
import cn.iocoder.yudao.module.mp.dal.mysql.message.MpAutoReplyMapper;
import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyMatchEnum;
import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyTypeEnum;
import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@ -25,15 +28,15 @@ public class MpAutoReplyServiceImpl implements MpAutoReplyService {
@Resource
private MpMessageService mpMessageService;
@Resource
@Lazy // 延迟加载避免循环依赖
private MpAccountService mpAccountService;
@Resource
private MpAutoReplyMapper mpAutoReplyMapper;
@Override
public WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage) {
// if (true) {
// return new TextBuilder().build("nihao", wxMessage, null);
// }
// 第一步匹配自动回复
List<MpAutoReplyDO> replies = null;
// 1.1 关键字
@ -58,4 +61,24 @@ public class MpAutoReplyServiceImpl implements MpAutoReplyService {
return mpMessageService.createFromAutoReply(wxMessage.getFromUser(), reply);
}
@Override
public WxMpXmlOutMessage replyForSubscribe(String appId, WxMpXmlMessage wxMessage) {
// 第一步匹配自动回复
List<MpAutoReplyDO> replies = mpAutoReplyMapper.selectListByAppIdAndSubscribe(appId);
MpAutoReplyDO reply = CollUtil.isNotEmpty(replies) ? CollUtil.getFirst(replies)
: buildDefaultSubscribeAutoReply(appId); // 如果不存在提供一个默认末班
// 第二步基于自动回复创建消息
return mpMessageService.createFromAutoReply(wxMessage.getFromUser(), reply);
}
private MpAutoReplyDO buildDefaultSubscribeAutoReply(String appId) {
MpAccountDO account = mpAccountService.getAccountFromCache(appId);
Assert.notNull(account, "公众号账号({}) 不存在", appId);
// 构建默认的关注自动回复
return new MpAutoReplyDO().setAppId(appId).setAccountId(account.getId())
.setType(MpAutoReplyTypeEnum.SUBSCRIBE.getType())
.setResponseMessageType(WxConsts.XmlMsgType.TEXT).setResponseContent("感谢关注");
}
}

View File

@ -89,7 +89,7 @@ public class MpMessageServiceImpl implements MpMessageService {
}
mpMessageMapper.insert(message);
// WxConsts.MenuButtonType.VIEW
// WxConsts.MenuButtonType.VIEW TODO 芋艿待测试
// wxMessage.getEventKey()
// WxConsts.MenuButtonType.CLICK