diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/MessageTemplateConstants.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/MessageTemplateConstants.java index 197b08ad5..bf28724dc 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/MessageTemplateConstants.java +++ b/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 { String PAY_WALLET_CHANGE = "充值成功通知"; - // TODO @puhui999:这种建议不枚举,直接写~嘿嘿。 - /** - * 充值成功通知模版参数 - * - * @author HUIHUI - */ - class PayWalletChangeTemplateParams { - - public static final String NO = "character_string1"; // 流水编号 - public static final String PRICE = "amount2"; // 充值金额 - public static final String PAY_TIME = "time3"; // 充值时间 - public static final String STATUS = "phrase4"; // 充值状态 - - } - } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/message/package-info.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/message/package-info.java deleted file mode 100644 index 2e26571ef..000000000 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/message/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.pay.message; \ No newline at end of file diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/message/subscribe/SubscribeMessageClient.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/message/subscribe/SubscribeMessageClient.java deleted file mode 100644 index 3ef26156d..000000000 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/message/subscribe/SubscribeMessageClient.java +++ /dev/null @@ -1,56 +0,0 @@ -package cn.iocoder.yudao.module.pay.message.subscribe; - -import cn.iocoder.yudao.module.system.api.social.SocialClientApi; -import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Component; - -import java.util.Map; - -import static cn.iocoder.yudao.module.pay.enums.MessageTemplateConstants.PAY_WALLET_CHANGE; - -// TODO @puhui999:建议可以先直接调用,不要新建一个 client。 -/** - * 订阅消息 - * - * @author HUIHUI - */ -@Component -@Slf4j -public class SubscribeMessageClient { - - public static final String WALLET_MONEY_PATH = "pages/user/wallet/money"; // 钱包详情页 - - @Resource - public SocialClientApi socialClientApi; - - /** - * 发送钱包充值通知 - * - * @param messages 消息 - * @param userType 用户类型 - * @param userId 用户编号 - */ - @Async - public void sendPayWalletChangeMessage(Map messages, Integer userType, Long userId) { - sendWxMessage(PAY_WALLET_CHANGE, messages, userType, userId, WALLET_MONEY_PATH); - } - - - /** - * 发送微信订阅消息 - * - * @param templateTitle 模版标题 - * @param messages 消息 - * @param userType 用户类型 - * @param userId 用户编号 - * @param path 点击模板卡片后的跳转页面,仅限本小程序内的页面 - */ - private void sendWxMessage(String templateTitle, Map messages, Integer userType, Long userId, - String path) { - socialClientApi.sendSubscribeMessage(templateTitle, messages, userType, userId, SocialTypeEnum.WECHAT_MINI_APP.getType(), path); - } - -} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java index 40050ac01..b7ba2eb7a 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java +++ b/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; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; -import cn.hutool.core.map.MapUtil; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; @@ -15,21 +15,22 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO; import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO; import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletRechargeMapper; -import cn.iocoder.yudao.module.pay.enums.MessageTemplateConstants; import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; -import cn.iocoder.yudao.module.pay.message.subscribe.SubscribeMessageClient; import cn.iocoder.yudao.module.pay.service.order.PayOrderService; import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxSubscribeMessageSendReqDTO; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.Duration; import java.time.LocalDateTime; -import java.util.Map; import java.util.Objects; import static cn.hutool.core.util.ObjectUtil.notEqual; @@ -39,6 +40,7 @@ import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString import static cn.iocoder.yudao.framework.common.util.number.MoneyUtils.fenToYuanStr; import static cn.iocoder.yudao.module.pay.convert.wallet.PayWalletRechargeConvert.INSTANCE; import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.pay.enums.MessageTemplateConstants.PAY_WALLET_CHANGE; import static cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum.*; /** @@ -57,6 +59,8 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { private static final String WALLET_RECHARGE_ORDER_SUBJECT = "钱包余额充值"; + public static final String WALLET_MONEY_PATH = "pages/user/wallet/money"; // 钱包详情页 + @Resource private PayWalletRechargeMapper walletRechargeMapper; @Resource @@ -68,7 +72,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { @Resource private PayWalletRechargePackageService payWalletRechargePackageService; @Resource - private SubscribeMessageClient subscribeMessageClient; + public SocialClientApi socialClientApi; @Override @Transactional(rollbackFor = Exception.class) @@ -136,21 +140,21 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { PayWalletBizTypeEnum.RECHARGE, walletRecharge.getTotalPrice()); // 4. 发送订阅消息 - sendPayWalletChangeMessage(payOrderId, walletRecharge); + getSelf().sendPayWalletChangeMessage(payOrderId, walletRecharge); } - // TODO @puhui999:发送,使用异步发送;@Async - private void sendPayWalletChangeMessage(Long payOrderId, PayWalletRechargeDO walletRecharge) { + @Async + public void sendPayWalletChangeMessage(Long payOrderId, PayWalletRechargeDO walletRecharge) { + // 1. 获得会员钱包信息 PayWalletDO wallet = payWalletService.getWallet(walletRecharge.getWalletId()); - // TODO @puhui999:可以使用 MapUtil.builder();另外,不应该是并发 hashmap 哈 - Map messages = MapUtil.newConcurrentHashMap(4); - messages.put(MessageTemplateConstants.PayWalletChangeTemplateParams.NO, String.valueOf(payOrderId)); - messages.put(MessageTemplateConstants.PayWalletChangeTemplateParams.PRICE, - fenToYuanStr(walletRecharge.getTotalPrice())); - messages.put(MessageTemplateConstants.PayWalletChangeTemplateParams.STATUS, "充值成功"); - messages.put(MessageTemplateConstants.PayWalletChangeTemplateParams.PAY_TIME, - LocalDateTimeUtil.formatNormal(LocalDateTime.now())); - subscribeMessageClient.sendPayWalletChangeMessage(messages, wallet.getUserType(), wallet.getUserId()); + // 2. 构建并发送模版消息 + socialClientApi.sendSubscribeMessage(new SocialWxSubscribeMessageSendReqDTO().setPage(WALLET_MONEY_PATH) + .setUserId(wallet.getUserId()).setUserType(wallet.getUserType()).setTemplateTitle(PAY_WALLET_CHANGE) + .setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType()) + // 添加模版消息 + .addMessage("phrase4", "充值成功").addMessage("character_string1", String.valueOf(payOrderId)) + .addMessage("amount2", fenToYuanStr(walletRecharge.getTotalPrice())) + .addMessage("time3", LocalDateTimeUtil.formatNormal(LocalDateTime.now()))); } @Override @@ -307,4 +311,13 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { return payOrder; } + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private PayWalletRechargeServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java index 72534768a..03cbde57d 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java +++ b/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; import jakarta.validation.Valid; import java.util.List; -import java.util.Map; /** * 社交应用的 API 接口 @@ -57,25 +56,11 @@ public interface SocialClientApi { */ List getSubscribeTemplateList(Integer userType); - // TODO @puhui999:sendSubscribeMessage 两个方法,可以融合成一个么? /** * 发送微信小程序订阅消息 * * @param reqDTO 请求 */ - void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO, Integer userType); - - /** - * 发送微信小程序订阅消息 - * - * @param templateTitle 模版标题 - * @param messages 消息 - * @param userType 用户类型 - * @param userId 用户编号 - * @param socialType 社交客服端类型 - * @param path 点击模板卡片后的跳转页面,仅限本小程序内的页面 - */ - void sendSubscribeMessage(String templateTitle, Map messages, Integer userType, Long userId, - Integer socialType, String path); + void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO); } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxSubscribeMessageSendReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxSubscribeMessageSendReqDTO.java index 8ebb70b45..9799d69bd 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxSubscribeMessageSendReqDTO.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxSubscribeMessageSendReqDTO.java @@ -1,36 +1,45 @@ package cn.iocoder.yudao.module.system.api.social.dto; -import jakarta.validation.constraints.NotNull; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; import lombok.Data; +import java.util.HashMap; import java.util.Map; /** * 微信小程序订阅消息发送 Request DTO * - * @see 接口文档 * @author HUIHUI */ @Data public class SocialWxSubscribeMessageSendReqDTO { - // TODO @puhui999:貌似使用 userId + userType 会不会更合理哈。这样,后端进行查询三方用户的绑定表~ /** - * 接收者(用户)的 openid. - *
-     * 参数:touser
-     * 是否必填: 是
-     * 描述: 接收者(用户)的 openid
-     * 
+ * 用户 id + * + * 关联 MemberUserDO 的 id 编号 + * 关联 AdminUserDO 的 id 编号 */ - @NotNull(message = "接收者(用户)的 openid不能为空") - private String toUser; + private Long userId; + /** + * 用户类型, 预留 多商户转帐可能需要用到 + * + * 关联 {@link UserTypeEnum} + */ + private Integer userType; /** - * 模版消息编号 + * 社交类型 + * + * 枚举 {@link SocialTypeEnum} */ - @NotNull(message = "模版消息编号不能为空") - private String templateId; + private Integer socialType; + + /** + * 消息模版标题 + */ + private String templateTitle; /** * 点击模板卡片后的跳转页面,仅限本小程序内的页面 @@ -39,31 +48,17 @@ public class SocialWxSubscribeMessageSendReqDTO { */ private String page; - /** - * 跳转小程序类型 - * - * developer 为开发版;trial 为体验版;formal 为正式版【默认】 - * - * 枚举 WxMaConstants.MiniProgramState - */ - // TODO @puhui999:这个非必填。如果没有,代码里去默认下; - @NotNull(message = "跳转小程序类型不能为空") - private String miniprogramState; - - /** - * 进入小程序查看的语言类型 - * - * zh_CN(简体中文)【默认】、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文) - * - * 枚举 WxMaConstants.MiniProgramLang - */ - // TODO @puhui999:这个非必填。如果没有,代码里去默认下; - @NotNull(message = "进入小程序查看的语言类型不能为空") - private String lang; - /** * 模板内容的参数 */ private Map messages; + public SocialWxSubscribeMessageSendReqDTO addMessage(String key, String value) { + if (messages == null) { + messages = new HashMap<>(); + } + messages.put(key, value); + return this; + } + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java index fe72d9706..131381552 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java +++ b/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; import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.api.social.dto.*; -import cn.iocoder.yudao.module.system.convert.social.SocialUserConvert; import cn.iocoder.yudao.module.system.service.social.SocialClientService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -18,7 +16,9 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.util.List; -import java.util.Map; + +import static cn.hutool.core.collection.CollUtil.findOne; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; /** * 社交应用的 API 实现类 @@ -65,80 +65,36 @@ public class SocialClientApiImpl implements SocialClientApi { @Override public List getSubscribeTemplateList(Integer userType) { List subscribeTemplate = socialClientService.getSubscribeTemplateList(userType); - return SocialUserConvert.INSTANCE.convertList(subscribeTemplate); + return convertList(subscribeTemplate, item -> BeanUtils.toBean(item, SocialWxSubscribeTemplateRespDTO.class) + .setId(item.getPriTmplId())); } @Override - public void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO, Integer userType) { - socialClientService.sendSubscribeMessage(reqDTO, userType); - } - - public void sendSubscribeMessage(String templateTitle, Map messages, Integer userType, Long userId, - Integer socialType, String path) { - // TODO @puhui999:建议是,先不拆小方法。因为逻辑的复杂度其实不高哈。合在一个方法里,因为咱写了 1.1 1.2 2. 这样的逻辑,也能一下子看懂。 - // 1.1 获得订阅模版 - SocialWxSubscribeTemplateRespDTO template = getTemplate(templateTitle, userType); - if (template == null) { - return; - } - // 1.2 获得发送对象的 openId - String openId = getUserOpenId(userType, userId, socialType); - if (StrUtil.isBlankIfStr(openId)) { - return; - } - - // 2. 发送消息 - sendSubscribeMessage(buildMessageSendReqDTO(openId, path, template).setMessages(messages), userType); - } - - /** - * 构建发送消息请求参数 - * - * @param openId 接收者(用户)的 openid - * @param path 点击模板卡片后的跳转页面,仅限本小程序内的页面 - * @param template 订阅模版 - * @return 微信小程序订阅消息发送 - */ - private SocialWxSubscribeMessageSendReqDTO buildMessageSendReqDTO(String openId, String path, - SocialWxSubscribeTemplateRespDTO template) { - return new SocialWxSubscribeMessageSendReqDTO().setLang("zh_CN").setMiniprogramState(envVersion) - .setTemplateId(template.getId()).setToUser(openId).setPage(path); - } - - // TODO @puhui999:建议下沉到 service 实现。 - /** - * 获得小程序订阅消息模版 - * - * @param templateTitle 模版标题 - * @param userType 用户类型 - * @return 小程序订阅消息模版 - */ - private SocialWxSubscribeTemplateRespDTO getTemplate(String templateTitle, Integer userType) { - List templateList = getSubscribeTemplateList(userType); + public void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO) { + // 1.1 获得订阅模版列表 + List templateList = getSubscribeTemplateList(reqDTO.getUserType()); if (CollUtil.isEmpty(templateList)) { - log.warn("[getTemplate][templateTitle({}) userType({}) 没有找到订阅模板]", templateTitle, userType); - return null; + log.warn("[sendSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:没有找到订阅模板]", reqDTO); + return; + } + // 1.2 获得需要使用的模版 + SocialWxSubscribeTemplateRespDTO template = findOne(templateList, item -> + ObjUtil.equal(item.getTitle(), reqDTO.getTemplateTitle())); + if (template == null) { + log.warn("[sendSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:没有找到订阅模板]", reqDTO); + return; } - return CollectionUtil.findOne(templateList, item -> ObjUtil.equal(item.getTitle(), templateTitle)); - } - // TODO @puhui999:建议下沉到 service 实现。 - /** - * 获得用户 openId - * - * @param userType 用户类型 - * @param userId 用户编号 - * @param socialType 社交类型 - * @return 用户 openId - */ - private String getUserOpenId(Integer userType, Long userId, Integer socialType) { - SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId(userType, userId, socialType); + // 2. 获得社交用户 + SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId(reqDTO.getUserType(), reqDTO.getUserId(), + reqDTO.getSocialType()); if (StrUtil.isBlankIfStr(socialUser.getOpenid())) { - log.warn("[getUserOpenId][userType({}) userId({}) socialType({}) 会员 openid 缺失]", - userType, userId, socialType); - return null; + log.warn("[sendSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:会员 openid 缺失]", reqDTO); + return; } - return socialUser.getOpenid(); + + // 3. 发送订阅消息 + socialClientService.sendSubscribeMessage(reqDTO, template.getId(), socialUser.getOpenid()); } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.http b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.http index b4ba43a09..5ab64392a 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.http +++ b/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 tenant-id: {{adminTenentId}} { - "toUser": "oKNkb4xxw2H135-MVPKtEMkumK08", - "templateId": "W4ybDTIwCfKHtMKR7fSfx83DtmVKEeXQo3Ti7GCw4_4", - "miniprogramState": "developer", - "lang": "zh_CN", + "userId": 247, + "userType": 1, + "socialType": 34, + "templateTitle": "充值成功通知", + "page": "", "messages": { "character_string1":"5616122165165", "amount2":"1000.00", "time3":"2024-01-01 10:10:10", - "phrase4":"成功" + "phrase4": "充值成功" } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java index 08fba16fe..aedc3282c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.system.controller.admin.socail; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; import cn.iocoder.yudao.module.system.api.social.dto.SocialWxSubscribeMessageSendReqDTO; import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientRespVO; @@ -29,6 +29,8 @@ public class SocialClientController { @Resource private SocialClientService socialClientService; + @Resource + private SocialClientApi socialClientApi; @PostMapping("/create") @Operation(summary = "创建社交客户端") @@ -75,7 +77,7 @@ public class SocialClientController { @Operation(summary = "发送订阅消息") // 用于测试 @PreAuthorize("@ss.hasPermission('system:social-client:query')") public void sendSubscribeMessage(@RequestBody SocialWxSubscribeMessageSendReqDTO reqDTO) { - socialClientService.sendSubscribeMessage(reqDTO, UserTypeEnum.MEMBER.getValue()); + socialClientApi.sendSubscribeMessage(reqDTO); } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/social/SocialUserConvert.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/social/SocialUserConvert.java index f0d8c4c18..9e679a242 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/social/SocialUserConvert.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/social/SocialUserConvert.java @@ -1,23 +1,11 @@ package cn.iocoder.yudao.module.system.convert.social; -import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage; -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; -import cn.iocoder.yudao.module.system.api.social.dto.SocialWxSubscribeMessageSendReqDTO; -import cn.iocoder.yudao.module.system.api.social.dto.SocialWxSubscribeTemplateRespDTO; import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserBindReqVO; -import me.chanjar.weixin.common.bean.subscribemsg.TemplateInfo; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; - @Mapper public interface SocialUserConvert { @@ -26,25 +14,4 @@ public interface SocialUserConvert { @Mapping(source = "reqVO.type", target = "socialType") SocialUserBindReqDTO convert(Long userId, Integer userType, SocialUserBindReqVO reqVO); - // TODO @puhui999:要不 convert 直接放到 service 里。 - default WxMaSubscribeMessage convert(SocialWxSubscribeMessageSendReqDTO reqDTO) { - WxMaSubscribeMessage message = BeanUtils.toBean(reqDTO, WxMaSubscribeMessage.class); - Map messages = reqDTO.getMessages(); - if (CollUtil.isNotEmpty(messages)) { - messages.keySet().forEach(key -> findAndThen(messages, key, value -> message.addData(new WxMaSubscribeMessage.MsgData(key, value)))); - } - return message; - } - - // TODO @puhui999:要不 convert 直接放到 service 里。其实可以 BeanUtils.toBean(reqDTO, WxMaSubscribeMessage.class) 来搞的呀。 - @Mapping(target = "id", source = "priTmplId") - SocialWxSubscribeTemplateRespDTO convert(TemplateInfo templateInfo); - - // TODO @puhui999:是不是用 CollectionUtils.convertList 就 ok 啦。 - default List convertList(List subscribeTemplate) { - List list = new ArrayList<>(); - subscribeTemplate.forEach(templateInfo -> list.add(convert(templateInfo))); - return list; - } - } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java index 5d39680ea..6f3480869 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java +++ b/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 { /** * 发送微信小程序订阅消息 * - * @param reqDTO 请求 + * @param reqDTO 请求 + * @param templateId 模版编号 + * @param openId 会员 openId */ - void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO, Integer userType); + void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO, String templateId, String openId); // =================== 客户端管理 =================== diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java index ab888b801..106a6dda3 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java +++ b/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; import cn.binarywang.wx.miniapp.api.WxMaSubscribeService; import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage; import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ReflectUtil; @@ -19,7 +21,6 @@ import cn.iocoder.yudao.module.system.api.social.dto.SocialWxQrcodeReqDTO; import cn.iocoder.yudao.module.system.api.social.dto.SocialWxSubscribeMessageSendReqDTO; import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; -import cn.iocoder.yudao.module.system.convert.social.SocialUserConvert; import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper; import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; @@ -51,9 +52,11 @@ import org.springframework.stereotype.Service; import java.time.Duration; import java.util.List; +import java.util.Map; import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; @@ -273,17 +276,39 @@ public class SocialClientServiceImpl implements SocialClientService { } @Override - public void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO, Integer userType) { - WxMaService service = getWxMaService(userType); + public void sendSubscribeMessage(SocialWxSubscribeMessageSendReqDTO reqDTO, String templateId, String openId) { + WxMaService service = getWxMaService(reqDTO.getUserType()); try { WxMaSubscribeService subscribeService = service.getSubscribeService(); - subscribeService.sendSubscribeMsg(SocialUserConvert.INSTANCE.convert(reqDTO)); + subscribeService.sendSubscribeMsg(buildMessageSendReqDTO(reqDTO, templateId, openId)); } catch (WxErrorException e) { - log.error("[sendSubscribeMessage][reqVO({}) userType({}) 发送小程序订阅消息]", reqDTO, userType, e); + log.error("[sendSubscribeMessage][reqVO({}) templateId({}) openId({}) 发送小程序订阅消息失败]", reqDTO, templateId, openId, e); throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_MESSAGE_ERROR); } } + /** + * 构建发送消息请求参数 + * + * @param openId 接收者(用户)的 openid + * @param path 点击模板卡片后的跳转页面,仅限本小程序内的页面 + * @param template 订阅模版 + * @return 微信小程序订阅消息发送 + */ + private WxMaSubscribeMessage buildMessageSendReqDTO(SocialWxSubscribeMessageSendReqDTO reqDTO, + String templateId, String openId) { + // 1.1 设置订阅消息基本参数 + WxMaSubscribeMessage subscribeMessage = new WxMaSubscribeMessage().setLang("zh_CN").setMiniprogramState(envVersion) + .setTemplateId(templateId).setToUser(openId).setPage(reqDTO.getPage()); + // 1.2 设置具体消息参数 + Map messages = reqDTO.getMessages(); + if (CollUtil.isNotEmpty(messages)) { + messages.keySet().forEach(key -> findAndThen(messages, key, value -> + subscribeMessage.addData(new WxMaSubscribeMessage.MsgData(key, value)))); + } + return subscribeMessage; + } + /** * 获得 clientId + clientSecret 对应的 WxMpService 对象 *