Commit 44f0bcd182a9a9e7b23dcadff7071e548d4a4160
1 parent
48bea21a
mp:实现关键字,自动回复
Showing
9 changed files
with
210 additions
and
16 deletions
yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/message/MpAutoReplyMatchEnum.java
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 | * |