短信提交 2021-04-03,重构返回的结果

This commit is contained in:
YunaiV
2021-04-03 22:05:11 +08:00
parent 5a1491d7fd
commit d843d6a5a8
28 changed files with 232 additions and 227 deletions

View File

@@ -4,7 +4,6 @@ import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
import io.swagger.annotations.Api;
@@ -13,7 +12,6 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
@@ -31,12 +29,6 @@ public class SmsChannelController {
return success(service.pageSmsChannels(reqVO));
}
@ApiOperation("获取渠道枚举")
@GetMapping("/list/channel-enum")
public CommonResult<List<SmsChannelEnumRespVO>> getChannelEnums() {
return success(service.getSmsChannelEnums());
}
@ApiOperation("添加消息渠道")
@PostMapping("/create")
public CommonResult<Long> add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) {

View File

@@ -1,21 +0,0 @@
package cn.iocoder.dashboard.modules.system.controller.sms.vo.resp;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@ApiModel("用户分页 Request VO")
@Data
@NoArgsConstructor
@EqualsAndHashCode
public class SmsChannelEnumRespVO implements Serializable {
private String code;
private String name;
}

View File

@@ -1,10 +1,8 @@
package cn.iocoder.dashboard.modules.system.convert.sms;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import org.mapstruct.Mapper;
@@ -21,8 +19,6 @@ public interface SmsChannelConvert {
SysSmsChannelDO convert(SysUserUpdateReqVO bean);
List<SmsChannelEnumRespVO> convertEnum(List<SmsChannelEnum> bean);
List<SmsChannelAllVO> convert(List<SysSmsChannelDO> bean);
List<SmsChannelProperties> convertProperty(List<SmsChannelAllVO> list);

View File

@@ -6,16 +6,18 @@ import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* 短信渠道
* 短信渠道 DO
*
* @author zzf
* @since 2021-01-25
*/
@TableName(value = "sms_channel", autoResultMap = true)
@TableName(value = "sys_sms_channel", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysSmsChannelDO extends BaseDO {
/**

View File

@@ -2,28 +2,30 @@ package cn.iocoder.dashboard.modules.system.dal.dataobject.sms;
import cn.iocoder.dashboard.common.enums.UserTypeEnum;
import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*;
import java.util.Date;
import java.util.Map;
/**
* 短信发送日志
* 短信日志 DO
*
* @author zzf
* @since 2021-01-25
*/
@TableName(value = "sms_send_log", autoResultMap = true)
@TableName(value = "sys_sms_log", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SysSmsSendLogDO extends BaseDO {
public class SysSmsLogDO extends BaseDO {
/**
* 自增编号
@@ -48,7 +50,7 @@ public class SysSmsSendLogDO extends BaseDO {
// ========= 模板相关字段 =========
/**
* 短信模板编号
* 模板编号
*
* 关联 {@link SysSmsTemplateDO#getId()}
*/
@@ -70,8 +72,9 @@ public class SysSmsSendLogDO extends BaseDO {
*/
private String templateContent;
/**
* 基于 {@link SysSmsTemplateDO#getParams()} 输入后的内容
* 基于 {@link SysSmsTemplateDO#getParams()} 输入后的参数
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, Object> templateParams;
/**
* 短信 API 的模板编号
@@ -106,32 +109,32 @@ public class SysSmsSendLogDO extends BaseDO {
*/
private Integer sendStatus;
/**
* 时间发送时间
* 发送时间
*/
private Date sendTime;
/**
* 发送失败的类型
* 发送结果的编码
*
* 枚举 {@link SmsSendFailureTypeEnum#getType()}
* 枚举 {@link SmsFrameworkErrorCodeConstants}
*/
private Integer sendFailureType;
private Integer sendCode;
/**
* 发送失败的提示
* 发送结果的提示
*
* 一般情况下使用 {@link SmsSendFailureTypeEnum#getMsg()}
* 一般情况下使用 {@link SmsFrameworkErrorCodeConstants}
* 异常情况下通过格式化 Exception 的提示存储
*/
private String sendFailureMsg;
private String sendMsg;
/**
* 短信 API 发送失败的类型
* 短信 API 发送结果的编码
*
* 由于第三方的错误码可能是字符串所以使用 String 类型
*/
private String apiSendFailureType;
private String apiSendCode;
/**
* 短信 API 发送失败的提示
*/
private String apiSendFailureMsg;
private String apiSendMsg;
/**
* 短信 API 发送返回的唯一请求 ID
*
@@ -147,9 +150,9 @@ public class SysSmsSendLogDO extends BaseDO {
// ========= 接收相关字段 =========
/**
* 是否获取过结果[0否 1是]
*/
private Integer gotResult;
// /**
// * 是否获取过结果[0否 1是]
// */
// private Integer gotResult;
}

View File

@@ -8,18 +8,20 @@ import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.List;
/**
* 短信模板
* 短信模板 DO
*
* @author zzf
* @since 2021-01-25
*/
@TableName(value = "sys_sms_template", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@TableName(value = "sms_template", autoResultMap = true)
@ToString(callSuper = true)
public class SysSmsTemplateDO extends BaseDO {
/**
@@ -46,11 +48,11 @@ public class SysSmsTemplateDO extends BaseDO {
*/
private String code;
/**
* 名称
* 模板名称
*/
private String name;
/**
* 内容
* 模板内容
*
* 内容的参数,使用 {} 包括,例如说 {name}
*/

View File

@@ -1,9 +1,9 @@
package cn.iocoder.dashboard.modules.system.dal.mysql.sms;
import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysSmsSendLogMapper extends BaseMapperX<SysSmsSendLogDO> {
public interface SysSmsLogMapper extends BaseMapperX<SysSmsLogDO> {
}

View File

@@ -16,6 +16,7 @@ public enum SysSmsSendStatusEnum {
INIT(0), // 初始化
SUCCESS(10), // 发送成功
FAILURE(20), // 发送失败
IGNORE(30), // 忽略,即不发送
;
private final int status;

View File

@@ -1,10 +1,11 @@
package cn.iocoder.dashboard.modules.system.mq.message.sms;
import cn.iocoder.dashboard.common.core.KeyValue;
import cn.iocoder.dashboard.framework.redis.core.stream.StreamMessage;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.Map;
import java.util.List;
/**
* 短信发送消息
@@ -15,10 +16,10 @@ import java.util.Map;
public class SysSmsSendMessage implements StreamMessage {
/**
* 发送日志编号
* 短信日志编号
*/
@NotNull(message = "发送日志编号不能为空")
private Long sendLogId;
@NotNull(message = "短信日志编号不能为空")
private Long logId;
/**
* 手机号
*/
@@ -37,7 +38,7 @@ public class SysSmsSendMessage implements StreamMessage {
/**
* 短信模板参数
*/
private Map<String, Object> templateParams;
private List<KeyValue<String, Object>> templateParams;
@Override
public String getStreamKey() {

View File

@@ -1,5 +1,6 @@
package cn.iocoder.dashboard.modules.system.mq.producer.sms;
import cn.iocoder.dashboard.common.core.KeyValue;
import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils;
import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage;
import lombok.extern.slf4j.Slf4j;
@@ -7,7 +8,7 @@ import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Map;
import java.util.List;
/**
* 短信发送流消息监听器
@@ -25,16 +26,15 @@ public class SysSmsProducer {
/**
* 发送短信 Message
*
* @param sendLogId 发送日志编号
* @param logId 短信日志编号
* @param mobile 手机号
* @param channelId 渠道编号
* @param apiTemplateId 短信模板编号
* @param templateParams 短信模板参数
* @param sendLogId 发送日志编号
*/
public void sendSmsSendMessage(Long sendLogId, String mobile,
Long channelId, String apiTemplateId, Map<String, Object> templateParams) {
SysSmsSendMessage message = new SysSmsSendMessage().setSendLogId(sendLogId).setMobile(mobile);
public void sendSmsSendMessage(Long logId, String mobile,
Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
SysSmsSendMessage message = new SysSmsSendMessage().setLogId(logId).setMobile(mobile);
message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams);
RedisMessageUtils.sendStreamMessage(stringRedisTemplate, message);
}

View File

@@ -3,11 +3,8 @@ package cn.iocoder.dashboard.modules.system.service.sms;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import java.util.List;
/**
* 短信渠道Service接口
*
@@ -17,9 +14,9 @@ import java.util.List;
public interface SysSmsChannelService {
/**
* 初始化短信渠道并缓存短信模板信息
* 初始化短信客户端
*/
void initSmsClientAndCacheSmsTemplate();
void initSmsClients();
/**
* 分页查询短信渠道信息
@@ -37,11 +34,4 @@ public interface SysSmsChannelService {
*/
Long createSmsChannel(SmsChannelCreateReqVO reqVO);
/**
* 获取短信渠道枚举/渠道编码
*
* @return 短信渠道枚举/渠道编码
*/
List<SmsChannelEnumRespVO> getSmsChannelEnums();
}

View File

@@ -0,0 +1,44 @@
package cn.iocoder.dashboard.modules.system.service.sms;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import java.util.Map;
/**
* 短信日志服务接口
*
* @author zzf
* @date 13:48 2021/3/2
*/
public interface SysSmsLogService {
/**
* 创建短信日志
*
* @param mobile 手机号
* @param userId 用户编号
* @param userType 用户类型
* @param isSend 是否发送
* @param template 短信模板
* @param templateContent 短信内容
* @param templateParams 短信参数
* @return 发送日志编号
*/
Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend,
SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams);
/**
* 更新发送日志的结果
*
* @param id 日志编号
* @param sendCode 发送结果的编码
* @param sendMsg 发送结果的提示
* @param apiSendCode 短信 API 发送结果的编码
* @param apiSendMsg 短信 API 发送失败的提示
* @param apiRequestId 短信 API 发送返回的唯一请求 ID
* @param apiSerialNo 短信 API 发送返回的序号
*/
void updateSmsSendResult(Long id, Integer sendCode, String sendMsg,
String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo);
}

View File

@@ -1,49 +0,0 @@
package cn.iocoder.dashboard.modules.system.service.sms;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import java.util.Map;
/**
* 短信发送日志服务接口
*
* @author zzf
* @date 13:48 2021/3/2
*/
public interface SysSmsSendLogService {
/**
* 创建发送日志
*
* @param mobile 手机号
* @param userId 用户编号
* @param userType 用户类型
* @param template 短信模板
* @param templateContent 短信内容
* @param templateParams 短信参数
* @return
*/
Long createSmsSendLog(String mobile, Long userId, Integer userType,
SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams);
/**
* 更新发送日志的结果
*
* @param id 日志编号
* @param success 是否成功
* @param sendFailureType 发送失败的类型
* @param sendFailureMsg 发送失败的提示
* @param apiSendFailureType 短信 API 发送失败的类型
* @param apiSendFailureMsg 短信 API 发送失败的提示
* @param apiRequestId 短信 API 发送返回的唯一请求 ID
* @param apiSerialNo 短信 API 发送返回的序号
*/
void updateSmsSendLogResult(Long id, Boolean success, Integer sendFailureType, String sendFailureMsg,
String apiSendFailureType, String apiSendFailureMsg, String apiRequestId, String apiSerialNo);
default void updateSmsSendLogFailure(Long id, SmsSendFailureTypeEnum sendFailureType) {
updateSmsSendLogResult(id, false, sendFailureType.getType(), sendFailureType.getMsg(),
null, null, null, null);
}
}

View File

@@ -3,21 +3,17 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl;
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
import cn.iocoder.dashboard.modules.system.convert.sms.SmsChannelConvert;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsChannelMapper;
import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
/**
@@ -35,12 +31,9 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService {
@Resource
private SysSmsChannelMapper channelMapper;
@Resource
private SysSmsTemplateMapper templateMapper;
@Override
@PostConstruct
public void initSmsClientAndCacheSmsTemplate() {
public void initSmsClients() {
// 查询有效渠道信息
List<SysSmsChannelDO> channelDOList = channelMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
// 创建渠道 Client
@@ -48,6 +41,8 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService {
propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));
}
// TODO 芋艿:刷新缓存
@Override
public PageResult<SysSmsChannelDO> pageSmsChannels(SmsChannelPageReqVO reqVO) {
return channelMapper.selectChannelPage(reqVO);
@@ -60,11 +55,6 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService {
return channelDO.getId();
}
@Override
public List<SmsChannelEnumRespVO> getSmsChannelEnums() {
return SmsChannelConvert.INSTANCE.convertEnum(Arrays.asList(SmsChannelEnum.values()));
}
// @Override
// public List<SmsChannelAllVO> listSmsChannelAllEnabledInfo() {
// List<SysSmsChannelDO> channelDOList = channelMapper.selectListByStatus();

View File

@@ -1,10 +1,11 @@
package cn.iocoder.dashboard.modules.system.service.sms.impl;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsSendLogMapper;
import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsLogMapper;
import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -21,15 +22,18 @@ import java.util.Objects;
*/
@Slf4j
@Service
public class SysSmsSendLogServiceImpl implements SysSmsSendLogService {
public class SysSmsSendLogServiceImpl implements SysSmsLogService {
@Resource
private SysSmsSendLogMapper smsSendLogMapper;
private SysSmsLogMapper smsLogMapper;
@Override
public Long createSmsSendLog(String mobile, Long userId, Integer userType,
SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams) {
SysSmsSendLogDO.SysSmsSendLogDOBuilder logBuilder = SysSmsSendLogDO.builder();
public Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend,
SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams) {
SysSmsLogDO.SysSmsLogDOBuilder logBuilder = SysSmsLogDO.builder();
// 根据是否要发送,设置状态
logBuilder.sendStatus(Objects.equals(isSend, true) ? SysSmsSendStatusEnum.INIT.getStatus()
: SysSmsSendStatusEnum.IGNORE.getStatus());
// 设置手机相关字段
logBuilder.mobile(mobile).userId(userId).userType(userType);
// 设置模板相关字段
@@ -39,18 +43,18 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService {
logBuilder.channelId(template.getChannelId()).channelCode(template.getChannelCode());
// 插入数据库
SysSmsSendLogDO logDO = logBuilder.build();
smsSendLogMapper.insert(logDO);
SysSmsLogDO logDO = logBuilder.build();
smsLogMapper.insert(logDO);
return logDO.getId();
}
@Override
public void updateSmsSendLogResult(Long id, Boolean success, Integer sendFailureType, String sendFailureMsg,
String apiSendFailureType, String apiSendFailureMsg, String apiRequestId, String apiSerialNo) {
SysSmsSendStatusEnum sendStatus = Objects.equals(success, true) ? SysSmsSendStatusEnum.SUCCESS : SysSmsSendStatusEnum.FAILURE;
smsSendLogMapper.updateById(new SysSmsSendLogDO().setId(id).setSendStatus(sendStatus.getStatus()).setSendTime(new Date())
.setSendFailureType(sendFailureType).setSendFailureMsg(sendFailureMsg)
.setApiSendFailureType(apiSendFailureType).setApiSendFailureMsg(apiSendFailureMsg).setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo));
public void updateSmsSendResult(Long id, Integer sendCode, String sendMsg,
String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) {
SysSmsSendStatusEnum sendStatus = CommonResult.isSuccess(sendCode) ? SysSmsSendStatusEnum.SUCCESS : SysSmsSendStatusEnum.FAILURE;
smsLogMapper.updateById(SysSmsLogDO.builder().id(id).sendStatus(sendStatus.getStatus()).sendTime(new Date())
.sendCode(sendCode).sendMsg(sendMsg).apiSendCode(apiSendCode).apiSendMsg(apiSendMsg)
.apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build());
}
}

View File

@@ -1,29 +1,32 @@
package cn.iocoder.dashboard.modules.system.service.sms.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.common.core.KeyValue;
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
import cn.iocoder.dashboard.common.enums.UserTypeEnum;
import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum;
import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage;
import cn.iocoder.dashboard.modules.system.mq.producer.sms.SysSmsProducer;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService;
import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
@@ -38,10 +41,12 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
@Slf4j
public class SysSmsServiceImpl implements SysSmsService {
@Resource
private SysSmsChannelService smsChannelService;
@Resource
private SysSmsTemplateService smsTemplateService;
@Resource
private SysSmsSendLogService smsSendLogService;
private SysSmsLogService smsLogService;
@Resource
private SysSmsProducer smsProducer;
@Resource
@@ -54,53 +59,58 @@ public class SysSmsServiceImpl implements SysSmsService {
public void sendSingleSms(String mobile, Long userId, Integer userType,
String templateCode, Map<String, Object> templateParams) {
// 校验短信模板是否合法
SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode, templateParams);
SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode);
// 校验手机号码是否存在
mobile = this.checkMobile(mobile, userId, userType);
// 创建发送日志
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); // 如果模板被禁用,则不发送短信,只记录日志
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
Long sendLogId = smsSendLogService.createSmsSendLog(mobile, userId, userType, template, content, templateParams);
Long sendLogId = smsLogService.createSmsLog(mobile, userId, userType, isSend, template, content, templateParams);
// 如果模板被禁用,则直接标记发送失败。也就说,不发短信,嘿嘿。
if (CommonStatusEnum.DISABLE.getStatus().equals(template.getStatus())) {
smsSendLogService.updateSmsSendLogFailure(sendLogId, SmsSendFailureTypeEnum.SMS_TEMPLATE_DISABLE);
// 发送 MQ 消息,异步执行发送短信
if (!isSend) {
return;
}
// 如果模板未禁用,发送 MQ 消息。目的是,异步化调用短信平台
smsProducer.sendSmsSendMessage(sendLogId, mobile, template.getChannelId(), template.getApiTemplateId(), templateParams);
List<KeyValue<String, Object>> newTemplateParams = this.buildTemplateParams(template, templateParams);
smsProducer.sendSmsSendMessage(sendLogId, mobile, template.getChannelId(), template.getApiTemplateId(), newTemplateParams);
}
@Override
public void sendBatchSms(List<String> mobiles, List<Long> userIds, Integer userType,
String templateCode, Map<String, Object> templateParams) {
// 校验短信模板是否存在
SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode, templateParams);
SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode);
}
private SysSmsTemplateDO checkSmsTemplateValid(String templateCode, Map<String, Object> templateParams) {
private SysSmsTemplateDO checkSmsTemplateValid(String templateCode) {
// 短信模板不存在
SysSmsTemplateDO template = smsTemplateService.getSmsTemplateByCode(templateCode);
if (template == null) {
throw exception(SMS_TEMPLATE_NOT_EXISTS);
}
// 参数不够
if (CollUtil.isNotEmpty(template.getParams())) {
template.getParams().forEach(param -> {
if (!templateParams.containsKey(param)) {
throw exception(SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS);
}
});
}
// 移除多余参数
if (CollUtil.isEmpty(template.getParams())) {
templateParams.clear();
} else {
templateParams.entrySet().removeIf(entry -> !template.getParams().contains(entry.getKey()));
}
return template;
}
/**
* 将参数模板,处理成有序的 KeyValue 数组
*
* 原因是,部分短信平台并不是使用 key 作为参数,而是数组下标,例如说腾讯云 https://cloud.tencent.com/document/product/382/39023
*
* @param template 短信模板
* @param templateParams 原始参数
* @return 处理后的参数
*/
private List<KeyValue<String, Object>> buildTemplateParams(SysSmsTemplateDO template, Map<String, Object> templateParams) {
return template.getParams().stream().map(key -> {
Object value = templateParams.get(key);
if (value == null) {
throw exception(SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, key);
}
return new KeyValue<>(key, value);
}).collect(Collectors.toList());
}
private String checkMobile(String mobile, Long userId, Integer userType) {
mobile = getMobile(mobile, userId, userType);
if (StrUtil.isEmpty(mobile)) {
@@ -130,15 +140,12 @@ public class SysSmsServiceImpl implements SysSmsService {
public void doSendSms(SysSmsSendMessage message) {
// 获得渠道对应的 SmsClient 客户端
SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId());
if (smsClient == null) {
log.error("[doSendSms][短信 message({}) 找不到对应的客户端]", message);
smsSendLogService.updateSmsSendLogFailure(message.getSendLogId(), SmsSendFailureTypeEnum.SMS_CHANNEL_CLIENT_NOT_EXISTS);
return;
}
Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", message.getChannelId()));
// 发送短信
SmsCommonResult sendResult = smsClient.send(message.getSendLogId(), message.getMobile(),
SmsCommonResult<SmsSendRespDTO> sendResult = smsClient.send(message.getLogId(), message.getMobile(),
message.getApiTemplateId(), message.getTemplateParams());
smsLogService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(),
sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(), sendResult.getData().getSerialNo());
}
@Override