Commit 44f0bcd182a9a9e7b23dcadff7071e548d4a4160

Authored by YunaiV
1 parent 48bea21a

mp:实现关键字,自动回复

yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/message/MpAutoReplyMatchEnum.java
@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
4 import lombok.Getter; 4 import lombok.Getter;
5 5
6 /** 6 /**
7 - * 微信消息自动回复的匹配模式 7 + * 公众号消息自动回复的匹配模式
8 * 8 *
9 * @author 芋道源码 9 * @author 芋道源码
10 */ 10 */
yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/message/MpAutoReplyTypeEnum.java
@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
4 import lombok.Getter; 4 import lombok.Getter;
5 5
6 /** 6 /**
7 - * 微信消息自动回复的类型 7 + * 公众号消息自动回复的类型
8 * 8 *
9 * @author 芋道源码 9 * @author 芋道源码
10 */ 10 */
@@ -14,7 +14,7 @@ public enum MpAutoReplyTypeEnum { @@ -14,7 +14,7 @@ public enum MpAutoReplyTypeEnum {
14 14
15 SUBSCRIBE(1, "关注时回复"), 15 SUBSCRIBE(1, "关注时回复"),
16 MESSAGE(2, "收到消息回复"), 16 MESSAGE(2, "收到消息回复"),
17 - KEYWORD(2, "关键词回复"), 17 + KEYWORD(3, "关键词回复"),
18 ; 18 ;
19 19
20 /** 20 /**
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/message/MpMessageConvert.java
1 package cn.iocoder.yudao.module.mp.convert.message; 1 package cn.iocoder.yudao.module.mp.convert.message;
2 2
3 -import java.util.*;  
4 - 3 +import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 - 5 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  6 +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.MpMessageRespVO;
7 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; 7 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
  8 +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO;
8 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; 9 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO;
9 import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; 10 import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO;
  11 +import me.chanjar.weixin.common.api.WxConsts;
10 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; 12 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
  13 +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
  14 +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutNewsMessage;
  15 +import me.chanjar.weixin.mp.builder.outxml.BaseBuilder;
  16 +import me.chanjar.weixin.mp.builder.outxml.TextBuilder;
  17 +import me.chanjar.weixin.mp.builder.outxml.VideoBuilder;
11 import org.mapstruct.Mapper; 18 import org.mapstruct.Mapper;
12 import org.mapstruct.Mapping; 19 import org.mapstruct.Mapping;
13 import org.mapstruct.Mappings; 20 import org.mapstruct.Mappings;
14 import org.mapstruct.factory.Mappers; 21 import org.mapstruct.factory.Mappers;
15 -import cn.iocoder.yudao.module.mp.controller.admin.message.vo.*; 22 +
  23 +import java.util.Collections;
  24 +import java.util.List;
16 25
17 @Mapper 26 @Mapper
18 public interface MpMessageConvert { 27 public interface MpMessageConvert {
@@ -41,4 +50,64 @@ public interface MpMessageConvert { @@ -41,4 +50,64 @@ public interface MpMessageConvert {
41 } 50 }
42 return message; 51 return message;
43 } 52 }
  53 +
  54 + default MpMessageDO convert(MpAutoReplyDO reply, MpAccountDO account, MpUserDO user) {
  55 + // 构建消息
  56 + MpMessageDO message = new MpMessageDO();
  57 + message.setType(reply.getResponseMessageType());
  58 + // 1. 文本
  59 + if (StrUtil.equals(reply.getResponseMessageType(), WxConsts.XmlMsgType.TEXT)) {
  60 + message.setContent(reply.getResponseContent());
  61 + } else if (ObjectUtils.equalsAny(reply.getResponseMessageType(), WxConsts.XmlMsgType.IMAGE, // 2. 图片
  62 + WxConsts.XmlMsgType.VOICE)) { // 3. 语音
  63 + message.setMediaId(reply.getResponseMediaId()).setMediaUrl(reply.getResponseMediaUrl());
  64 + } else if (StrUtil.equals(reply.getResponseMessageType(), WxConsts.XmlMsgType.VIDEO)) { // 4. 视频
  65 + message.setMediaId(reply.getResponseMediaId()).setMediaUrl(reply.getResponseMediaUrl())
  66 + .setTitle(reply.getResponseTitle()).setDescription(reply.getResponseDescription());
  67 + } else if (StrUtil.equals(reply.getResponseMessageType(), WxConsts.XmlMsgType.NEWS)) { // 5. 图文
  68 + message.setArticles(Collections.singletonList(reply.getResponseArticle()));
  69 + } else {
  70 + throw new IllegalArgumentException("不支持的消息类型:" + message.getType());
  71 + }
  72 +
  73 + // 其它字段
  74 + if (account != null) {
  75 + message.setAccountId(account.getId()).setAppId(account.getAppId());
  76 + }
  77 + if (user != null) {
  78 + message.setUserId(user.getId()).setOpenid(user.getOpenid());
  79 + }
  80 + return message;
  81 + }
  82 +
  83 + default WxMpXmlOutMessage convert02(MpMessageDO message, MpAccountDO account) {
  84 + BaseBuilder<?, ? extends WxMpXmlOutMessage> messageBuilder;
  85 + // 个性化字段
  86 + switch (message.getType()) {
  87 + case WxConsts.XmlMsgType.TEXT:
  88 + messageBuilder = WxMpXmlOutMessage.TEXT().content(message.getContent());
  89 + break;
  90 + case WxConsts.XmlMsgType.IMAGE:
  91 + messageBuilder = WxMpXmlOutMessage.IMAGE().mediaId(message.getMediaId());
  92 + break;
  93 + case WxConsts.XmlMsgType.VOICE:
  94 + messageBuilder = WxMpXmlOutMessage.VOICE().mediaId(message.getMediaId());
  95 + break;
  96 + case WxConsts.XmlMsgType.VIDEO:
  97 + messageBuilder = WxMpXmlOutMessage.VIDEO().mediaId(message.getMediaId())
  98 + .title(message.getTitle()).description(message.getDescription());
  99 + break;
  100 + case WxConsts.XmlMsgType.NEWS:
  101 + messageBuilder = WxMpXmlOutMessage.NEWS().articles(convertList02(message.getArticles()));
  102 + break;
  103 + default:
  104 + throw new IllegalArgumentException("不支持的消息类型:" + message.getType());
  105 + }
  106 + // 通用字段
  107 + messageBuilder.fromUser(account.getAccount());
  108 + messageBuilder.toUser(message.getOpenid());
  109 + return messageBuilder.build();
  110 + }
  111 + List<WxMpXmlOutNewsMessage.Item> convertList02(List<MpMessageDO.Article> list);
  112 +
44 } 113 }
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/message/MpAutoReplyDO.java
@@ -6,18 +6,21 @@ import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; @@ -6,18 +6,21 @@ import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
6 import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyMatchEnum; 6 import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyMatchEnum;
7 import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyTypeEnum; 7 import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyTypeEnum;
8 import com.baomidou.mybatisplus.annotation.KeySequence; 8 import com.baomidou.mybatisplus.annotation.KeySequence;
  9 +import com.baomidou.mybatisplus.annotation.TableField;
9 import com.baomidou.mybatisplus.annotation.TableId; 10 import com.baomidou.mybatisplus.annotation.TableId;
10 import com.baomidou.mybatisplus.annotation.TableName; 11 import com.baomidou.mybatisplus.annotation.TableName;
  12 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
11 import lombok.Data; 13 import lombok.Data;
12 import lombok.EqualsAndHashCode; 14 import lombok.EqualsAndHashCode;
13 import lombok.ToString; 15 import lombok.ToString;
14 import me.chanjar.weixin.common.api.WxConsts; 16 import me.chanjar.weixin.common.api.WxConsts;
15 import me.chanjar.weixin.common.api.WxConsts.XmlMsgType; 17 import me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
16 18
  19 +import java.util.List;
17 import java.util.Set; 20 import java.util.Set;
18 21
19 /** 22 /**
20 - * 微信消息自动回复 DO 23 + * 公众号消息自动回复 DO
21 * 24 *
22 * @author 芋道源码 25 * @author 芋道源码
23 */ 26 */
@@ -99,4 +102,35 @@ public class MpAutoReplyDO extends BaseDO { @@ -99,4 +102,35 @@ public class MpAutoReplyDO extends BaseDO {
99 */ 102 */
100 private String responseContent; 103 private String responseContent;
101 104
  105 + /**
  106 + * 回复的媒体 id
  107 + *
  108 + * 消息类型为 {@link WxConsts.XmlMsgType} 的 IMAGE、VOICE、VIDEO
  109 + */
  110 + private String responseMediaId;
  111 + /**
  112 + * 回复的媒体 URL
  113 + */
  114 + private String responseMediaUrl;
  115 +
  116 + /**
  117 + * 回复的标题
  118 + *
  119 + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO
  120 + */
  121 + private String responseTitle;
  122 + /**
  123 + * 回复的描述
  124 + *
  125 + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO
  126 + */
  127 + private String responseDescription;
  128 +
  129 + /**
  130 + * 回复的图文消息
  131 + *
  132 + * 消息类型为 {@link WxConsts.XmlMsgType} 的 NEWS
  133 + */
  134 + @TableField(typeHandler = JacksonTypeHandler.class)
  135 + private MpMessageDO.Article responseArticle;
102 } 136 }
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/message/MpMessageDO.java
1 package cn.iocoder.yudao.module.mp.dal.dataobject.message; 1 package cn.iocoder.yudao.module.mp.dal.dataobject.message;
2 2
  3 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; 5 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
5 import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; 6 import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO;
6 import cn.iocoder.yudao.module.mp.enums.message.MpMessageSendFromEnum; 7 import cn.iocoder.yudao.module.mp.enums.message.MpMessageSendFromEnum;
7 import com.baomidou.mybatisplus.annotation.KeySequence; 8 import com.baomidou.mybatisplus.annotation.KeySequence;
  9 +import com.baomidou.mybatisplus.annotation.TableField;
8 import com.baomidou.mybatisplus.annotation.TableId; 10 import com.baomidou.mybatisplus.annotation.TableId;
9 import com.baomidou.mybatisplus.annotation.TableName; 11 import com.baomidou.mybatisplus.annotation.TableName;
  12 +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler;
10 import lombok.*; 13 import lombok.*;
11 import me.chanjar.weixin.common.api.WxConsts; 14 import me.chanjar.weixin.common.api.WxConsts;
12 15
  16 +import java.io.Serializable;
  17 +import java.util.List;
  18 +
13 /** 19 /**
14 - * 微信消息 DO 20 + * 公众号消息 DO
15 * 21 *
16 * @author 芋道源码 22 * @author 芋道源码
17 */ 23 */
@@ -160,6 +166,14 @@ public class MpMessageDO extends BaseDO { @@ -160,6 +166,14 @@ public class MpMessageDO extends BaseDO {
160 */ 166 */
161 private String label; 167 private String label;
162 168
  169 + /**
  170 + * 图文消息数组
  171 + *
  172 + * 消息类型为 {@link WxConsts.XmlMsgType} 的 NEWS
  173 + */
  174 + @TableField(typeHandler = ArticleTypeHandler.class)
  175 + private List<Article> articles;
  176 +
163 // ========= 事件推送 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html 177 // ========= 事件推送 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html
164 178
165 /** 179 /**
@@ -176,4 +190,45 @@ public class MpMessageDO extends BaseDO { @@ -176,4 +190,45 @@ public class MpMessageDO extends BaseDO {
176 */ 190 */
177 private String eventKey; 191 private String eventKey;
178 192
  193 + /**
  194 + * 文章
  195 + */
  196 + @Data
  197 + public static class Article implements Serializable {
  198 +
  199 + /**
  200 + * 图文消息标题
  201 + */
  202 + private String title;
  203 + /**
  204 + * 图文消息描述
  205 + */
  206 + private String description;
  207 + /**
  208 + * 图片链接
  209 + *
  210 + * 支持JPG、PNG格式,较好的效果为大图 360*200,小图 200*200
  211 + */
  212 + private String picUrl;
  213 + /**
  214 + * 点击图文消息跳转链接
  215 + */
  216 + private String url;
  217 +
  218 + }
  219 +
  220 + // TODO @芋艿:可以找一些新的思路
  221 + public static class ArticleTypeHandler extends AbstractJsonTypeHandler<List<Article>> {
  222 +
  223 + @Override
  224 + protected List<Article> parse(String json) {
  225 + return JsonUtils.parseArray(json, Article.class);
  226 + }
  227 +
  228 + @Override
  229 + protected String toJson(List<Article> obj) {
  230 + return JsonUtils.toJsonString(obj);
  231 + }
  232 +
  233 + }
179 } 234 }
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpAutoReplyMapper.java
@@ -5,9 +5,11 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; @@ -5,9 +5,11 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
5 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO; 5 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO;
6 import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyMatchEnum; 6 import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyMatchEnum;
7 import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyTypeEnum; 7 import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyTypeEnum;
  8 +import org.apache.ibatis.annotations.Mapper;
8 9
9 import java.util.List; 10 import java.util.List;
10 11
  12 +@Mapper
11 public interface MpAutoReplyMapper extends BaseMapperX<MpAutoReplyDO> { 13 public interface MpAutoReplyMapper extends BaseMapperX<MpAutoReplyDO> {
12 14
13 default List<MpAutoReplyDO> selectListByAppIdAndKeywordAll(String appId, String requestKeyword) { 15 default List<MpAutoReplyDO> selectListByAppIdAndKeywordAll(String appId, String requestKeyword) {
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyServiceImpl.java
1 package cn.iocoder.yudao.module.mp.service.message; 1 package cn.iocoder.yudao.module.mp.service.message;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.module.mp.builder.TextBuilder;
4 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO; 5 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO;
5 import cn.iocoder.yudao.module.mp.dal.mysql.message.MpAutoReplyMapper; 6 import cn.iocoder.yudao.module.mp.dal.mysql.message.MpAutoReplyMapper;
6 import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyMatchEnum; 7 import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyMatchEnum;
7 import me.chanjar.weixin.common.api.WxConsts; 8 import me.chanjar.weixin.common.api.WxConsts;
8 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; 9 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
9 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; 10 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
  11 +import org.springframework.stereotype.Service;
10 import org.springframework.validation.annotation.Validated; 12 import org.springframework.validation.annotation.Validated;
11 13
12 import javax.annotation.Resource; 14 import javax.annotation.Resource;
@@ -17,18 +19,21 @@ import java.util.List; @@ -17,18 +19,21 @@ import java.util.List;
17 * 19 *
18 * @author 芋道源码 20 * @author 芋道源码
19 */ 21 */
20 -@Resource 22 +@Service
21 @Validated 23 @Validated
22 public class MpAutoReplyServiceImpl implements MpAutoReplyService { 24 public class MpAutoReplyServiceImpl implements MpAutoReplyService {
23 25
24 @Resource 26 @Resource
25 - private MpAutoReplyService mpAutoReplyService; 27 + private MpMessageService mpMessageService;
26 28
27 @Resource 29 @Resource
28 private MpAutoReplyMapper mpAutoReplyMapper; 30 private MpAutoReplyMapper mpAutoReplyMapper;
29 31
30 @Override 32 @Override
31 public WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage) { 33 public WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage) {
  34 +// if (true) {
  35 +// return new TextBuilder().build("nihao", wxMessage, null);
  36 +// }
32 // 第一步,匹配自动回复 37 // 第一步,匹配自动回复
33 List<MpAutoReplyDO> replies = null; 38 List<MpAutoReplyDO> replies = null;
34 // 1.1 关键字 39 // 1.1 关键字
@@ -47,12 +52,10 @@ public class MpAutoReplyServiceImpl implements MpAutoReplyService { @@ -47,12 +52,10 @@ public class MpAutoReplyServiceImpl implements MpAutoReplyService {
47 if (CollUtil.isEmpty(replies)) { 52 if (CollUtil.isEmpty(replies)) {
48 return null; 53 return null;
49 } 54 }
  55 + MpAutoReplyDO reply = CollUtil.getFirst(replies);
50 56
51 // 第二步,基于自动回复,创建消息 57 // 第二步,基于自动回复,创建消息
52 -  
53 -  
54 - // 第三步,将消息转换成 WxMpXmlOutMessage 返回  
55 - return null; 58 + return mpMessageService.createFromAutoReply(wxMessage.getFromUser(), reply);
56 } 59 }
57 60
58 } 61 }
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageService.java
@@ -2,8 +2,10 @@ package cn.iocoder.yudao.module.mp.service.message; @@ -2,8 +2,10 @@ package cn.iocoder.yudao.module.mp.service.message;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.mp.controller.admin.message.vo.MpMessagePageReqVO; 4 import cn.iocoder.yudao.module.mp.controller.admin.message.vo.MpMessagePageReqVO;
  5 +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO;
5 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; 6 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO;
6 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; 7 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
  8 +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
7 9
8 /** 10 /**
9 * 粉丝消息表 Service 接口 11 * 粉丝消息表 Service 接口
@@ -28,4 +30,14 @@ public interface MpMessageService { @@ -28,4 +30,14 @@ public interface MpMessageService {
28 * @param wxMessage 消息 30 * @param wxMessage 消息
29 */ 31 */
30 void createFromUser(String appId, WxMpXmlMessage wxMessage); 32 void createFromUser(String appId, WxMpXmlMessage wxMessage);
  33 +
  34 + /**
  35 + * 创建粉丝消息,通过自动回复
  36 + *
  37 + * @param openid 公众号粉丝 openid
  38 + * @param reply 自动回复
  39 + * @return 微信回复消息 XML
  40 + */
  41 + WxMpXmlOutMessage createFromAutoReply(String openid, MpAutoReplyDO reply);
  42 +
31 } 43 }
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageServiceImpl.java
@@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.util.io.FileUtils; @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.util.io.FileUtils;
9 import cn.iocoder.yudao.module.infra.api.file.FileApi; 9 import cn.iocoder.yudao.module.infra.api.file.FileApi;
10 import cn.iocoder.yudao.module.mp.convert.message.MpMessageConvert; 10 import cn.iocoder.yudao.module.mp.convert.message.MpMessageConvert;
11 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; 11 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
  12 +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO;
12 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; 13 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO;
13 import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; 14 import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO;
14 import cn.iocoder.yudao.module.mp.enums.message.MpMessageSendFromEnum; 15 import cn.iocoder.yudao.module.mp.enums.message.MpMessageSendFromEnum;
@@ -20,6 +21,7 @@ import lombok.extern.slf4j.Slf4j; @@ -20,6 +21,7 @@ import lombok.extern.slf4j.Slf4j;
20 import me.chanjar.weixin.common.error.WxErrorException; 21 import me.chanjar.weixin.common.error.WxErrorException;
21 import me.chanjar.weixin.mp.api.WxMpService; 22 import me.chanjar.weixin.mp.api.WxMpService;
22 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; 23 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
  24 +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
23 import org.springframework.context.annotation.Lazy; 25 import org.springframework.context.annotation.Lazy;
24 import org.springframework.stereotype.Service; 26 import org.springframework.stereotype.Service;
25 27
@@ -74,7 +76,7 @@ public class MpMessageServiceImpl implements MpMessageService { @@ -74,7 +76,7 @@ public class MpMessageServiceImpl implements MpMessageService {
74 MpAccountDO account = mpAccountService.getAccountFromCache(appId); 76 MpAccountDO account = mpAccountService.getAccountFromCache(appId);
75 Assert.notNull(account, "公众号账号({}) 不存在", appId); 77 Assert.notNull(account, "公众号账号({}) 不存在", appId);
76 MpUserDO user = mpUserService.getUser(appId, wxMessage.getFromUser()); 78 MpUserDO user = mpUserService.getUser(appId, wxMessage.getFromUser());
77 - Assert.notNull(account, "公众号粉丝({}/{}) 不存在", appId, wxMessage.getFromUser()); 79 + Assert.notNull(user, "公众号粉丝({}/{}) 不存在", appId, wxMessage.getFromUser());
78 80
79 // 记录消息 81 // 记录消息
80 MpMessageDO message = MpMessageConvert.INSTANCE.convert(wxMessage, account, user); 82 MpMessageDO message = MpMessageConvert.INSTANCE.convert(wxMessage, account, user);
@@ -94,6 +96,23 @@ public class MpMessageServiceImpl implements MpMessageService { @@ -94,6 +96,23 @@ public class MpMessageServiceImpl implements MpMessageService {
94 // wxMessage.getEventKey() 96 // wxMessage.getEventKey()
95 } 97 }
96 98
  99 + @Override
  100 + public WxMpXmlOutMessage createFromAutoReply(String openid, MpAutoReplyDO reply) {
  101 + // 获得关联信息
  102 + MpAccountDO account = mpAccountService.getAccountFromCache(reply.getAppId());
  103 + Assert.notNull(account, "公众号账号({}) 不存在", reply.getAppId());
  104 + MpUserDO user = mpUserService.getUser(reply.getAppId(), openid);
  105 + Assert.notNull(user, "公众号粉丝({}/{}) 不存在", reply.getAppId(), openid);
  106 +
  107 + // 记录消息
  108 + MpMessageDO message = MpMessageConvert.INSTANCE.convert(reply, account, user);
  109 + message.setSendFrom(MpMessageSendFromEnum.MP_TO_USER.getFrom());
  110 + mpMessageMapper.insert(message);
  111 +
  112 + // 转换返回 WxMpXmlOutMessage 对象
  113 + return MpMessageConvert.INSTANCE.convert02(message, account);
  114 + }
  115 +
97 /** 116 /**
98 * 下载微信媒体文件的内容,并上传到文件服务 117 * 下载微信媒体文件的内容,并上传到文件服务
99 * 118 *