From 53340ab36fddf9eb21124621286214aa01cab54f Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 16 Aug 2024 09:23:13 +0800 Subject: [PATCH] =?UTF-8?q?REQ-2874:=20=E6=94=BF=E5=8A=A1-=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E9=AB=98=E6=96=B0=E5=8C=BA=E7=9F=AD=E4=BF=A1=E6=B8=A0?= =?UTF-8?q?=E9=81=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/PrivateMessageController.java | 50 ++++- .../service/todo/manage/TodoManager.java | 13 ++ .../request/AddChannelTemplateRequest.java | 12 + .../api/request/AddMnsChannelRequest.java | 30 +++ .../center/api/request/MnsSendCodeV2Req.java | 5 + .../api/request/SendMessageRequestDto.java | 10 +- .../UpdateMnsTemplateContentRequest.java | 21 ++ .../request/RevokeByTemplateCodeRequest.java | 30 +++ .../common/enums/ChannelHandlerEnum.java | 1 + .../common/enums/MessageChannelEnum.java | 1 + .../notices/common/enums/ReturnCodeEnum.java | 1 + .../client/impl/RegulatoryGaoxinClient.java | 208 ++++++++++++++++++ .../manager/api/MessageChannelRouter.java | 2 + .../dto/request/MessageSendRequestDto.java | 15 ++ .../api/dto/request/MnsRequestDto.java | 8 + .../plat/CreateTemplateRequestDto.java | 9 +- msg-notices/msg-notices-manager/pom.xml | 4 + .../manager/MessageChannelRouteImpl.java | 23 +- .../manager/RegulatoryGaoxinManager.java | 54 +++++ .../manager/SmsSendManagerComposite.java | 1 + .../service/impl/MessageServiceImpl.java | 3 + .../notices/service/impl/PlatServiceImpl.java | 38 ++-- .../notices/service/manager/SmsManager.java | 6 +- .../service/request/SendCodeV2Req.java | 6 + .../msg/center/api/MNSNoticesApiTest.java | 37 ++++ 25 files changed, 560 insertions(+), 28 deletions(-) create mode 100644 msg-center-api/src/main/java/cn/axzo/msg/center/api/request/AddChannelTemplateRequest.java create mode 100644 msg-center-api/src/main/java/cn/axzo/msg/center/api/request/AddMnsChannelRequest.java create mode 100644 msg-center-api/src/main/java/cn/axzo/msg/center/api/request/UpdateMnsTemplateContentRequest.java create mode 100644 msg-center-api/src/main/java/cn/axzo/msg/center/service/pending/request/RevokeByTemplateCodeRequest.java create mode 100644 msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/center/notices/integration/client/impl/RegulatoryGaoxinClient.java create mode 100644 msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/center/notices/manager/RegulatoryGaoxinManager.java create mode 100644 start/src/test/java/cn/axzo/msg/center/api/MNSNoticesApiTest.java diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/PrivateMessageController.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/PrivateMessageController.java index 14e79a3e..969863c5 100644 --- a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/PrivateMessageController.java +++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/PrivateMessageController.java @@ -1,12 +1,19 @@ package cn.axzo.msg.center.message.controller; +import cn.axzo.msg.center.api.MNSNoticesApi; import cn.axzo.msg.center.api.MessageAPIV3; +import cn.axzo.msg.center.api.request.AddMnsChannelRequest; +import cn.axzo.msg.center.api.request.MnsSendCodeV2Req; +import cn.axzo.msg.center.api.request.SendMessageRequestDto; +import cn.axzo.msg.center.api.request.UpdateMnsTemplateContentRequest; import cn.axzo.msg.center.api.request.v3.MessageSendReqV3; import cn.axzo.msg.center.api.request.v3.SearchMessageReqV3; import cn.axzo.msg.center.api.request.v3.SearchPendingMessageReq; import cn.axzo.msg.center.api.request.v3.SearchTodoLogReq; import cn.axzo.msg.center.api.request.v3.SetImSendPriorityRequest; import cn.axzo.msg.center.api.request.v3.UpdateMnsChannelTemplateRequest; +import cn.axzo.msg.center.dal.MNSMessageTemplateDao; +import cn.axzo.msg.center.domain.entity.MNSMessageTemplate; import cn.axzo.msg.center.im.service.IMService; import cn.axzo.msg.center.inside.notices.service.impl.TodoSearchService; import cn.axzo.msg.center.inside.notices.service.impl.v3.MessageRecordServiceV3; @@ -15,9 +22,11 @@ import cn.axzo.msg.center.message.service.group.GroupTemplateService; import cn.axzo.msg.center.message.service.impl.person.PersonService; import cn.axzo.msg.center.message.service.todo.manage.TodoManager; import cn.axzo.msg.center.message.xxl.MigrateOldMsgHotDataJob; +import cn.axzo.msg.center.notices.manager.api.MessageChannelRouter; import cn.axzo.msg.center.notices.manager.api.MessageTemplateManager; import cn.axzo.msg.center.notices.manager.api.dto.request.plat.CreateTemplateRequestDto; import cn.axzo.msg.center.notices.service.api.PlatService; +import cn.axzo.msg.center.service.pending.request.RevokeByTemplateCodeRequest; import cn.axzo.trade.web.annotation.EnableResponseAdvice; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; @@ -33,11 +42,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.LoaderOptions; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.SafeConstructor; -import org.yaml.snakeyaml.nodes.Tag; -import org.yaml.snakeyaml.representer.Representer; import javax.validation.Valid; import java.util.Map; @@ -64,6 +68,9 @@ public class PrivateMessageController { private final MessageTemplateManager messageTemplateManager; private final PlatService platService; private final ConfigurableEnvironment configurableEnvironment; + private final MNSNoticesApi mnsNoticesApi; + private final MessageChannelRouter messageChannelRouter; + private final MNSMessageTemplateDao mnsMessageTemplateDao; @PostMapping("/sendPendingMessage") @EnableResponseAdvice(enable = false) @@ -71,6 +78,12 @@ public class PrivateMessageController { return todoManager.send(request); } + @PostMapping("/revokeTodoByTemplateCode") + @EnableResponseAdvice(enable = false) + public Object revokeTodoByTemplateCode(@RequestBody @Valid RevokeByTemplateCodeRequest request) { + return todoManager.revokeByTemplateCode(request); + } + @PostMapping("/sendByEventMapping") @EnableResponseAdvice(enable = false) public Object sendByEventMapping(@RequestBody @Valid MessageSendReqV3 request) { @@ -161,6 +174,33 @@ public class PrivateMessageController { return "created"; } + @PostMapping("/sendSms") + @EnableResponseAdvice(enable = false) + public Object sendSms(@RequestBody @Valid SendMessageRequestDto request) { + return mnsNoticesApi.sendMessage(request); + } + + @PostMapping("/sendSmsCode") + @EnableResponseAdvice(enable = false) + public Object sendSmsCode(@RequestBody @Valid MnsSendCodeV2Req request) { + return mnsNoticesApi.sendCodeV2(request); + } + + @PostMapping("/addMnsChannel") + @EnableResponseAdvice(enable = false) + public Object addMnsChannel(@RequestBody @Valid AddMnsChannelRequest request){ + return messageChannelRouter.addChannel(request); + } + + @PostMapping("/updateMnsTemplateContent") + @EnableResponseAdvice(enable = false) + public Object updateMnsTemplateContent(@RequestBody @Valid UpdateMnsTemplateContentRequest request) { + return mnsMessageTemplateDao.lambdaUpdate() + .eq(MNSMessageTemplate::getTemplateNo, request.getInnerTemplateCode()) + .set(MNSMessageTemplate::getTemplateContent, request.getTemplateContent()) + .update(); + } + @PostMapping("/listMnsApps") @EnableResponseAdvice(enable = false) public Object listMnsApps(){ diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/todo/manage/TodoManager.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/todo/manage/TodoManager.java index a573cbe6..a0d254f8 100644 --- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/todo/manage/TodoManager.java +++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/todo/manage/TodoManager.java @@ -34,6 +34,7 @@ import cn.axzo.msg.center.service.pending.request.CompletePendingBySubCodeReques import cn.axzo.msg.center.service.pending.request.CompletePendingMessageByIdRequest; import cn.axzo.msg.center.service.pending.request.CompletePendingMessageRequest; import cn.axzo.msg.center.service.pending.request.PresetButtonPressedRequest; +import cn.axzo.msg.center.service.pending.request.RevokeByTemplateCodeRequest; import cn.axzo.msg.center.service.pending.request.RevokePendingMessageByIdRequest; import cn.axzo.msg.center.service.pending.request.SetHideRequest; import cn.axzo.msg.center.service.pending.request.TodoHandoverRequest; @@ -441,6 +442,18 @@ public class TodoManager { return true; } + @Transactional(rollbackFor = Exception.class) + public boolean revokeByTemplateCode(RevokeByTemplateCodeRequest request) { + TodoRequestContext ctx = TodoRequestContext.create("revokeByTemplateCode", request); + StateAdvanceResult advanceResult = advanceState(ctx, execAdvanceBuilder() + .eq(Todo::getTemplateCode, request.getTemplateCode()) + .set(Todo::getState, PendingMessageStateEnum.RETRACT)); + if (!advanceResult.isAdvanced()) + return false; + todoLogger.logTodoRevoked(ctx, advanceResult.getAdvancedTodos()); + return true; + } + // !! update /** diff --git a/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/AddChannelTemplateRequest.java b/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/AddChannelTemplateRequest.java new file mode 100644 index 00000000..79ca1afc --- /dev/null +++ b/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/AddChannelTemplateRequest.java @@ -0,0 +1,12 @@ +package cn.axzo.msg.center.api.request; + +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +public class AddChannelTemplateRequest { +} \ No newline at end of file diff --git a/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/AddMnsChannelRequest.java b/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/AddMnsChannelRequest.java new file mode 100644 index 00000000..9e898343 --- /dev/null +++ b/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/AddMnsChannelRequest.java @@ -0,0 +1,30 @@ +package cn.axzo.msg.center.api.request; + +import com.alibaba.fastjson.JSON; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @author yanglin + */ +@Setter +@Getter +public class AddMnsChannelRequest { + + @NotBlank(message = "渠道名称不能为空") + private String channelCode; + + @NotBlank(message = "渠道名称不能为空") + private String channelName; + + @NotNull(message = "优先级不能为空") + private Integer priority; + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/MnsSendCodeV2Req.java b/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/MnsSendCodeV2Req.java index 3c584ab8..c21a00c0 100644 --- a/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/MnsSendCodeV2Req.java +++ b/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/MnsSendCodeV2Req.java @@ -31,4 +31,9 @@ public class MnsSendCodeV2Req extends MnsMockReq { private String appCode; @NotBlank(message = "templateNo参数不参为空") private String templateNo; + + /** + * 扩展参数, 和{@link SendMessageRequestDto#getExpansion()}里面的作用一样 + */ + private String expansion; } diff --git a/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/SendMessageRequestDto.java b/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/SendMessageRequestDto.java index 4deed8b2..d65b334a 100644 --- a/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/SendMessageRequestDto.java +++ b/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/SendMessageRequestDto.java @@ -40,7 +40,13 @@ public class SendMessageRequestDto { /** 短信模板变更 */ @NotNull(message = "params must not be null") private Map params = new HashMap<>(); - /** 扩展参数 */ + + /** + * 扩展参数. + * 指定渠道为高新政务: String expansion = "{\"assign_channel\": \"regulatory_gaoxin\"}"; + * 不指定渠道时, 使用默认渠道 (当前为阿里云) + *

这个是很早之前就有的字段了, 不确定是否有其它人在使用, 因此保留为String类型 + */ private String expansion; -} +} \ No newline at end of file diff --git a/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/UpdateMnsTemplateContentRequest.java b/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/UpdateMnsTemplateContentRequest.java new file mode 100644 index 00000000..a6559137 --- /dev/null +++ b/msg-center-api/src/main/java/cn/axzo/msg/center/api/request/UpdateMnsTemplateContentRequest.java @@ -0,0 +1,21 @@ +package cn.axzo.msg.center.api.request; + +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; + +/** + * @author yanglin + */ +@Setter +@Getter +public class UpdateMnsTemplateContentRequest { + + @NotBlank(message = "模板编号不能为空") + private String innerTemplateCode; + + @NotBlank(message = "模板内容不能为空") + private String templateContent; + +} diff --git a/msg-center-api/src/main/java/cn/axzo/msg/center/service/pending/request/RevokeByTemplateCodeRequest.java b/msg-center-api/src/main/java/cn/axzo/msg/center/service/pending/request/RevokeByTemplateCodeRequest.java new file mode 100644 index 00000000..3f7f0d6a --- /dev/null +++ b/msg-center-api/src/main/java/cn/axzo/msg/center/service/pending/request/RevokeByTemplateCodeRequest.java @@ -0,0 +1,30 @@ +package cn.axzo.msg.center.service.pending.request; + +import com.alibaba.fastjson.JSON; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author yanglin + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class RevokeByTemplateCodeRequest implements Serializable { + + /** + * 模版编码 + */ + private String templateCode; + + @Override + public String toString() { + return JSON.toJSONString(this); + } + +} \ No newline at end of file diff --git a/msg-notices/msg-notices-common/src/main/java/cn/axzo/msg/center/notices/common/enums/ChannelHandlerEnum.java b/msg-notices/msg-notices-common/src/main/java/cn/axzo/msg/center/notices/common/enums/ChannelHandlerEnum.java index 541e6471..7bacd999 100644 --- a/msg-notices/msg-notices-common/src/main/java/cn/axzo/msg/center/notices/common/enums/ChannelHandlerEnum.java +++ b/msg-notices/msg-notices-common/src/main/java/cn/axzo/msg/center/notices/common/enums/ChannelHandlerEnum.java @@ -22,6 +22,7 @@ public enum ChannelHandlerEnum implements EnumBase { CHUANG_LAN("chuanglan", "chuangLanSmsSendManager", "创蓝"), SUB_MAIL("sub_mail", "subMailSmsSendManager", "赛邮"), LIAN_LU("lian_lu", "lianLuSmsSendManager", "联麓"), + REGULATORY_GAOXIN("regulatory_gaoxin", "regulatoryGaoxinManager", "监管机构: 高新") ; private final String code; diff --git a/msg-notices/msg-notices-common/src/main/java/cn/axzo/msg/center/notices/common/enums/MessageChannelEnum.java b/msg-notices/msg-notices-common/src/main/java/cn/axzo/msg/center/notices/common/enums/MessageChannelEnum.java index 8d853017..5de4be02 100644 --- a/msg-notices/msg-notices-common/src/main/java/cn/axzo/msg/center/notices/common/enums/MessageChannelEnum.java +++ b/msg-notices/msg-notices-common/src/main/java/cn/axzo/msg/center/notices/common/enums/MessageChannelEnum.java @@ -21,6 +21,7 @@ public enum MessageChannelEnum implements EnumBase { CHUANG_LAN("chuanglan", "创蓝云智"), SUB_MAIL("sub_mail", "赛邮"), LIAN_LU("lian_lu", "联麓"), + REGULATORY_GAOXIN("regulatory_gaoxin", "监管机构: 高新") ; private final String code; diff --git a/msg-notices/msg-notices-common/src/main/java/cn/axzo/msg/center/notices/common/enums/ReturnCodeEnum.java b/msg-notices/msg-notices-common/src/main/java/cn/axzo/msg/center/notices/common/enums/ReturnCodeEnum.java index 1c6c65cf..452a7d54 100644 --- a/msg-notices/msg-notices-common/src/main/java/cn/axzo/msg/center/notices/common/enums/ReturnCodeEnum.java +++ b/msg-notices/msg-notices-common/src/main/java/cn/axzo/msg/center/notices/common/enums/ReturnCodeEnum.java @@ -27,6 +27,7 @@ public enum ReturnCodeEnum implements EnumBase { MESSAGE_TEMPLATE_NOT_EXIST(10003, "短信模板不存在"), MESSAGE_CHANNEL_NOT_VALID(10004, "无可用消息渠道"), MESSAGE_TEMPLATE_NOT_VALID(10005, "短信模板不可用"), + MESSAGE_CHANNEL_EXISTS(10006, "短信渠道已存在"), ; diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/center/notices/integration/client/impl/RegulatoryGaoxinClient.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/center/notices/integration/client/impl/RegulatoryGaoxinClient.java new file mode 100644 index 00000000..b186aa06 --- /dev/null +++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/center/notices/integration/client/impl/RegulatoryGaoxinClient.java @@ -0,0 +1,208 @@ +package cn.axzo.msg.center.notices.integration.client.impl; + +import cn.hutool.core.net.URLEncoder; +import cn.hutool.core.util.BooleanUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Maps; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.context.annotation.Configuration; + +import java.util.Map; + +/** + * 信息中心短信服务组件 + * + * @author liuqibin@axzo.cn + * @date 2023-12-11 + */ +@Log4j2 +@RefreshScope +@Configuration +public class RegulatoryGaoxinClient { + + /** + * 帐号 + */ + @Value("${regulatory.sms.corpId}") + private String corpId; + + /** + * 密码 + */ + @Value("${regulatory.sms.pwd}") + private String pwd; + + /** + * 短信签名 + */ + @Value("${regulatory.sms.signName}") + private String signName; + + /** + * 平台地址 + */ + @Value("${regulatory.sms.url}") + private String url; + + /** + * 直接根据短信内容进行发送 + * + * @param phone 手机号 + * @param content 短信内容 + */ + public String send(String phone, String content) { + //参数判断 + if (StrUtil.isBlank(phone) || StrUtil.isBlank(content)) { + log.warn("必要参数(手机号、内容)信息为空,无法执行短信发送"); + return null; + } + + //组装请求参数 + String requestParam = this.createParam( + phone, content, StrUtil.EMPTY_JSON, Boolean.FALSE + ); + + //执行发送 + return this.executeSend(requestParam); + } + + /** + * 创建请求参数 + * + * @param phone 手机号 + * @param content 短信内容(模板) + * @param params json参数 + * @return 请求参数 + */ + private String createParam(String phone, String content, String params, Boolean formatContent) { + //格式化短信内容信息 + if (BooleanUtil.isTrue(formatContent)) { + content = this.formatContent(content, params); + } + + //添加签名并进行编码 + String encodeContent = this.addSignAndEncodeContent(content); + if (StrUtil.isBlank(encodeContent)) { + log.warn("短信内容信息处理失败,无法进行参数组装操作"); + return StrUtil.EMPTY; + } + + //组装参数并返回 + Map param = Maps.newHashMap(); + param.put("CorpID", corpId); + param.put("Pwd", pwd); + param.put("Mobile", phone); + param.put("Content", encodeContent); + return HttpUtil.toParams(param); + } + + /** + * 执行发送 + * + * @param param 参数 + */ + private String executeSend(String param) { + try { + //构建url + String requestUrl = this.createUrl(param); + + log.info("发送政务短信请求: {}", requestUrl); + + //执行请求 + String result = HttpUtil.post( + requestUrl, StrUtil.EMPTY_JSON + ); + + //打印发送结果 + log.info("短信发送完成,本次执行短信发送的结果为:{}", result); + return result; + } catch (Exception e) { + log.error("执行短信发送出错,错误信息为:", e); + } + return null; + } + + /** + * 构建请求链接信息 + * + * @param params 请求参数 + * @return 请求链接 + */ + private String createUrl(String params) { + return url.concat("?") + .concat(params); + } + + /** + * 格式化短信内容 + * + * @param template 短信模板 + * @param params json参数 + * @return 短信内容 + */ + private String formatContent(String template, String params) { + //转换为json + JSONObject parsed = JSON.parseObject(params); + + //处理参数 + String paramTag; + String key; + Object val; + for (Map.Entry entry : parsed.entrySet()) { + key = entry.getKey(); + val = entry.getValue(); + if (StrUtil.isBlank(key) || ObjectUtil.isNull(val)) { + return StrUtil.EMPTY; + } + paramTag = this.createParamTag(key); + if (StrUtil.isBlank(paramTag)) { + return StrUtil.EMPTY; + } + template = template.replaceAll(paramTag, String.valueOf(val)); + } + + //返回处理结果 + return template; + } + + /** + * 给短信内容添加签名并编码 + *

+ * 需要对内容使用GBK编码 + *

+ * + * @param content 短信内容 + * @return 添加签名 + */ + private String addSignAndEncodeContent(String content) { + if (StrUtil.isBlank(content)) { + return StrUtil.EMPTY; + } + return URLEncoder.ALL.encode( + content.concat(signName), CharsetUtil.CHARSET_GBK + ); + } + + /** + * 创建参数标识:${param} + * + * @param paramName 参数名称 + * @return 参数标识 + */ + private String createParamTag(String paramName) { + if (StrUtil.isBlank(paramName)) { + return StrUtil.EMPTY; + } + return StrUtil.BACKSLASH.concat("$") + .concat(StrUtil.BACKSLASH).concat(StrUtil.DELIM_START) + .concat(paramName).concat(StrUtil.BACKSLASH) + .concat(StrUtil.DELIM_END); + } +} \ No newline at end of file diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/MessageChannelRouter.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/MessageChannelRouter.java index 63a958df..97602dee 100644 --- a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/MessageChannelRouter.java +++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/MessageChannelRouter.java @@ -1,5 +1,6 @@ package cn.axzo.msg.center.notices.manager.api; +import cn.axzo.msg.center.api.request.AddMnsChannelRequest; import cn.axzo.msg.center.domain.entity.MNSMessageChannel; /** @@ -30,4 +31,5 @@ public interface MessageChannelRouter { */ MNSMessageChannel route(String condition, String innerTemplateCode); + String addChannel(AddMnsChannelRequest request); } diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/dto/request/MessageSendRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/dto/request/MessageSendRequestDto.java index 8da6abbd..04e6d93a 100644 --- a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/dto/request/MessageSendRequestDto.java +++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/dto/request/MessageSendRequestDto.java @@ -1,5 +1,7 @@ package cn.axzo.msg.center.notices.manager.api.dto.request; +import cn.axzo.msg.center.domain.entity.MNSChannelMessageTemplate; +import cn.axzo.msg.center.domain.entity.MNSMessageTemplate; import lombok.Data; import java.util.Map; @@ -47,4 +49,17 @@ public class MessageSendRequestDto { */ private String requestChannelNo; + /** + * 短信模版 + */ + private MNSMessageTemplate template; + /** + * 渠道模版信息 + */ + private MNSChannelMessageTemplate channelTemplate; + + /** + * 原始请求 + */ + private MnsRequestDto request; } diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/dto/request/MnsRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/dto/request/MnsRequestDto.java index a51cf27f..ac25cf4b 100644 --- a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/dto/request/MnsRequestDto.java +++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/dto/request/MnsRequestDto.java @@ -1,10 +1,12 @@ package cn.axzo.msg.center.notices.manager.api.dto.request; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; import java.util.Map; @@ -51,6 +53,12 @@ public class MnsRequestDto { private Object internalObj; + public JSONObject parseExpansion() { + if (StringUtils.isBlank(expansion)) + return new JSONObject(); + return JSON.parseObject(expansion); + } + public T getInternalObj(Class clazz) { return clazz.isInstance(internalObj) ? clazz.cast(internalObj) : null; } diff --git a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/dto/request/plat/CreateTemplateRequestDto.java b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/dto/request/plat/CreateTemplateRequestDto.java index 4dcde9f4..0e7ac8d7 100644 --- a/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/dto/request/plat/CreateTemplateRequestDto.java +++ b/msg-notices/msg-notices-manager-api/src/main/java/cn/axzo/msg/center/notices/manager/api/dto/request/plat/CreateTemplateRequestDto.java @@ -21,12 +21,12 @@ public class CreateTemplateRequestDto { /** * 短信模板编码 */ - private String templateNo; + private String innerTemplateNo; /** * 阿里短信模板编码 */ - private String templateAliNo; + private String channelTemplateCode; /** * 标题 @@ -42,4 +42,9 @@ public class CreateTemplateRequestDto { * 模板原因 */ private String remark; + + /** + * 渠道 + */ + private String channel; } diff --git a/msg-notices/msg-notices-manager/pom.xml b/msg-notices/msg-notices-manager/pom.xml index fe154d9e..bf2c1a96 100644 --- a/msg-notices/msg-notices-manager/pom.xml +++ b/msg-notices/msg-notices-manager/pom.xml @@ -20,6 +20,10 @@ + + cn.axzo.msgcenter + msg-center-common + com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/center/notices/manager/MessageChannelRouteImpl.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/center/notices/manager/MessageChannelRouteImpl.java index 1db29a35..e71c03e8 100644 --- a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/center/notices/manager/MessageChannelRouteImpl.java +++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/center/notices/manager/MessageChannelRouteImpl.java @@ -1,5 +1,6 @@ package cn.axzo.msg.center.notices.manager; +import cn.axzo.msg.center.api.request.AddMnsChannelRequest; import cn.axzo.msg.center.dal.MNSMessageChannelDao; import cn.axzo.msg.center.domain.entity.MNSMessageChannel; import cn.axzo.msg.center.notices.common.constans.CommonConstants; @@ -16,7 +17,12 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.*; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; /** * 消息渠道路由实现类 @@ -73,6 +79,21 @@ public class MessageChannelRouteImpl implements MessageChannelRouter { .orElse(null); } + @Override + public String addChannel(AddMnsChannelRequest request) { + MNSMessageChannel savedChannel = mnsMessageChannelDao.lambdaQuery() + .eq(MNSMessageChannel::getChannelCode, request.getChannelCode()) + .last("LIMIT 1") + .one(); + BizException.error(savedChannel == null, ReturnCodeEnum.MESSAGE_CHANNEL_EXISTS); + MNSMessageChannel channel = new MNSMessageChannel(); + channel.setChannelCode(request.getChannelCode()); + channel.setChannelName(request.getChannelName()); + channel.setPriority(request.getPriority()); + mnsMessageChannelDao.save(channel); + return channel.getId() + ""; + } + private String parseCondition(String condition) { if (StringUtils.isEmpty(condition)) { // 未指定渠道 diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/center/notices/manager/RegulatoryGaoxinManager.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/center/notices/manager/RegulatoryGaoxinManager.java new file mode 100644 index 00000000..71c2cc3f --- /dev/null +++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/center/notices/manager/RegulatoryGaoxinManager.java @@ -0,0 +1,54 @@ +package cn.axzo.msg.center.notices.manager; + +import cn.axzo.msg.center.common.utils.PlaceholderResolver; +import cn.axzo.msg.center.notices.integration.client.impl.RegulatoryGaoxinClient; +import cn.axzo.msg.center.notices.manager.api.SmsSendManager; +import cn.axzo.msg.center.notices.manager.api.dto.request.BatchMessageSendRequestDto; +import cn.axzo.msg.center.notices.manager.api.dto.request.MessageSendRequestDto; +import cn.axzo.msg.center.notices.manager.api.dto.response.BatchMessageSendResponseDto; +import cn.axzo.msg.center.notices.manager.api.dto.response.SendSmsCommonResponseDto; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 政务系统 + * + * @author yanglin + */ +@Slf4j +@RequiredArgsConstructor +@Service("regulatoryGaoxinManager") +public class RegulatoryGaoxinManager implements SmsSendManager { + + private static final String USE_CHANNEL_CONTENT = "use_channel_content"; + + private final RegulatoryGaoxinClient regulatoryGaoxinClient; + + @Override + public SendSmsCommonResponseDto sendMessage(MessageSendRequestDto request) { + log.info("[RegulatoryAuthorityManager#sendMessage] -> 政务 - 发送sms {}", JSON.toJSONString(request)); + JSONObject expansion = request.getRequest().parseExpansion(); + Boolean useChannelContent = expansion.getBoolean(USE_CHANNEL_CONTENT); + if (useChannelContent == null) useChannelContent = false; + String templateContent = useChannelContent + ? request.getChannelTemplate().getTemplateContent() + : request.getTemplate().getTemplateContent(); + String content = PlaceholderResolver.getDefaultResolver().resolveByMap( + templateContent, request.getTemplateMap()); + String respStr = regulatoryGaoxinClient.send(request.getPhoneNo(), content); + SendSmsCommonResponseDto result = new SendSmsCommonResponseDto(); + result.setBizId(respStr); + result.setRequestId(""); + result.setMessage(""); + return result; + } + + @Override + public BatchMessageSendResponseDto sendBatchMessage(BatchMessageSendRequestDto requestDto) { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/center/notices/manager/SmsSendManagerComposite.java b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/center/notices/manager/SmsSendManagerComposite.java index 88c6bb9e..a25bf387 100644 --- a/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/center/notices/manager/SmsSendManagerComposite.java +++ b/msg-notices/msg-notices-manager/src/main/java/cn/axzo/msg/center/notices/manager/SmsSendManagerComposite.java @@ -69,6 +69,7 @@ public class SmsSendManagerComposite implements SmsSendManager, ApplicationConte saveMessageChannelLog(request, e); throw e; } catch (Exception e) { + log.warn("SmsSendManagerComposite#sendMessage is Exception", e); LogUtil.error("SmsSendManagerComposite#sendMessage is Exception", e); // 保存渠道日志 saveMessageChannelLog(request, e.getMessage()); diff --git a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MessageServiceImpl.java b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MessageServiceImpl.java index 7687dd31..d28155f0 100644 --- a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MessageServiceImpl.java +++ b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MessageServiceImpl.java @@ -173,6 +173,9 @@ public class MessageServiceImpl implements MessageService, EnvironmentAware { dto.setTemplateMap(request.getParams()); dto.setAppRequestNo(message.getRequestNo()); dto.setRequestChannelNo(message.getMessageOrderNo()); + dto.setTemplate(messageTemplate); + dto.setChannelTemplate(channelTemplate); + dto.setRequest(request); SendSmsCommonResponseDto response = smsSendManagerComposite.sendMessage(dto); messageManager.updateToProcessing(response.getBizId(), response.getRequestId(), message.getId()); mnsLimiter.setSendSuccess(request); diff --git a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/PlatServiceImpl.java b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/PlatServiceImpl.java index 444a93a7..bf41d7fe 100644 --- a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/PlatServiceImpl.java +++ b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/PlatServiceImpl.java @@ -52,8 +52,7 @@ public class PlatServiceImpl implements PlatService { @Override @Transactional(rollbackFor = Exception.class) public void createTemplate(CreateTemplateRequestDto request) { - String remark = request.getRemark(); - ChannelHandlerEnum channel = parseChannel(remark); + ChannelHandlerEnum channel = parseChannel(request.getChannel()); checkCreateTemplate(request, channel); insertMessageApp(request.getServiceName()); @@ -62,10 +61,13 @@ public class PlatServiceImpl implements PlatService { insertChannelMessageTemplate(request, channel); - insertMessageTemplateParam(request.getTemplateAliNo(), request.getTemplateContent()); + insertMessageTemplateParam(request.getChannelTemplateCode(), request.getTemplateContent()); } - private ChannelHandlerEnum parseChannel(String expStr) { + private ChannelHandlerEnum parseChannel(String channelCode) { + ChannelHandlerEnum channel = ChannelHandlerEnum.getByCode(channelCode); + if (channel != null) + return channel; return ChannelHandlerEnum.ALI_YUN; } @@ -99,11 +101,11 @@ public class PlatServiceImpl implements PlatService { if (request.getMessageTemplateType() == null) { throw new BizException(ReturnCodeEnum.FAIL, "模板类型不能为空"); } - if (StringUtils.isBlank(request.getTemplateNo())) { - throw new BizException(ReturnCodeEnum.FAIL, "短信模板编码不能为空"); + if (StringUtils.isBlank(request.getInnerTemplateNo())) { + throw new BizException(ReturnCodeEnum.FAIL, "内部短信模板编码不能为空"); } - if (StringUtils.isBlank(request.getTemplateAliNo())) { - throw new BizException(ReturnCodeEnum.FAIL, "阿里短信模板编码不能为空"); + if (StringUtils.isBlank(request.getChannelTemplateCode())) { + throw new BizException(ReturnCodeEnum.FAIL, "渠道短信模板编码不能为空"); } if (StringUtils.isBlank(request.getTitle())) { throw new BizException(ReturnCodeEnum.FAIL, "标题不能为空"); @@ -114,15 +116,15 @@ public class PlatServiceImpl implements PlatService { // 判断短信编码是否存在 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(MNSChannelMessageTemplate::getChannelCode, channel.getCode()); - queryWrapper.eq(MNSChannelMessageTemplate::getTemplateNo, request.getTemplateAliNo()); + queryWrapper.eq(MNSChannelMessageTemplate::getTemplateNo, request.getChannelTemplateCode()); // 一个内部模板可以映射多个渠道商 - queryWrapper.eq(MNSChannelMessageTemplate::getInnerTemplateNo, request.getTemplateNo()); + queryWrapper.eq(MNSChannelMessageTemplate::getInnerTemplateNo, request.getInnerTemplateNo()); List list = mnsChannelMessageTemplateMapper.selectList(queryWrapper); if (CollectionUtils.isNotEmpty(list)) { MNSChannelMessageTemplate channelMessageTemplate = list.get(0); String templateNo = channelMessageTemplate.getTemplateNo(); String innerTemplateNo = channelMessageTemplate.getInnerTemplateNo(); - String templatNo = templateNo.equals(request.getTemplateAliNo()) ? templateNo : innerTemplateNo; + String templatNo = templateNo.equals(request.getChannelTemplateCode()) ? templateNo : innerTemplateNo; throw new BizException(ReturnCodeEnum.FAIL, "模板编码已存在:" + templatNo); } } @@ -132,14 +134,14 @@ public class PlatServiceImpl implements PlatService { */ private void insertMessageTemplate(CreateTemplateRequestDto request) { LambdaQueryWrapper query = new LambdaQueryWrapper<>(); - query.eq(MNSMessageTemplate::getTemplateNo, request.getTemplateNo()) + query.eq(MNSMessageTemplate::getTemplateNo, request.getInnerTemplateNo()) .eq(MNSMessageTemplate::getIsDelete, YesNoEnum.NO.getCode()); List messageTemplates = mnsMessageTemplateMapper.selectList(query); if (CollectionUtils.isNotEmpty(messageTemplates)) { return; } MNSMessageTemplate messageTemplate = new MNSMessageTemplate(); - messageTemplate.setTemplateNo(request.getTemplateNo()); + messageTemplate.setTemplateNo(request.getInnerTemplateNo()); messageTemplate.setTitle(request.getTitle()); messageTemplate.setType(request.getMessageTemplateType()); messageTemplate.setTemplateContent(request.getTemplateContent()); @@ -155,9 +157,15 @@ public class PlatServiceImpl implements PlatService { * 插入 ChannelMessageTemplate */ private void insertChannelMessageTemplate(CreateTemplateRequestDto request, ChannelHandlerEnum channel) { + List templates = mnsChannelMessageTemplateMapper.selectList( + query(MNSChannelMessageTemplate.class) + .eq(MNSChannelMessageTemplate::getChannelCode, channel.getCode()) + .eq(MNSChannelMessageTemplate::getTemplateNo, request.getChannelTemplateCode()) + .eq(MNSChannelMessageTemplate::getInnerTemplateNo, request.getInnerTemplateNo())); + if (CollectionUtils.isNotEmpty(templates)) return; MNSChannelMessageTemplate channelMessageTemplate = new MNSChannelMessageTemplate(); - channelMessageTemplate.setInnerTemplateNo(request.getTemplateNo()); - channelMessageTemplate.setTemplateNo(request.getTemplateAliNo()); + channelMessageTemplate.setInnerTemplateNo(request.getInnerTemplateNo()); + channelMessageTemplate.setTemplateNo(request.getChannelTemplateCode()); channelMessageTemplate.setChannelCode(channel.getCode()); channelMessageTemplate.setChannelName(channel.getDesc()); channelMessageTemplate.setTitle(request.getTitle()); diff --git a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/manager/SmsManager.java b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/manager/SmsManager.java index eb91fb3a..e553e182 100644 --- a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/manager/SmsManager.java +++ b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/manager/SmsManager.java @@ -32,7 +32,6 @@ import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import javax.validation.constraints.NotNull; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -75,7 +74,7 @@ public class SmsManager extends BaseManager implements SmsGateway { * @return */ public int sendSmsCode(SendCodeV2Req req) { - sendMnsCode(req.getPhone(), req.getParam(), req.getAppCode(),req.getTemplateNo(), req.getCode()); + sendMnsCode(req.getPhone(), req.getParam(), req.getAppCode(),req.getTemplateNo(), req.getCode(), req.getExpansion()); log.info("发送验证码 手机号{} -- 参数 {} -- 应用程序code {} -- 模板编号templateCode {}", req.getPhone(), req.getParam(), req.getAppCode(),req.getTemplateNo()); return req.getCode(); } @@ -183,7 +182,7 @@ public class SmsManager extends BaseManager implements SmsGateway { } } - public void sendMnsCode(String phoneNumber, Map param, String appCode, String templateNo, Integer code) { + public void sendMnsCode(String phoneNumber, Map param, String appCode, String templateNo, Integer code, String expansion) { if (!isSendMnsCode) { return; } @@ -194,6 +193,7 @@ public class SmsManager extends BaseManager implements SmsGateway { request.setParams(param); request.setRequestNo(UUID.randomUUID().toString()); request.setInternalObj(MnsType.VERIFY_CODE); + request.setExpansion(expansion); messageService.sendMessage(request); } } diff --git a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/request/SendCodeV2Req.java b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/request/SendCodeV2Req.java index 4521e141..fe5c5f90 100644 --- a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/request/SendCodeV2Req.java +++ b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/request/SendCodeV2Req.java @@ -1,5 +1,6 @@ package cn.axzo.msg.center.notices.service.request; +import cn.axzo.msg.center.api.request.SendMessageRequestDto; import lombok.Data; import lombok.EqualsAndHashCode; @@ -31,4 +32,9 @@ public class SendCodeV2Req extends MockReq { private String appCode; @NotBlank(message = "templateNo参数不参为空") private String templateNo; + + /** + * 扩展参数, 和{@link SendMessageRequestDto#getExpansion()}里面的作用一样 + */ + private String expansion; } diff --git a/start/src/test/java/cn/axzo/msg/center/api/MNSNoticesApiTest.java b/start/src/test/java/cn/axzo/msg/center/api/MNSNoticesApiTest.java new file mode 100644 index 00000000..192de9ac --- /dev/null +++ b/start/src/test/java/cn/axzo/msg/center/api/MNSNoticesApiTest.java @@ -0,0 +1,37 @@ +package cn.axzo.msg.center.api; + +import cn.axzo.msg.center.MsgCenterApplication; +import cn.axzo.msg.center.api.request.MnsSendCodeV2Req; +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.HashMap; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author yanglin + */ +@SpringBootTest(classes = MsgCenterApplication.class) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +class MNSNoticesApiTest { + + private final MNSNoticesApi mNSNoticesApi; + + @Test + void exec() { + HashMap param = new HashMap<>(); + int code = 15; + param.put("code", code); + MnsSendCodeV2Req req = new MnsSendCodeV2Req(); + req.setCode(code); + req.setAppCode("pudge"); + req.setTemplateNo("pudge_100000031_regulatory"); + req.setParam(param); + req.setPhone("18608045398"); + mNSNoticesApi.sendCodeV2(req); + } + +} \ No newline at end of file