Commit 3be6ee271b4b4a86a1fa454c609d5cb63a738f65

Authored by 芋道源码
Committed by Gitee
2 parents 345f41b1 ab4e10cc

!1023 【优化】SYSTEM: 根据代码评审优化订阅消息

Merge pull request !1023 from puhui999/develop
Showing 12 changed files with 126 additions and 252 deletions
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/MessageTemplateConstants.java
... ... @@ -11,19 +11,4 @@ public interface MessageTemplateConstants {
11 11  
12 12 String PAY_WALLET_CHANGE = "充值成功通知";
13 13  
14   - // TODO @puhui999:这种建议不枚举,直接写~嘿嘿。
15   - /**
16   - * 充值成功通知模版参数
17   - *
18   - * @author HUIHUI
19   - */
20   - class PayWalletChangeTemplateParams {
21   -
22   - public static final String NO = "character_string1"; // 流水编号
23   - public static final String PRICE = "amount2"; // 充值金额
24   - public static final String PAY_TIME = "time3"; // 充值时间
25   - public static final String STATUS = "phrase4"; // 充值状态
26   -
27   - }
28   -
29 14 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/message/package-info.java deleted
1   -package cn.iocoder.yudao.module.pay.message;
2 0 \ No newline at end of file
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/message/subscribe/SubscribeMessageClient.java deleted
1   -package cn.iocoder.yudao.module.pay.message.subscribe;
2   -
3   -import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
4   -import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
5   -import jakarta.annotation.Resource;
6   -import lombok.extern.slf4j.Slf4j;
7   -import org.springframework.scheduling.annotation.Async;
8   -import org.springframework.stereotype.Component;
9   -
10   -import java.util.Map;
11   -
12   -import static cn.iocoder.yudao.module.pay.enums.MessageTemplateConstants.PAY_WALLET_CHANGE;
13   -
14   -// TODO @puhui999:建议可以先直接调用,不要新建一个 client。
15   -/**
16   - * 订阅消息
17   - *
18   - * @author HUIHUI
19   - */
20   -@Component
21   -@Slf4j
22   -public class SubscribeMessageClient {
23   -
24   - public static final String WALLET_MONEY_PATH = "pages/user/wallet/money"; // 钱包详情页
25   -
26   - @Resource
27   - public SocialClientApi socialClientApi;
28   -
29   - /**
30   - * 发送钱包充值通知
31   - *
32   - * @param messages 消息
33   - * @param userType 用户类型
34   - * @param userId 用户编号
35   - */
36   - @Async
37   - public void sendPayWalletChangeMessage(Map<String, String> messages, Integer userType, Long userId) {
38   - sendWxMessage(PAY_WALLET_CHANGE, messages, userType, userId, WALLET_MONEY_PATH);
39   - }
40   -
41   -
42   - /**
43   - * 发送微信订阅消息
44   - *
45   - * @param templateTitle 模版标题
46   - * @param messages 消息
47   - * @param userType 用户类型
48   - * @param userId 用户编号
49   - * @param path 点击模板卡片后的跳转页面,仅限本小程序内的页面
50   - */
51   - private void sendWxMessage(String templateTitle, Map<String, String> messages, Integer userType, Long userId,
52   - String path) {
53   - socialClientApi.sendSubscribeMessage(templateTitle, messages, userType, userId, SocialTypeEnum.WECHAT_MINI_APP.getType(), path);
54   - }
55   -
56   -}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java
... ... @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.pay.service.wallet;
2 2  
3 3 import cn.hutool.core.date.LocalDateTimeUtil;
4 4 import cn.hutool.core.lang.Assert;
5   -import cn.hutool.core.map.MapUtil;
  5 +import cn.hutool.extra.spring.SpringUtil;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageParam;
7 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 8 import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
... ... @@ -15,21 +15,22 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
15 15 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
16 16 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO;
17 17 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletRechargeMapper;
18   -import cn.iocoder.yudao.module.pay.enums.MessageTemplateConstants;
19 18 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
20 19 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
21 20 import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
22   -import cn.iocoder.yudao.module.pay.message.subscribe.SubscribeMessageClient;
23 21 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
24 22 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
  23 +import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
  24 +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxSubscribeMessageSendReqDTO;
  25 +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
25 26 import jakarta.annotation.Resource;
26 27 import lombok.extern.slf4j.Slf4j;
  28 +import org.springframework.scheduling.annotation.Async;
27 29 import org.springframework.stereotype.Service;
28 30 import org.springframework.transaction.annotation.Transactional;
29 31  
30 32 import java.time.Duration;
31 33 import java.time.LocalDateTime;
32   -import java.util.Map;
33 34 import java.util.Objects;
34 35  
35 36 import static cn.hutool.core.util.ObjectUtil.notEqual;
... ... @@ -39,6 +40,7 @@ import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString
39 40 import static cn.iocoder.yudao.framework.common.util.number.MoneyUtils.fenToYuanStr;
40 41 import static cn.iocoder.yudao.module.pay.convert.wallet.PayWalletRechargeConvert.INSTANCE;
41 42 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
  43 +import static cn.iocoder.yudao.module.pay.enums.MessageTemplateConstants.PAY_WALLET_CHANGE;
42 44 import static cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum.*;
43 45  
44 46 /**
... ... @@ -57,6 +59,8 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
57 59  
58 60 private static final String WALLET_RECHARGE_ORDER_SUBJECT = "钱包余额充值";
59 61  
  62 + public static final String WALLET_MONEY_PATH = "pages/user/wallet/money"; // 钱包详情页
  63 +
60 64 @Resource
61 65 private PayWalletRechargeMapper walletRechargeMapper;
62 66 @Resource
... ... @@ -68,7 +72,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
68 72 @Resource
69 73 private PayWalletRechargePackageService payWalletRechargePackageService;
70 74 @Resource
71   - private SubscribeMessageClient subscribeMessageClient;
  75 + public SocialClientApi socialClientApi;
72 76  
73 77 @Override
74 78 @Transactional(rollbackFor = Exception.class)
... ... @@ -136,21 +140,21 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
136 140 PayWalletBizTypeEnum.RECHARGE, walletRecharge.getTotalPrice());
137 141  
138 142 // 4. 发送订阅消息
139   - sendPayWalletChangeMessage(payOrderId, walletRecharge);
  143 + getSelf().sendPayWalletChangeMessage(payOrderId, walletRecharge);
140 144 }
141 145  
142   - // TODO @puhui999:发送,使用异步发送;@Async
143   - private void sendPayWalletChangeMessage(Long payOrderId, PayWalletRechargeDO walletRecharge) {
  146 + @Async
  147 + public void sendPayWalletChangeMessage(Long payOrderId, PayWalletRechargeDO walletRecharge) {
  148 + // 1.1 获得会员钱包信息
144 149 PayWalletDO wallet = payWalletService.getWallet(walletRecharge.getWalletId());
145   - // TODO @puhui999:可以使用 MapUtil.builder();另外,不应该是并发 hashmap 哈
146   - Map<String, String> messages = MapUtil.newConcurrentHashMap(4);
147   - messages.put(MessageTemplateConstants.PayWalletChangeTemplateParams.NO, String.valueOf(payOrderId));
148   - messages.put(MessageTemplateConstants.PayWalletChangeTemplateParams.PRICE,
149   - fenToYuanStr(walletRecharge.getTotalPrice()));
150   - messages.put(MessageTemplateConstants.PayWalletChangeTemplateParams.STATUS, "充值成功");
151   - messages.put(MessageTemplateConstants.PayWalletChangeTemplateParams.PAY_TIME,
152   - LocalDateTimeUtil.formatNormal(LocalDateTime.now()));
153   - subscribeMessageClient.sendPayWalletChangeMessage(messages, wallet.getUserType(), wallet.getUserId());
  150 + // 1.2 构建并发送模版消息
  151 + socialClientApi.sendSubscribeMessage(new SocialWxSubscribeMessageSendReqDTO().setPage(WALLET_MONEY_PATH)
  152 + .setUserId(wallet.getUserId()).setUserType(wallet.getUserType()).setTemplateTitle(PAY_WALLET_CHANGE)
  153 + .setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())
  154 + // 添加模版消息
  155 + .addMessage("phrase4", "充值成功").addMessage("character_string1", String.valueOf(payOrderId))
  156 + .addMessage("amount2", fenToYuanStr(walletRecharge.getTotalPrice()))
  157 + .addMessage("time3", LocalDateTimeUtil.formatNormal(LocalDateTime.now())));
154 158 }
155 159  
156 160 @Override
... ... @@ -307,4 +311,13 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
307 311 return payOrder;
308 312 }
309 313  
  314 + /**
  315 + * 获得自身的代理对象,解决 AOP 生效问题
  316 + *
  317 + * @return 自己
  318 + */
  319 + private PayWalletRechargeServiceImpl getSelf() {
  320 + return SpringUtil.getBean(getClass());
  321 + }
  322 +
310 323 }
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java
... ... @@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
5 5 import jakarta.validation.Valid;
6 6  
7 7 import java.util.List;
8   -import java.util.Map;
9 8  
10 9 /**
11 10 * 社交应用的 API 接口
... ... @@ -57,25 +56,11 @@ public interface SocialClientApi {
57 56 */
58 57 List<SocialWxSubscribeTemplateRespDTO> getSubscribeTemplateList(Integer userType);
59 58  
60   - // TODO @puhui999:sendSubscribeMessage 两个方法,可以融合成一个么?
61 59 /**
62 60 * 发送微信小程序订阅消息
63 61 *
64 62 * @param reqDTO 请求
65 63 */
66   - void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO, Integer userType);
67   -
68   - /**
69   - * 发送微信小程序订阅消息
70   - *
71   - * @param templateTitle 模版标题
72   - * @param messages 消息
73   - * @param userType 用户类型
74   - * @param userId 用户编号
75   - * @param socialType 社交客服端类型
76   - * @param path 点击模板卡片后的跳转页面,仅限本小程序内的页面
77   - */
78   - void sendSubscribeMessage(String templateTitle, Map<String, String> messages, Integer userType, Long userId,
79   - Integer socialType, String path);
  64 + void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO);
80 65  
81 66 }
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxSubscribeMessageSendReqDTO.java
1 1 package cn.iocoder.yudao.module.system.api.social.dto;
2 2  
3   -import jakarta.validation.constraints.NotNull;
  3 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  4 +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
4 5 import lombok.Data;
5 6  
  7 +import java.util.HashMap;
6 8 import java.util.Map;
7 9  
8 10 /**
9 11 * 微信小程序订阅消息发送 Request DTO
10 12 *
11   - * @see <a href="https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html">接口文档</a>
12 13 * @author HUIHUI
13 14 */
14 15 @Data
15 16 public class SocialWxSubscribeMessageSendReqDTO {
16 17  
17   - // TODO @puhui999:貌似使用 userId + userType 会不会更合理哈。这样,后端进行查询三方用户的绑定表~
18 18 /**
19   - * 接收者(用户)的 openid.
20   - * <pre>
21   - * 参数:touser
22   - * 是否必填: 是
23   - * 描述: 接收者(用户)的 openid
24   - * </pre>
  19 + * 用户 id
  20 + *
  21 + * 关联 MemberUserDO 的 id 编号
  22 + * 关联 AdminUserDO 的 id 编号
25 23 */
26   - @NotNull(message = "接收者(用户)的 openid不能为空")
27   - private String toUser;
28   -
  24 + private Long userId;
29 25 /**
30   - * 模版消息编号
  26 + * 用户类型, 预留 多商户转帐可能需要用到
  27 + *
  28 + * 关联 {@link UserTypeEnum}
31 29 */
32   - @NotNull(message = "模版消息编号不能为空")
33   - private String templateId;
  30 + private Integer userType;
34 31  
35 32 /**
36   - * 点击模板卡片后的跳转页面,仅限本小程序内的页面
  33 + * 社交类型
37 34 *
38   - * 支持带参数,(示例 index?foo=bar )。该字段不填则模板无跳转。
  35 + * 枚举 {@link SocialTypeEnum}
39 36 */
40   - private String page;
  37 + private Integer socialType;
41 38  
42 39 /**
43   - * 跳转小程序类型
44   - *
45   - * developer 为开发版;trial 为体验版;formal 为正式版【默认】
46   - *
47   - * 枚举 WxMaConstants.MiniProgramState
  40 + * 消息模版标题
48 41 */
49   - // TODO @puhui999:这个非必填。如果没有,代码里去默认下;
50   - @NotNull(message = "跳转小程序类型不能为空")
51   - private String miniprogramState;
  42 + private String templateTitle;
52 43  
53 44 /**
54   - * 进入小程序查看的语言类型
55   - *
56   - * zh_CN(简体中文)【默认】、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文)
  45 + * 点击模板卡片后的跳转页面,仅限本小程序内的页面
57 46 *
58   - * 枚举 WxMaConstants.MiniProgramLang
  47 + * 支持带参数,(示例 index?foo=bar )。该字段不填则模板无跳转。
59 48 */
60   - // TODO @puhui999:这个非必填。如果没有,代码里去默认下;
61   - @NotNull(message = "进入小程序查看的语言类型不能为空")
62   - private String lang;
  49 + private String page;
63 50  
64 51 /**
65 52 * 模板内容的参数
66 53 */
67 54 private Map<String, String> messages;
68 55  
  56 + public SocialWxSubscribeMessageSendReqDTO addMessage(String key, String value) {
  57 + if (messages == null) {
  58 + messages = new HashMap<>();
  59 + }
  60 + messages.put(key, value);
  61 + return this;
  62 + }
  63 +
69 64 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java
... ... @@ -2,12 +2,10 @@ package cn.iocoder.yudao.module.system.api.social;
2 2  
3 3 import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
4 4 import cn.hutool.core.collection.CollUtil;
5   -import cn.hutool.core.collection.CollectionUtil;
6 5 import cn.hutool.core.util.ObjUtil;
7 6 import cn.hutool.core.util.StrUtil;
8 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
9 8 import cn.iocoder.yudao.module.system.api.social.dto.*;
10   -import cn.iocoder.yudao.module.system.convert.social.SocialUserConvert;
11 9 import cn.iocoder.yudao.module.system.service.social.SocialClientService;
12 10 import jakarta.annotation.Resource;
13 11 import lombok.extern.slf4j.Slf4j;
... ... @@ -18,7 +16,9 @@ import org.springframework.stereotype.Service;
18 16 import org.springframework.validation.annotation.Validated;
19 17  
20 18 import java.util.List;
21   -import java.util.Map;
  19 +
  20 +import static cn.hutool.core.collection.CollUtil.findOne;
  21 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
22 22  
23 23 /**
24 24 * 社交应用的 API 实现类
... ... @@ -65,80 +65,36 @@ public class SocialClientApiImpl implements SocialClientApi {
65 65 @Override
66 66 public List<SocialWxSubscribeTemplateRespDTO> getSubscribeTemplateList(Integer userType) {
67 67 List<TemplateInfo> subscribeTemplate = socialClientService.getSubscribeTemplateList(userType);
68   - return SocialUserConvert.INSTANCE.convertList(subscribeTemplate);
  68 + return convertList(subscribeTemplate, item -> BeanUtils.toBean(item, SocialWxSubscribeTemplateRespDTO.class)
  69 + .setId(item.getPriTmplId()));
69 70 }
70 71  
71 72 @Override
72   - public void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO, Integer userType) {
73   - socialClientService.sendSubscribeMessage(reqDTO, userType);
74   - }
75   -
76   - public void sendSubscribeMessage(String templateTitle, Map<String, String> messages, Integer userType, Long userId,
77   - Integer socialType, String path) {
78   - // TODO @puhui999:建议是,先不拆小方法。因为逻辑的复杂度其实不高哈。合在一个方法里,因为咱写了 1.1 1.2 2. 这样的逻辑,也能一下子看懂。
79   - // 1.1 获得订阅模版
80   - SocialWxSubscribeTemplateRespDTO template = getTemplate(templateTitle, userType);
81   - if (template == null) {
  73 + public void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO) {
  74 + // 1.1 获得订阅模版列表
  75 + List<SocialWxSubscribeTemplateRespDTO> templateList = getSubscribeTemplateList(reqDTO.getUserType());
  76 + if (CollUtil.isEmpty(templateList)) {
  77 + log.warn("[sendSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:没有找到订阅模板]", reqDTO);
82 78 return;
83 79 }
84   - // 1.2 获得发送对象的 openId
85   - String openId = getUserOpenId(userType, userId, socialType);
86   - if (StrUtil.isBlankIfStr(openId)) {
  80 + // 1.2 获得需要使用的模版
  81 + SocialWxSubscribeTemplateRespDTO template = findOne(templateList, item ->
  82 + ObjUtil.equal(item.getTitle(), reqDTO.getTemplateTitle()));
  83 + if (template == null) {
  84 + log.warn("[sendSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:没有找到订阅模板]", reqDTO);
87 85 return;
88 86 }
89 87  
90   - // 2. 发送消息
91   - sendSubscribeMessage(buildMessageSendReqDTO(openId, path, template).setMessages(messages), userType);
92   - }
93   -
94   - /**
95   - * 构建发送消息请求参数
96   - *
97   - * @param openId 接收者(用户)的 openid
98   - * @param path 点击模板卡片后的跳转页面,仅限本小程序内的页面
99   - * @param template 订阅模版
100   - * @return 微信小程序订阅消息发送
101   - */
102   - private SocialWxSubscribeMessageSendReqDTO buildMessageSendReqDTO(String openId, String path,
103   - SocialWxSubscribeTemplateRespDTO template) {
104   - return new SocialWxSubscribeMessageSendReqDTO().setLang("zh_CN").setMiniprogramState(envVersion)
105   - .setTemplateId(template.getId()).setToUser(openId).setPage(path);
106   - }
107   -
108   - // TODO @puhui999:建议下沉到 service 实现。
109   - /**
110   - * 获得小程序订阅消息模版
111   - *
112   - * @param templateTitle 模版标题
113   - * @param userType 用户类型
114   - * @return 小程序订阅消息模版
115   - */
116   - private SocialWxSubscribeTemplateRespDTO getTemplate(String templateTitle, Integer userType) {
117   - List<SocialWxSubscribeTemplateRespDTO> templateList = getSubscribeTemplateList(userType);
118   - if (CollUtil.isEmpty(templateList)) {
119   - log.warn("[getTemplate][templateTitle({}) userType({}) 没有找到订阅模板]", templateTitle, userType);
120   - return null;
121   - }
122   - return CollectionUtil.findOne(templateList, item -> ObjUtil.equal(item.getTitle(), templateTitle));
123   - }
124   -
125   - // TODO @puhui999:建议下沉到 service 实现。
126   - /**
127   - * 获得用户 openId
128   - *
129   - * @param userType 用户类型
130   - * @param userId 用户编号
131   - * @param socialType 社交类型
132   - * @return 用户 openId
133   - */
134   - private String getUserOpenId(Integer userType, Long userId, Integer socialType) {
135   - SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId(userType, userId, socialType);
  88 + // 2. 获得社交用户
  89 + SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId(reqDTO.getUserType(), reqDTO.getUserId(),
  90 + reqDTO.getSocialType());
136 91 if (StrUtil.isBlankIfStr(socialUser.getOpenid())) {
137   - log.warn("[getUserOpenId][userType({}) userId({}) socialType({}) 会员 openid 缺失]",
138   - userType, userId, socialType);
139   - return null;
  92 + log.warn("[sendSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:会员 openid 缺失]", reqDTO);
  93 + return;
140 94 }
141   - return socialUser.getOpenid();
  95 +
  96 + // 3. 发送订阅消息
  97 + socialClientService.sendSubscribeMessage(reqDTO, template.getId(), socialUser.getOpenid());
142 98 }
143 99  
144 100 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.http
... ... @@ -6,14 +6,15 @@ Content-Type: application/json
6 6 tenant-id: {{adminTenentId}}
7 7  
8 8 {
9   - "toUser": "oKNkb4xxw2H135-MVPKtEMkumK08",
10   - "templateId": "W4ybDTIwCfKHtMKR7fSfx83DtmVKEeXQo3Ti7GCw4_4",
11   - "miniprogramState": "developer",
12   - "lang": "zh_CN",
  9 + "userId": 247,
  10 + "userType": 1,
  11 + "socialType": 34,
  12 + "templateTitle": "充值成功通知",
  13 + "page": "",
13 14 "messages": {
14 15 "character_string1":"5616122165165",
15 16 "amount2":"1000.00",
16 17 "time3":"2024-01-01 10:10:10",
17   - "phrase4":"成功"
  18 + "phrase4": "充值成功"
18 19 }
19 20 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.socail;
2 2  
3   -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
7 7 import cn.iocoder.yudao.module.system.api.social.dto.SocialWxSubscribeMessageSendReqDTO;
8 8 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
9 9 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientRespVO;
... ... @@ -29,6 +29,8 @@ public class SocialClientController {
29 29  
30 30 @Resource
31 31 private SocialClientService socialClientService;
  32 + @Resource
  33 + private SocialClientApi socialClientApi;
32 34  
33 35 @PostMapping("/create")
34 36 @Operation(summary = "创建社交客户端")
... ... @@ -75,7 +77,7 @@ public class SocialClientController {
75 77 @Operation(summary = "发送订阅消息") // 用于测试
76 78 @PreAuthorize("@ss.hasPermission('system:social-client:query')")
77 79 public void sendSubscribeMessage(@RequestBody SocialWxSubscribeMessageSendReqDTO reqDTO) {
78   - socialClientService.sendSubscribeMessage(reqDTO, UserTypeEnum.MEMBER.getValue());
  80 + socialClientApi.sendSubscribeMessage(reqDTO);
79 81 }
80 82  
81 83 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/social/SocialUserConvert.java
1 1 package cn.iocoder.yudao.module.system.convert.social;
2 2  
3   -import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
4   -import cn.hutool.core.collection.CollUtil;
5   -import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 3 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
7   -import cn.iocoder.yudao.module.system.api.social.dto.SocialWxSubscribeMessageSendReqDTO;
8   -import cn.iocoder.yudao.module.system.api.social.dto.SocialWxSubscribeTemplateRespDTO;
9 4 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserBindReqVO;
10   -import me.chanjar.weixin.common.bean.subscribemsg.TemplateInfo;
11 5 import org.mapstruct.Mapper;
12 6 import org.mapstruct.Mapping;
13 7 import org.mapstruct.factory.Mappers;
14 8  
15   -import java.util.ArrayList;
16   -import java.util.List;
17   -import java.util.Map;
18   -
19   -import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
20   -
21 9 @Mapper
22 10 public interface SocialUserConvert {
23 11  
... ... @@ -26,25 +14,4 @@ public interface SocialUserConvert {
26 14 @Mapping(source = "reqVO.type", target = "socialType")
27 15 SocialUserBindReqDTO convert(Long userId, Integer userType, SocialUserBindReqVO reqVO);
28 16  
29   - // TODO @puhui999:要不 convert 直接放到 service 里。
30   - default WxMaSubscribeMessage convert(SocialWxSubscribeMessageSendReqDTO reqDTO) {
31   - WxMaSubscribeMessage message = BeanUtils.toBean(reqDTO, WxMaSubscribeMessage.class);
32   - Map<String, String> messages = reqDTO.getMessages();
33   - if (CollUtil.isNotEmpty(messages)) {
34   - messages.keySet().forEach(key -> findAndThen(messages, key, value -> message.addData(new WxMaSubscribeMessage.MsgData(key, value))));
35   - }
36   - return message;
37   - }
38   -
39   - // TODO @puhui999:要不 convert 直接放到 service 里。其实可以 BeanUtils.toBean(reqDTO, WxMaSubscribeMessage.class) 来搞的呀。
40   - @Mapping(target = "id", source = "priTmplId")
41   - SocialWxSubscribeTemplateRespDTO convert(TemplateInfo templateInfo);
42   -
43   - // TODO @puhui999:是不是用 CollectionUtils.convertList 就 ok 啦。
44   - default List<SocialWxSubscribeTemplateRespDTO> convertList(List<TemplateInfo> subscribeTemplate) {
45   - List<SocialWxSubscribeTemplateRespDTO> list = new ArrayList<>();
46   - subscribeTemplate.forEach(templateInfo -> list.add(convert(templateInfo)));
47   - return list;
48   - }
49   -
50 17 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java
... ... @@ -83,9 +83,11 @@ public interface SocialClientService {
83 83 /**
84 84 * 发送微信小程序订阅消息
85 85 *
86   - * @param reqDTO 请求
  86 + * @param reqDTO 请求
  87 + * @param templateId 模版编号
  88 + * @param openId 会员 openId
87 89 */
88   - void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO, Integer userType);
  90 + void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO, String templateId, String openId);
89 91  
90 92 // =================== 客户端管理 ===================
91 93  
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java
... ... @@ -4,8 +4,10 @@ import cn.binarywang.wx.miniapp.api.WxMaService;
4 4 import cn.binarywang.wx.miniapp.api.WxMaSubscribeService;
5 5 import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
6 6 import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
  7 +import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
7 8 import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl;
8 9 import cn.hutool.core.bean.BeanUtil;
  10 +import cn.hutool.core.collection.CollUtil;
9 11 import cn.hutool.core.lang.Assert;
10 12 import cn.hutool.core.util.ObjUtil;
11 13 import cn.hutool.core.util.ReflectUtil;
... ... @@ -19,7 +21,6 @@ import cn.iocoder.yudao.module.system.api.social.dto.SocialWxQrcodeReqDTO;
19 21 import cn.iocoder.yudao.module.system.api.social.dto.SocialWxSubscribeMessageSendReqDTO;
20 22 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
21 23 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
22   -import cn.iocoder.yudao.module.system.convert.social.SocialUserConvert;
23 24 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
24 25 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
25 26 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
... ... @@ -51,9 +52,11 @@ import org.springframework.stereotype.Service;
51 52  
52 53 import java.time.Duration;
53 54 import java.util.List;
  55 +import java.util.Map;
54 56 import java.util.Objects;
55 57  
56 58 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  59 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
57 60 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
58 61 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
59 62  
... ... @@ -273,18 +276,40 @@ public class SocialClientServiceImpl implements SocialClientService {
273 276 }
274 277  
275 278 @Override
276   - public void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO, Integer userType) {
277   - WxMaService service = getWxMaService(userType);
  279 + public void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO, String templateId, String openId) {
  280 + WxMaService service = getWxMaService(reqDTO.getUserType());
278 281 try {
279 282 WxMaSubscribeService subscribeService = service.getSubscribeService();
280   - subscribeService.sendSubscribeMsg(SocialUserConvert.INSTANCE.convert(reqDTO));
  283 + subscribeService.sendSubscribeMsg(buildMessageSendReqDTO(reqDTO, templateId, openId));
281 284 } catch (WxErrorException e) {
282   - log.error("[sendSubscribeMessage][reqVO({}) userType({}) 发送小程序订阅消息]", reqDTO, userType, e);
  285 + log.error("[sendSubscribeMessage][reqVO({}) templateId({}) openId({}) 发送小程序订阅消息失败]", reqDTO, templateId, openId, e);
283 286 throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_MESSAGE_ERROR);
284 287 }
285 288 }
286 289  
287 290 /**
  291 + * 构建发送消息请求参数
  292 + *
  293 + * @param reqDTO 请求
  294 + * @param templateId 模版编号
  295 + * @param openId 会员 openId
  296 + * @return 微信小程序订阅消息发送
  297 + */
  298 + private WxMaSubscribeMessage buildMessageSendReqDTO(SocialWxSubscribeMessageSendReqDTO reqDTO,
  299 + String templateId, String openId) {
  300 + // 1.1 设置订阅消息基本参数
  301 + WxMaSubscribeMessage subscribeMessage = new WxMaSubscribeMessage().setLang("zh_CN").setMiniprogramState(envVersion)
  302 + .setTemplateId(templateId).setToUser(openId).setPage(reqDTO.getPage());
  303 + // 1.2 设置具体消息参数
  304 + Map<String, String> messages = reqDTO.getMessages();
  305 + if (CollUtil.isNotEmpty(messages)) {
  306 + messages.keySet().forEach(key -> findAndThen(messages, key, value ->
  307 + subscribeMessage.addData(new WxMaSubscribeMessage.MsgData(key, value))));
  308 + }
  309 + return subscribeMessage;
  310 + }
  311 +
  312 + /**
288 313 * 获得 clientId + clientSecret 对应的 WxMpService 对象
289 314 *
290 315 * @param userType 用户类型
... ...