diff --git a/msg-center-domain/src/main/java/cn/axzo/msg/center/domain/entity/MNSMessage.java b/msg-center-domain/src/main/java/cn/axzo/msg/center/domain/entity/MNSMessage.java index ee1a9012..01ef677a 100644 --- a/msg-center-domain/src/main/java/cn/axzo/msg/center/domain/entity/MNSMessage.java +++ b/msg-center-domain/src/main/java/cn/axzo/msg/center/domain/entity/MNSMessage.java @@ -2,6 +2,7 @@ package cn.axzo.msg.center.domain.entity; import cn.axzo.msg.center.domain.persistence.BaseOwnEntity; import cn.axzo.trade.datasecurity.core.annotation.CryptField; +import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -129,4 +130,8 @@ public class MNSMessage extends BaseOwnEntity { return this.id; } + @Override + public String toString() { + return JSON.toJSONString(this); + } } diff --git a/msg-center-domain/src/main/java/cn/axzo/msg/center/domain/entity/MNSMessageTemplate.java b/msg-center-domain/src/main/java/cn/axzo/msg/center/domain/entity/MNSMessageTemplate.java index e42ef9bd..b19058e5 100644 --- a/msg-center-domain/src/main/java/cn/axzo/msg/center/domain/entity/MNSMessageTemplate.java +++ b/msg-center-domain/src/main/java/cn/axzo/msg/center/domain/entity/MNSMessageTemplate.java @@ -2,6 +2,7 @@ package cn.axzo.msg.center.domain.entity; import cn.axzo.msg.center.domain.enums.YesNoEnum; import cn.axzo.msg.center.domain.persistence.BaseOwnEntity; +import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -79,6 +80,11 @@ public class MNSMessageTemplate extends BaseOwnEntity { return this.id; } + @Override + public String toString() { + return JSON.toJSONString(this); + } + public boolean hasParam() { return YesNoEnum.YES.getCode().equals(hasParam); } diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/center/notices/integration/client/impl/AliYunSmsClientImpl.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/center/notices/integration/client/impl/AliYunSmsClientImpl.java index 1266967e..882e4b83 100644 --- a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/center/notices/integration/client/impl/AliYunSmsClientImpl.java +++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/center/notices/integration/client/impl/AliYunSmsClientImpl.java @@ -184,8 +184,11 @@ public class AliYunSmsClientImpl implements AliYunSmsClient { String message = responseBody.getMessage(); boolean isRateLimited = message != null && message.contains("触发") && message.contains("流控"); log.warn("AliyunSmsService#checkResponse is fail, error message : {}", message); - if (!isRateLimited) + if (isRateLimited) { + throw new RateLimitException(ReturnCodeEnum.SYSTEM_ERROR, message); + } else { throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, message); + } } return responseBody; } diff --git a/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/center/notices/integration/client/impl/RateLimitException.java b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/center/notices/integration/client/impl/RateLimitException.java new file mode 100644 index 00000000..81578bc5 --- /dev/null +++ b/msg-notices/msg-notices-integration/src/main/java/cn/axzo/msg/center/notices/integration/client/impl/RateLimitException.java @@ -0,0 +1,15 @@ +package cn.axzo.msg.center.notices.integration.client.impl; + +import cn.axzo.msg.center.notices.common.enums.ReturnCodeEnum; +import cn.axzo.msg.center.notices.common.exception.BizException; + +/** + * @author yanglin + */ +public class RateLimitException extends BizException { + + public RateLimitException(ReturnCodeEnum returnCode, String message) { + super(returnCode, message); + } + +} 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 cfccbe0e..a51cf27f 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,5 +1,6 @@ package cn.axzo.msg.center.notices.manager.api.dto.request; +import com.alibaba.fastjson.JSON; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -48,4 +49,14 @@ public class MnsRequestDto { */ private String expansion; + private Object internalObj; + + public T getInternalObj(Class clazz) { + return clazz.isInstance(internalObj) ? clazz.cast(internalObj) : null; + } + + @Override + public String toString() { + return JSON.toJSONString(this); + } } diff --git a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MNSNoticesApiImpl.java b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MNSNoticesApiImpl.java index fc38206b..1d2f0b43 100644 --- a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MNSNoticesApiImpl.java +++ b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MNSNoticesApiImpl.java @@ -64,6 +64,7 @@ public class MNSNoticesApiImpl implements MNSNoticesApi { BeanUtils.copyProperties(request, mnsRequestDto); log.info("request value={},mnsRequestDto value={}", JSONUtil.toJsonStr(request),JSONUtil.toJsonStr(mnsRequestDto)); try { + mnsRequestDto.setInternalObj(MnsType.BIZ); messageService.sendMessage(mnsRequestDto); return CommonResponse.success(); } catch (Exception e) { 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 1c575eee..9dd1e063 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 @@ -1,17 +1,37 @@ package cn.axzo.msg.center.notices.service.impl; +import cn.axzo.msg.center.common.utils.PlaceholderResolver; import cn.axzo.msg.center.dal.MNSMessageAppDao; -import cn.axzo.msg.center.domain.entity.*; +import cn.axzo.msg.center.domain.entity.MNSBatchMessageRequest; +import cn.axzo.msg.center.domain.entity.MNSChannelMessageTemplate; +import cn.axzo.msg.center.domain.entity.MNSMessage; +import cn.axzo.msg.center.domain.entity.MNSMessageApp; +import cn.axzo.msg.center.domain.entity.MNSMessageChannel; +import cn.axzo.msg.center.domain.entity.MNSMessageRedo; +import cn.axzo.msg.center.domain.entity.MNSMessageTemplate; import cn.axzo.msg.center.domain.enums.YesNoEnum; import cn.axzo.msg.center.notices.common.annotation.ApiRequestLog; import cn.axzo.msg.center.notices.common.constans.CommonConstants; import cn.axzo.msg.center.notices.common.domain.BatchMessageSendContext; import cn.axzo.msg.center.notices.common.domain.MessageContext; -import cn.axzo.msg.center.notices.common.enums.*; +import cn.axzo.msg.center.notices.common.enums.AvailableStatusEnum; +import cn.axzo.msg.center.notices.common.enums.BatchMessageRequestStatusEnum; +import cn.axzo.msg.center.notices.common.enums.BatchSendTypeEnum; +import cn.axzo.msg.center.notices.common.enums.MessageStatusEnum; +import cn.axzo.msg.center.notices.common.enums.MessageTypeEnum; +import cn.axzo.msg.center.notices.common.enums.NotifyTypeEnum; +import cn.axzo.msg.center.notices.common.enums.RetryingFlagEnum; +import cn.axzo.msg.center.notices.common.enums.ReturnCodeEnum; import cn.axzo.msg.center.notices.common.exception.BizException; import cn.axzo.msg.center.notices.common.utils.DateUtils; import cn.axzo.msg.center.notices.integration.client.DingDingClient; -import cn.axzo.msg.center.notices.manager.api.*; +import cn.axzo.msg.center.notices.integration.client.impl.RateLimitException; +import cn.axzo.msg.center.notices.manager.api.BatchMessageRequestManger; +import cn.axzo.msg.center.notices.manager.api.MessageChannelRouter; +import cn.axzo.msg.center.notices.manager.api.MessageManager; +import cn.axzo.msg.center.notices.manager.api.MessageTemplateManager; +import cn.axzo.msg.center.notices.manager.api.RetryStrategy; +import cn.axzo.msg.center.notices.manager.api.SmsSendManager; import cn.axzo.msg.center.notices.manager.api.dto.request.MessageSendRequestDto; import cn.axzo.msg.center.notices.manager.api.dto.request.MnsRequestDto; import cn.axzo.msg.center.notices.manager.api.dto.request.SendBatchMessageRequestDto; @@ -30,7 +50,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.context.EnvironmentAware; @@ -38,8 +57,12 @@ import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.*; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; @@ -84,6 +107,9 @@ public class MessageServiceImpl implements MessageService, EnvironmentAware { @Resource(name = "userCellphoneProperties") private UserCellphoneProperties userCellphoneProperties; + @Resource + private MnsLimiter mnsLimiter; + @Value("${prod.profile.string:master}") private String prodProfileString; @@ -109,6 +135,8 @@ public class MessageServiceImpl implements MessageService, EnvironmentAware { boolean isLegalPhone = PhoneUtil.isPhone(request.getPhoneNo()); BizException.error(isLegalPhone, ReturnCodeEnum.INVALID_PARAMETER, "非法的手机号:" + request.getPhoneNo()); + mnsLimiter.maybeLimitSend(request); + // 查询并校验 MNSMessageTemplate messageTemplate = messageTemplateManager.queryAndCheckInnerTemplate(request.getTemplateNo()); @@ -147,12 +175,19 @@ public class MessageServiceImpl implements MessageService, EnvironmentAware { dto.setRequestChannelNo(message.getMessageOrderNo()); SendSmsCommonResponseDto response = smsSendManagerComposite.sendMessage(dto); messageManager.updateToProcessing(response.getBizId(), response.getRequestId(), message.getId()); + mnsLimiter.setSendSuccess(request); + } catch (RateLimitException e) { + messageManager.updateToFail(message.getId()); + mnsLimiter.setSendFail(request, e); + // don't rethrow rate limit exception to let client retry } catch (BizException e) { messageManager.updateToFail(message.getId()); + mnsLimiter.setSendFail(request, e); throw e; } } catch (Exception e) { dingDingClient.notifySingleMessage(request.getTemplateNo(), request.getRequestNo(), e.getMessage()); + mnsLimiter.setSendFail(request, e); throw e; } } @@ -206,7 +241,15 @@ public class MessageServiceImpl implements MessageService, EnvironmentAware { message.setChannelName(CommonConstants.MOCK_CHANNEL); message.updateById(); - String messageContent = parse(template.getTemplateContent(), request.getParams()); + String messageContent; + try { + messageContent = PlaceholderResolver.tryResolve(template.getTemplateContent(), request.getParams()); + } catch (Exception e) { + log.warn("fail to resolve template content, fallback to old method. request={}, template={}, message={}", + request, template, message, e); + //fallback + messageContent = parse(template.getTemplateContent(), request.getParams()); + } dingDingClient.notifyMockMessage(request.getPhoneNo(), template.getTitle(), messageContent); } diff --git a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MnsLimiter.java b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MnsLimiter.java new file mode 100644 index 00000000..639a5fd7 --- /dev/null +++ b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MnsLimiter.java @@ -0,0 +1,172 @@ +package cn.axzo.msg.center.notices.service.impl; + +import cn.axzo.basics.common.exception.ServiceException; +import cn.axzo.msg.center.notices.common.enums.ReturnCodeEnum; +import cn.axzo.msg.center.notices.manager.api.dto.request.MnsRequestDto; +import com.google.common.hash.Hasher; +import com.google.common.hash.Hashing; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +/** + * @author yanglin + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class MnsLimiter { + + private final MnsProperties props; + private final StringRedisTemplate stringRedisTemplate; + + /** + * 基于固定窗口, 限制重复内容的发送次数 + */ + void maybeLimitSend(MnsRequestDto request) { + if (!props.shouldLimit(request.getTemplateNo())) { + return; + } + // key中包含了固定窗口因子 + String key = buildTimeAwareKey(request); + String countStr = stringRedisTemplate.opsForValue().get(key); + if (StringUtils.isBlank(countStr)) { + return; + } + long alreadySendCount = Long.parseLong(countStr); + + MnsType msnType = request.getInternalObj(MnsType.class); + if (msnType == null) msnType = MnsType.BIZ; + + long limitCount; + String error; + if (msnType == MnsType.BIZ) { + limitCount = props.getBizLimitPerDay(); + error = String.format("业务短信: 每天发送给同一个手机号的重复内容不能超过 %s 条。 请勿重试发送!!", limitCount); + } else { + limitCount = props.getVerifyCodeLimitPerWindow(); + error = String.format("验证码短信: 每 %s 分钟发送给同一个手机号的重复内容不能超过 %s 条。 请勿重试发送!!", + props.getVerifyCodeLimitWindowMinutes(), limitCount); + } + if (alreadySendCount + 1 > limitCount) { + log.warn("{}, request={}", error, request); + throw new ServiceException(ReturnCodeEnum.FAIL.getCode(), error); + } + } + + void setSendSuccess(MnsRequestDto request) { + if (!props.shouldLimit(request.getTemplateNo())) { + return; + } + // key中包含了固定窗口因子 + String key = buildTimeAwareKey(request); + stringRedisTemplate.opsForValue().increment(key); + // 这里设置过期时间只是为了删除对应的key, 和限制逻辑本身没有太大的关系 + long expireMinutes = getTimeAwareExpireTimeMinutes(request); + // 延迟删除 + stringRedisTemplate.expire(key, expireMinutes + 1, TimeUnit.MINUTES); + } + + void setSendFail(MnsRequestDto request, Exception e) { + // NOP + } + + /** + * 获取key过期时间 + */ + private long getTimeAwareExpireTimeMinutes(MnsRequestDto request) { + MnsType msnType = request.getInternalObj(MnsType.class); + if (msnType == null) { + msnType = MnsType.BIZ; + } + return msnType == MnsType.BIZ + ? TimeUnit.DAYS.toMinutes(1) + : props.getVerifyCodeLimitWindowMinutes(); + } + + /** + * 构建包含时间元素的缓存key, key中包含了固定窗口因子. 固定窗口: 限制发送重复的内容 + */ + private String buildTimeAwareKey(MnsRequestDto request) { + MnsType msnType = request.getInternalObj(MnsType.class); + if (msnType == null) { + msnType = MnsType.BIZ; + } + StringBuilder buf = new StringBuilder(); + buf.append("msg-center:mns_limit"); + Consumer appender = value -> { + if (StringUtils.isNotBlank(value)) + buf.append(":").append(value); + }; + // 通过templateNo和params就可以判断出发送的内容是不是一样的 + appender.accept(msnType.name()); + appender.accept(request.getTemplateNo()); + appender.accept(request.getPhoneNo()); + appender.accept(buildTimeAwareSegment(request)); + appender.accept(hashParams(request.getParams())); + return buf.toString(); + } + + private String buildTimeAwareSegment(MnsRequestDto request) { + MnsType mnsType = request.getInternalObj(MnsType.class); + if (mnsType == null) { + mnsType = MnsType.BIZ; + } + Date now = new Date(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); + int windowMinutes = props.getVerifyCodeLimitWindowMinutes(); + return mnsType == MnsType.BIZ + ? sdf.format(now) + : String.format("%s-%d-%d", + sdf.format(now), windowMinutes, getVerifySegmentIndex(now, windowMinutes)); + } + + public static int getVerifySegmentIndex(Date now, int windowMinutes) { + DateTime dateTime = new DateTime(now, DateTimeZone.forID("Asia/Shanghai")); + // Calculate the total number of intervals in a day + int intervalsPerDay = 24 * 60 / windowMinutes; + // Get the current time in minutes + int currentMinutes = dateTime.getHourOfDay() * 60 + dateTime.getMinuteOfHour(); + // Find the index of the interval that the current time falls into + int intervalIndex = currentMinutes / windowMinutes; + // Ensure the index is within the range of the array + if (intervalIndex >= intervalsPerDay) { + intervalIndex = intervalsPerDay - 1; + } + return intervalIndex; + } + + @SuppressWarnings("UnstableApiUsage") + private static String hashParams(Map params) { + if (params == null || params.isEmpty()) { + return ""; + } + Hasher hasher = Hashing.murmur3_128().newHasher(); + Consumer appender = value -> { + if (value != null) { + hasher.putString(String.valueOf(value), StandardCharsets.UTF_8); + } + }; + for (Map.Entry e : new TreeMap<>(params).entrySet()) { + if (e.getKey() == null || e.getValue() == null) { + continue; + } + appender.accept(e.getKey()); + appender.accept(e.getValue()); + } + return hasher.hash().toString(); + } + +} \ No newline at end of file diff --git a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MnsProperties.java b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MnsProperties.java new file mode 100644 index 00000000..9f2e65c6 --- /dev/null +++ b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MnsProperties.java @@ -0,0 +1,54 @@ +package cn.axzo.msg.center.notices.service.impl; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.context.annotation.Configuration; + +/** + * @author yanglin + */ +@Setter +@Getter +@RefreshScope +@Configuration +@ConfigurationProperties(prefix = "user.cellphone") +public class MnsProperties { + + /** + * 是否开启重复发送限制 + */ + private boolean sendLimitOn = true; + + /** + * 不验证重复发送的内部模板编码 + */ + private String limitWhitelist; + + /** + * 业务上每天发送重复内容的次数限制 + */ + private long bizLimitPerDay = 20; + + /** + * 验证码15分钟内发送的内容都是一样的 + */ + private int verifyCodeLimitWindowMinutes = 15; + + /** + * 验证码每15分钟可以重复发送的次数 + */ + private long verifyCodeLimitPerWindow = 20; + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public boolean shouldLimit(String templateNo) { + return sendLimitOn && !isInLimitWhitelist(templateNo); + } + + private boolean isInLimitWhitelist(String templateNo) { + return StringUtils.isNotBlank(limitWhitelist) + && limitWhitelist.contains(templateNo); + } +} \ No newline at end of file diff --git a/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MnsType.java b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MnsType.java new file mode 100644 index 00000000..8d91ac82 --- /dev/null +++ b/msg-notices/msg-notices-service/src/main/java/cn/axzo/msg/center/notices/service/impl/MnsType.java @@ -0,0 +1,15 @@ +package cn.axzo.msg.center.notices.service.impl; + +/** + * @author yanglin + */ +public enum MnsType { + /** + * 业务短信 + */ + BIZ, + /** + * 验证码 + */ + VERIFY_CODE +} \ No newline at end of file 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 7732b4c2..d53f72ce 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 @@ -10,6 +10,7 @@ import cn.axzo.msg.center.notices.common.properties.SmsProperties; import cn.axzo.msg.center.notices.manager.api.dto.request.MnsRequestDto; import cn.axzo.msg.center.notices.service.api.MessageService; import cn.axzo.msg.center.notices.service.gateway.SmsGateway; +import cn.axzo.msg.center.notices.service.impl.MnsType; import cn.axzo.msg.center.notices.service.request.CaptchaParam; import cn.axzo.msg.center.notices.service.request.SendCodeV2Req; import cn.axzo.msg.center.notices.service.response.SmsCodeInfoRes; @@ -31,7 +32,13 @@ import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.*; +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; /** * @author zhangPeng @@ -68,7 +75,7 @@ public class SmsManager extends BaseManager implements SmsGateway { * @return */ public int sendSmsCode(SendCodeV2Req req) { - sendMnsCode(req.getPhone(), req.getParam(), req.getAppCode(),req.getTemplateNo()); + sendMnsCode(req.getPhone(), req.getParam(), req.getAppCode(),req.getTemplateNo(), req.getCode()); log.info("发送验证码 手机号{} -- 参数 {} -- 应用程序code {} -- 模板编号templateCode {}", req.getPhone(), req.getParam(), req.getAppCode(),req.getTemplateNo()); return req.getCode(); } @@ -176,7 +183,7 @@ public class SmsManager extends BaseManager implements SmsGateway { } } - public void sendMnsCode(String phoneNumber, Map param, String appCode,String templateNo) { + public void sendMnsCode(String phoneNumber, Map param, String appCode, String templateNo, Integer code) { if (!isSendMnsCode) { return; } @@ -186,6 +193,10 @@ public class SmsManager extends BaseManager implements SmsGateway { request.setTemplateNo(templateNo); request.setParams(param); request.setRequestNo(UUID.randomUUID().toString()); + request.setInternalObj(MnsType.VERIFY_CODE); + HashMap params = new HashMap<>(); + params.put("code", code); + request.setParams(params); messageService.sendMessage(request); } }