临时提交
This commit is contained in:
parent
a50db6bf7f
commit
b4be8e987a
@ -1,6 +1,11 @@
|
||||
package cn.iocoder.dashboard.framework.sms.client;
|
||||
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsBody;
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsResult;
|
||||
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 抽象短息客户端
|
||||
@ -8,7 +13,8 @@ import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
|
||||
* @author zzf
|
||||
* @date 2021/2/1 9:28
|
||||
*/
|
||||
public abstract class AbstractSmsClient<R> implements SmsClient<R> {
|
||||
@Slf4j
|
||||
public abstract class AbstractSmsClient implements SmsClient {
|
||||
|
||||
/**
|
||||
* 短信渠道参数
|
||||
@ -29,4 +35,43 @@ public abstract class AbstractSmsClient<R> implements SmsClient<R> {
|
||||
return channelVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsResult send(String templateApiId, SmsBody smsBody, Collection<String> targets) {
|
||||
SmsResult result;
|
||||
try {
|
||||
beforeSend(templateApiId, smsBody, targets);
|
||||
result = doSend(templateApiId, smsBody, targets);
|
||||
afterSend(templateApiId, smsBody, targets, result);
|
||||
} catch (Exception e) {
|
||||
// exception handle
|
||||
log.debug(e.getMessage(), e);
|
||||
return failResult("发送异常: " + e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param templateApiId 短信模板唯一标识
|
||||
* @param smsBody 消息内容
|
||||
* @param targets 发送对象列表
|
||||
* @return 短信发送结果
|
||||
*/
|
||||
public abstract SmsResult doSend(String templateApiId, SmsBody smsBody, Collection<String> targets) throws Exception;
|
||||
|
||||
protected void beforeSend(String templateApiId, SmsBody smsBody, Collection<String> targets) throws Exception {
|
||||
}
|
||||
|
||||
protected void afterSend(String templateApiId, SmsBody smsBody, Collection<String> targets, SmsResult result) throws Exception {
|
||||
}
|
||||
|
||||
|
||||
SmsResult failResult(String message) {
|
||||
SmsResult resultBody = new SmsResult();
|
||||
resultBody.setSuccess(false);
|
||||
resultBody.setMessage(message);
|
||||
return resultBody;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
package cn.iocoder.dashboard.framework.sms.client;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsBody;
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsResult;
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail;
|
||||
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
|
||||
import com.aliyuncs.DefaultAcsClient;
|
||||
import com.aliyuncs.IAcsClient;
|
||||
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
|
||||
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
|
||||
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
|
||||
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
|
||||
import com.aliyuncs.http.MethodType;
|
||||
@ -13,7 +17,9 @@ import com.aliyuncs.profile.IClientProfile;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 阿里短信实现类
|
||||
@ -22,7 +28,7 @@ import java.util.Collection;
|
||||
* @date 2021/1/25 14:17
|
||||
*/
|
||||
@Slf4j
|
||||
public class AliyunSmsClient extends AbstractSmsClient<SendSmsResponse> {
|
||||
public class AliyunSmsClient extends AbstractSmsClient {
|
||||
|
||||
private static final String OK = "OK";
|
||||
|
||||
@ -53,35 +59,36 @@ public class AliyunSmsClient extends AbstractSmsClient<SendSmsResponse> {
|
||||
|
||||
|
||||
@Override
|
||||
public SmsResult<SendSmsResponse> send(SmsBody smsBody, Collection<String> targets) {
|
||||
public SmsResult doSend(String templateApiId, SmsBody smsBody, Collection<String> targets) throws Exception {
|
||||
SendSmsRequest request = new SendSmsRequest();
|
||||
request.setSysMethod(MethodType.POST);
|
||||
request.setPhoneNumbers(StringUtils.join(targets, ","));
|
||||
request.setSignName(channelVO.getApiSignatureId());
|
||||
request.setTemplateCode(channelVO.getTemplateByTemplateCode(smsBody.getTemplateCode()).getApiTemplateId());
|
||||
request.setTemplateCode(templateApiId);
|
||||
request.setTemplateParam(smsBody.getParamsStr());
|
||||
// TODO FROM 芋艿 TO zzf:try catch 咱是不是可以交给 abstract 来做。这样,异常处理,重试,限流等等,都可以酱紫
|
||||
try {
|
||||
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
|
||||
// TODO FROM 芋艿 TO zzf:try catch 咱是不是可以交给 abstract 来做。这样,异常处理,重试,限流等等,都可以酱紫 DONE
|
||||
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
|
||||
|
||||
boolean result = OK.equals(sendSmsResponse.getCode());
|
||||
if (!result) {
|
||||
log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage());
|
||||
}
|
||||
SmsResult<SendSmsResponse> resultBody = new SmsResult<>();
|
||||
resultBody.setSuccess(result);
|
||||
resultBody.setResult(sendSmsResponse);
|
||||
return resultBody;
|
||||
} catch (Exception e) {
|
||||
log.debug(e.getMessage(), e);
|
||||
return failResult("发送异常: " + e.getMessage());
|
||||
boolean result = OK.equals(sendSmsResponse.getCode());
|
||||
if (!result) {
|
||||
log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage());
|
||||
}
|
||||
}
|
||||
SmsResult resultBody = new SmsResult();
|
||||
resultBody.setSuccess(result);
|
||||
QuerySendDetailsRequest querySendDetailsRequest = new QuerySendDetailsRequest();
|
||||
querySendDetailsRequest.setBizId(sendSmsResponse.getBizId());
|
||||
|
||||
SmsResult<SendSmsResponse> failResult(String message) {
|
||||
SmsResult<SendSmsResponse> resultBody = new SmsResult<>();
|
||||
resultBody.setSuccess(false);
|
||||
resultBody.setMessage(message);
|
||||
QuerySendDetailsResponse acsResponse = acsClient.getAcsResponse(querySendDetailsRequest);
|
||||
List<SmsResultDetail> resultDetailList = new ArrayList<>(Integer.parseInt(acsResponse.getTotalCount()));
|
||||
acsResponse.getSmsSendDetailDTOs().forEach(s -> {
|
||||
SmsResultDetail resultDetail = new SmsResultDetail();
|
||||
resultDetail.setCreateTime(DateUtil.parseDateTime(s.getSendDate()));
|
||||
resultDetail.setMessage(s.getContent());
|
||||
resultDetail.setPhone(s.getPhoneNum());
|
||||
resultDetail.setStatus(Math.toIntExact(s.getSendStatus()));
|
||||
resultDetailList.add(resultDetail);
|
||||
});
|
||||
resultBody.setResult(resultDetailList);
|
||||
return resultBody;
|
||||
}
|
||||
|
||||
|
@ -11,15 +11,16 @@ import java.util.Collection;
|
||||
* @author zzf
|
||||
* @date 2021/1/25 14:14
|
||||
*/
|
||||
public interface SmsClient<R> {
|
||||
public interface SmsClient {
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param smsBody 消息内容
|
||||
* @param targets 发送对象列表
|
||||
* @return 是否发送成功
|
||||
* @param templateApiId 短信模板唯一标识
|
||||
* @param smsBody 消息内容
|
||||
* @param targets 发送对象列表
|
||||
* @return 短信发送结果
|
||||
*/
|
||||
SmsResult<R> send(SmsBody smsBody, Collection<String> targets);
|
||||
SmsResult send(String templateApiId, SmsBody smsBody, Collection<String> targets);
|
||||
|
||||
}
|
@ -1,15 +1,14 @@
|
||||
package cn.iocoder.dashboard.framework.sms.core;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.dashboard.common.enums.SmsChannelEnum;
|
||||
import cn.iocoder.dashboard.common.exception.ServiceException;
|
||||
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
|
||||
import cn.iocoder.dashboard.framework.sms.client.AliyunSmsClient;
|
||||
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
|
||||
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
|
||||
import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@ -24,7 +23,17 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
|
||||
@Component
|
||||
public class SmsClientFactory {
|
||||
|
||||
private final Map<Long, AbstractSmsClient<?>> smsSenderMap = new ConcurrentHashMap<>(8);
|
||||
/**
|
||||
* channelId: client map
|
||||
* 保存 渠道id: 对应短信客户端 的map
|
||||
*/
|
||||
private final Map<Long, AbstractSmsClient> smsSenderMap = new ConcurrentHashMap<>(8);
|
||||
|
||||
/**
|
||||
* templateCode: TemplateProperty map
|
||||
* 保存 模板编码:模板信息 的map
|
||||
*/
|
||||
private final Map<String, SmsTemplateProperty> templatePropertyMap = new ConcurrentHashMap<>(16);
|
||||
|
||||
/**
|
||||
* 创建短信客户端
|
||||
@ -33,20 +42,13 @@ public class SmsClientFactory {
|
||||
* @return 客户端id(默认channelId)
|
||||
*/
|
||||
public Long createClient(SmsChannelProperty propertyVO) {
|
||||
// TODO FROM 芋艿 TO zzf:参数的校验,可以考虑统一使用 validation。
|
||||
if (StrUtil.isBlank(propertyVO.getCode())) {
|
||||
throw ServiceExceptionUtil.exception(PARAM_VALUE_IS_NULL, "短信渠道编码");
|
||||
}
|
||||
if (ObjectUtil.isNull(propertyVO.getId())) {
|
||||
throw ServiceExceptionUtil.exception(PARAM_VALUE_IS_NULL, "短信渠道ID");
|
||||
}
|
||||
|
||||
AbstractSmsClient<?> sender = createClient(SmsChannelEnum.getByCode(propertyVO.getCode()), propertyVO);
|
||||
// TODO FROM 芋艿 TO zzf:参数的校验,可以考虑统一使用 validation。 DONE
|
||||
AbstractSmsClient sender = createClient(SmsChannelEnum.getByCode(propertyVO.getCode()), propertyVO);
|
||||
smsSenderMap.put(propertyVO.getId(), sender);
|
||||
return propertyVO.getId();
|
||||
}
|
||||
|
||||
private AbstractSmsClient<?> createClient(SmsChannelEnum channelEnum, SmsChannelProperty channelVO) {
|
||||
private AbstractSmsClient createClient(SmsChannelEnum channelEnum, SmsChannelProperty channelVO) {
|
||||
if (channelEnum == null) {
|
||||
throw new ServiceException(INVALID_CHANNEL_CODE);
|
||||
}
|
||||
@ -66,7 +68,38 @@ public class SmsClientFactory {
|
||||
* @param channelId 渠道id
|
||||
* @return 短信id
|
||||
*/
|
||||
public AbstractSmsClient<?> getClient(Long channelId) {
|
||||
public AbstractSmsClient getClient(Long channelId) {
|
||||
return smsSenderMap.get(channelId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加或修改短信模板信息缓存
|
||||
*/
|
||||
public void addOrUpdateTemplateCache(Collection<SmsTemplateProperty> templateProperties) {
|
||||
templateProperties.forEach(s -> templatePropertyMap.put(s.getCode(), s));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加或修改短信模板信息缓存
|
||||
*/
|
||||
public void addOrUpdateTemplateCache(SmsTemplateProperty templateProperty) {
|
||||
templatePropertyMap.put(templateProperty.getCode(), templateProperty);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据短信模板编码获取模板唯一标识
|
||||
*
|
||||
* @param templateCode 短信模板编码
|
||||
* @return 短信id
|
||||
*/
|
||||
public String getTemplateApiIdByCode(String templateCode) {
|
||||
SmsTemplateProperty smsTemplateProperty = templatePropertyMap.get(templateCode);
|
||||
if (smsTemplateProperty == null) {
|
||||
throw new ServiceException(SMS_TEMPLATE_NOT_FOUND);
|
||||
}
|
||||
return smsTemplateProperty.getApiTemplateId();
|
||||
}
|
||||
}
|
||||
|
@ -3,17 +3,24 @@ package cn.iocoder.dashboard.framework.sms.core;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息内容实体类
|
||||
*/
|
||||
@Data
|
||||
public class SmsResult<T> implements Serializable {
|
||||
public class SmsResult implements Serializable {
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private Boolean success; // TODO FROM 芋艿 to zzf:未来要加一个 code,将不同平台的短信失败的情况,做一次统一的收敛。
|
||||
// TODO FROM 芋艿 to zzf:未来要加一个 code,将不同平台的短信失败的情况,做一次统一的收敛。 DONE
|
||||
private Boolean success;
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 提示
|
||||
@ -23,5 +30,7 @@ public class SmsResult<T> implements Serializable {
|
||||
/**
|
||||
* 返回值
|
||||
*/
|
||||
private T result; // TODO FROM 芋艿 to zzf:是不是统一各个平台的返回结果,这样对调用方来说统一。因为作为统一的短信客户端,最好让上层不太需要知道太具体。黑河诶
|
||||
// TODO FROM 芋艿 to zzf:是不是统一各个平台的返回结果,这样对调用方来说统一。因为作为统一的短信客户端,最好让上层不太需要知道太具体。黑河诶 DONE
|
||||
private List<SmsResultDetail> result;
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
package cn.iocoder.dashboard.framework.sms.core;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 消息内容实体类
|
||||
*/
|
||||
@Data
|
||||
public class SmsResultDetail implements Serializable {
|
||||
|
||||
/**
|
||||
* 状态 1成功 2失败 3等待回执
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 接收手机号
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 提示
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
@ -1,13 +1,10 @@
|
||||
package cn.iocoder.dashboard.common.enums;
|
||||
package cn.iocoder.dashboard.framework.sms.core.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 短信渠道枚举 TODO FROM 芋艿 TO zzf:属于短信的枚举类,可以放到 framework/sms 下
|
||||
* 短信渠道枚举 TODO FROM 芋艿 TO zzf:属于短信的枚举类,可以放到 framework/sms 下 DONE
|
||||
*
|
||||
* @author zzf
|
||||
* @date 2021/1/25 10:56
|
||||
@ -19,7 +16,7 @@ public enum SmsChannelEnum {
|
||||
ALI("ALI", "阿里"),
|
||||
HUA_WEI("HUA_WEI", "华为"),
|
||||
QI_NIU("QI_NIU", "七牛"),
|
||||
TEN_XUN("TEN_XUN", "腾讯"); // TODO FROM 芋艿 to zzf:TEN 有后鼻音哈,要被马爸爸打了。。。
|
||||
TENCENT("TENCENT", "腾讯"); // TODO FROM 芋艿 to zzf:TEN 有后鼻音哈,要被马爸爸打了。。。 DONE
|
||||
|
||||
private final String code;
|
||||
|
@ -3,6 +3,8 @@ package cn.iocoder.dashboard.framework.sms.core.property;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@ -19,40 +21,37 @@ public class SmsChannelProperty implements Serializable {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@NotNull(message = "短信渠道ID不能为空")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 编码(来自枚举类 阿里、华为、七牛等)
|
||||
*/
|
||||
@NotEmpty(message = "短信渠道编码不能为空")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 渠道账号id
|
||||
*/
|
||||
@NotEmpty(message = "渠道账号id不能为空")
|
||||
private String apiKey;
|
||||
|
||||
/**
|
||||
* 渠道账号秘钥
|
||||
*/
|
||||
@NotEmpty(message = "渠道账号秘钥不能为空")
|
||||
private String apiSecret;
|
||||
|
||||
/**
|
||||
* 实际渠道签名唯一标识
|
||||
*/
|
||||
@NotEmpty(message = "实际渠道签名唯一标识不能为空")
|
||||
private String apiSignatureId;
|
||||
|
||||
/**
|
||||
* 签名值
|
||||
*/
|
||||
@NotEmpty(message = "签名值不能为空")
|
||||
private String signature;
|
||||
|
||||
/**
|
||||
* 该渠道名下的短信模板集合
|
||||
*/
|
||||
private List<SmsTemplateProperty> templateList;
|
||||
|
||||
public SmsTemplateProperty getTemplateByTemplateCode(String tempCode) {
|
||||
return templateList.stream().filter(s -> s.getCode().equals(tempCode)).findFirst().get();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,8 +3,12 @@ package cn.iocoder.dashboard.framework.sms.core.property;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
/**
|
||||
* 渠道模板VO类 TODO FROM 芋艿 TO zzf:模板是不是不要提供到 client 里面,而是交给 factory 统一维护就好。不然,模板修改时候,刷新 client 会比较麻烦。
|
||||
* 渠道模板VO类
|
||||
* TODO FROM 芋艿 TO zzf:模板是不是不要提供到 client 里面,而是交给 factory 统一维护就好。不然,模板修改时候,刷新 client 会比较麻烦。
|
||||
*
|
||||
*
|
||||
* @author zzf
|
||||
* @date 2021/1/25 17:03
|
||||
@ -13,6 +17,12 @@ import lombok.EqualsAndHashCode;
|
||||
@EqualsAndHashCode
|
||||
public class SmsTemplateProperty {
|
||||
|
||||
/**
|
||||
* 渠道id
|
||||
*/
|
||||
@NotEmpty(message = "短信渠道编码不能为空")
|
||||
private Long channelId;
|
||||
|
||||
/**
|
||||
* 业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板)
|
||||
*/
|
||||
@ -21,18 +31,19 @@ public class SmsTemplateProperty {
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
@NotEmpty(message = "短信模板编码不能为空")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 实际渠道模板唯一标识
|
||||
*/
|
||||
@NotEmpty(message = "短信模板唯一标识不能为空")
|
||||
private String apiTemplateId;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
@NotEmpty(message = "短信模板内容不能为空")
|
||||
private String content;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ 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.mysql.dataobject.sms.SmsChannelDO;
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO;
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -23,25 +23,25 @@ import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
|
||||
public class SmsChannelController {
|
||||
|
||||
@Resource
|
||||
private SmsChannelService service;
|
||||
private SysSmsChannelService service;
|
||||
|
||||
@ApiOperation("获取渠道/签名分页")
|
||||
@GetMapping("/page")
|
||||
public CommonResult<PageResult<SmsChannelDO>> getPermissionInfo(@Validated SmsChannelPageReqVO reqVO) {
|
||||
return success(service.pageChannels(reqVO));
|
||||
public CommonResult<PageResult<SysSmsChannelDO>> getPermissionInfo(@Validated SmsChannelPageReqVO reqVO) {
|
||||
return success(service.pageSmsChannels(reqVO));
|
||||
}
|
||||
|
||||
@ApiOperation("获取渠道枚举")
|
||||
@GetMapping("/list/channel-enum")
|
||||
public CommonResult<List<SmsChannelEnumRespVO>> getChannelEnums() {
|
||||
return success(service.getChannelEnums());
|
||||
return success(service.getSmsChannelEnums());
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation("添加消息渠道")
|
||||
@PostMapping("/create")
|
||||
public CommonResult<Long> add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) {
|
||||
return success(service.createChannel(reqVO));
|
||||
return success(service.createSmsChannel(reqVO));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
package cn.iocoder.dashboard.modules.system.convert.sms;
|
||||
|
||||
import cn.iocoder.dashboard.common.enums.SmsChannelEnum;
|
||||
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
|
||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
|
||||
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.mysql.dataobject.sms.SmsChannelDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
@ -21,17 +21,19 @@ public interface SmsChannelConvert {
|
||||
SmsChannelConvert INSTANCE = Mappers.getMapper(SmsChannelConvert.class);
|
||||
|
||||
@Mapping(source = "records", target = "list")
|
||||
PageResult<SmsChannelDO> convertPage(IPage<SmsChannelDO> page);
|
||||
PageResult<SysSmsChannelDO> convertPage(IPage<SysSmsChannelDO> page);
|
||||
|
||||
SmsChannelDO convert(SmsChannelCreateReqVO bean);
|
||||
SysSmsChannelDO convert(SmsChannelCreateReqVO bean);
|
||||
|
||||
SmsChannelDO convert(SysUserUpdateReqVO bean);
|
||||
SysSmsChannelDO convert(SysUserUpdateReqVO bean);
|
||||
|
||||
List<SmsChannelEnumRespVO> convertEnum(List<SmsChannelEnum> bean);
|
||||
|
||||
List<SmsChannelAllVO> convert(List<SmsChannelDO> bean);
|
||||
List<SmsChannelAllVO> convert(List<SysSmsChannelDO> bean);
|
||||
|
||||
List<SmsChannelProperty> convertProperty(List<SmsChannelAllVO> list);
|
||||
|
||||
List<SmsChannelProperty> convertProperties(List<SysSmsChannelDO> list);
|
||||
|
||||
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ package cn.iocoder.dashboard.modules.system.convert.sms;
|
||||
|
||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsTemplateDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsTemplateDO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
@ -17,10 +17,10 @@ public interface SmsTemplateConvert {
|
||||
SmsTemplateConvert INSTANCE = Mappers.getMapper(SmsTemplateConvert.class);
|
||||
|
||||
@Mapping(source = "records", target = "list")
|
||||
PageResult<SmsChannelDO> convertPage(IPage<SmsChannelDO> page);
|
||||
PageResult<SysSmsChannelDO> convertPage(IPage<SysSmsChannelDO> page);
|
||||
|
||||
List<SmsTemplateVO> convert(List<SmsTemplateDO> bean);
|
||||
List<SmsTemplateVO> convert(List<SysSmsTemplateDO> bean);
|
||||
|
||||
SmsTemplateVO convert(SmsTemplateDO bean);
|
||||
SmsTemplateVO convert(SysSmsTemplateDO bean);
|
||||
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms;
|
||||
|
||||
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsTemplateDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SmsTemplateMapper extends BaseMapper<SmsTemplateDO> {
|
||||
|
||||
/**
|
||||
* 根据短信渠道id查询短信模板集合
|
||||
*
|
||||
* @param channelId 渠道id
|
||||
* @return 模板集合
|
||||
*/
|
||||
default List<SmsTemplateDO> selectListByChannelId(Long channelId) {
|
||||
return selectList(new LambdaQueryWrapper<SmsTemplateDO>()
|
||||
.eq(SmsTemplateDO::getChannelId, channelId)
|
||||
.eq(SmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
|
||||
.orderByAsc(SmsTemplateDO::getId)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询有效短信模板集合
|
||||
*
|
||||
* @return 有效短信模板集合
|
||||
*/
|
||||
default List<SmsTemplateDO> selectEnabledList() {
|
||||
return selectList(new LambdaQueryWrapper<SmsTemplateDO>()
|
||||
.eq(SmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
|
||||
.orderByAsc(SmsTemplateDO::getId)
|
||||
);
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils;
|
||||
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
@ -13,19 +13,19 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SmsChannelMapper extends BaseMapper<SmsChannelDO> {
|
||||
public interface SysSmsChannelMapper extends BaseMapper<SysSmsChannelDO> {
|
||||
|
||||
default IPage<SmsChannelDO> selectChannelPage(SmsChannelPageReqVO reqVO) {
|
||||
return selectPage(MyBatisUtils.buildPage(reqVO), new LambdaQueryWrapper<SmsChannelDO>()
|
||||
.like(StrUtil.isNotBlank(reqVO.getName()), SmsChannelDO::getName, reqVO.getName())
|
||||
.like(StrUtil.isNotBlank(reqVO.getSignature()), SmsChannelDO::getName, reqVO.getSignature())
|
||||
default IPage<SysSmsChannelDO> selectChannelPage(SmsChannelPageReqVO reqVO) {
|
||||
return selectPage(MyBatisUtils.buildPage(reqVO), new LambdaQueryWrapper<SysSmsChannelDO>()
|
||||
.like(StrUtil.isNotBlank(reqVO.getName()), SysSmsChannelDO::getName, reqVO.getName())
|
||||
.like(StrUtil.isNotBlank(reqVO.getSignature()), SysSmsChannelDO::getName, reqVO.getSignature())
|
||||
);
|
||||
}
|
||||
|
||||
default List<SmsChannelDO> selectEnabledList() {
|
||||
return selectList(new LambdaQueryWrapper<SmsChannelDO>()
|
||||
.eq(SmsChannelDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
|
||||
.orderByAsc(SmsChannelDO::getId)
|
||||
default List<SysSmsChannelDO> selectEnabledList() {
|
||||
return selectList(new LambdaQueryWrapper<SysSmsChannelDO>()
|
||||
.eq(SysSmsChannelDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
|
||||
.orderByAsc(SysSmsChannelDO::getId)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms;
|
||||
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsLogDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsLogDO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SmsLogMapper extends BaseMapper<SmsLogDO> {
|
||||
public interface SysSmsLogMapper extends BaseMapper<SysSmsLogDO> {
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms;
|
||||
|
||||
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsTemplateDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SysSmsTemplateMapper extends BaseMapper<SysSmsTemplateDO> {
|
||||
|
||||
/**
|
||||
* 根据短信渠道id查询短信模板集合
|
||||
*
|
||||
* @param channelId 渠道id
|
||||
* @return 模板集合
|
||||
*/
|
||||
default List<SysSmsTemplateDO> selectListByChannelId(Long channelId) {
|
||||
return selectList(new LambdaQueryWrapper<SysSmsTemplateDO>()
|
||||
.eq(SysSmsTemplateDO::getChannelId, channelId)
|
||||
.eq(SysSmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
|
||||
.orderByAsc(SysSmsTemplateDO::getId)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询有效短信模板集合
|
||||
*
|
||||
* @return 有效短信模板集合
|
||||
*/
|
||||
default List<SysSmsTemplateDO> selectEnabledList() {
|
||||
return selectList(new LambdaQueryWrapper<SysSmsTemplateDO>()
|
||||
.eq(SysSmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
|
||||
.orderByAsc(SysSmsTemplateDO::getId)
|
||||
);
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName(value = "sms_channel", autoResultMap = true)
|
||||
public class SmsChannelDO extends BaseDO {
|
||||
public class SysSmsChannelDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 自增编号
|
@ -18,7 +18,7 @@ import java.util.Date;
|
||||
@EqualsAndHashCode
|
||||
@Accessors(chain = true)
|
||||
@TableName(value = "sms_log", autoResultMap = true)
|
||||
public class SmsLogDO implements Serializable {
|
||||
public class SysSmsLogDO implements Serializable {
|
||||
|
||||
/**
|
||||
* 自增编号
|
@ -16,7 +16,7 @@ import java.util.Date;
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName(value = "sms_template", autoResultMap = true)
|
||||
public class SmsTemplateDO extends BaseDO {
|
||||
public class SysSmsTemplateDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 自增编号
|
@ -4,7 +4,7 @@ import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageLi
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsResult;
|
||||
import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage;
|
||||
import cn.iocoder.dashboard.modules.system.mq.message.sms.SmsSendMessage;
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SmsService;
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ -20,12 +20,12 @@ import javax.annotation.Resource;
|
||||
public class SmsSendConsumer extends AbstractChannelMessageListener<SmsSendMessage> {
|
||||
|
||||
@Resource
|
||||
private SmsService smsService;
|
||||
private SysSmsService sysSmsService;
|
||||
|
||||
@Override
|
||||
public void onMessage(SmsSendMessage message) {
|
||||
log.info("[onMessage][收到 发送短信 消息]");
|
||||
SmsResult<?> send = smsService.send(message.getSmsBody(), message.getTargetPhones());
|
||||
SmsResult send = sysSmsService.send(message.getSmsBody(), message.getTargetPhones());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ 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.req.SmsChannelPageReqVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -16,7 +16,7 @@ import java.util.List;
|
||||
* @author zzf
|
||||
* @date 2021/1/25 9:24
|
||||
*/
|
||||
public interface SmsChannelService {
|
||||
public interface SysSmsChannelService {
|
||||
|
||||
// TODO FROM 芋艿 to ZZF:SmsChannelService=》SysSmsChannelService,增加 Sys 前缀,算在系统模块里
|
||||
// TODO FROM 芋艿 to ZZF:方法名,保持不去掉 Sms 前缀。虽然长点,嘿嘿
|
||||
@ -32,7 +32,7 @@ public interface SmsChannelService {
|
||||
* @param reqVO 参数对象
|
||||
* @return 短信渠道分页对象
|
||||
*/
|
||||
PageResult<SmsChannelDO> pageChannels(SmsChannelPageReqVO reqVO);
|
||||
PageResult<SysSmsChannelDO> pageSmsChannels(SmsChannelPageReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 创建新的渠道信息
|
||||
@ -40,14 +40,14 @@ public interface SmsChannelService {
|
||||
* @param reqVO 参数对象
|
||||
* @return 渠道id
|
||||
*/
|
||||
Long createChannel(SmsChannelCreateReqVO reqVO);
|
||||
Long createSmsChannel(SmsChannelCreateReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 获取短信渠道枚举/渠道编码
|
||||
*
|
||||
* @return 短信渠道枚举/渠道编码
|
||||
*/
|
||||
List<SmsChannelEnumRespVO> getChannelEnums();
|
||||
List<SmsChannelEnumRespVO> getSmsChannelEnums();
|
||||
|
||||
/**
|
||||
* 根据短信模板编码获取短信客户端
|
||||
@ -55,12 +55,20 @@ public interface SmsChannelService {
|
||||
* @param templateCode 短信模板编码
|
||||
* @return 短信客户端
|
||||
*/
|
||||
AbstractSmsClient<?> getClient(String templateCode);
|
||||
AbstractSmsClient getSmsClient(String templateCode);
|
||||
|
||||
/**
|
||||
* 根据短信模板编码获取模板唯一标识
|
||||
*
|
||||
* @param templateCode 短信模板编码
|
||||
* @return 短信客户端
|
||||
*/
|
||||
String getSmsTemplateApiIdByCode(String templateCode);
|
||||
|
||||
/**
|
||||
* 查询渠道(包含名下模块)信息集合
|
||||
*
|
||||
* @return 渠道(包含名下模块)信息集合
|
||||
*/
|
||||
List<SmsChannelAllVO> listChannelAllEnabledInfo();
|
||||
List<SmsChannelAllVO> listSmsChannelAllEnabledInfo();
|
||||
}
|
@ -12,7 +12,7 @@ import java.util.List;
|
||||
* @author zzf
|
||||
* @date 2021/1/25 9:24
|
||||
*/
|
||||
public interface SmsLogService {
|
||||
public interface SysSmsLogService {
|
||||
/**
|
||||
* 发送短信前的日志处理
|
||||
*
|
||||
@ -22,9 +22,11 @@ public interface SmsLogService {
|
||||
* @param isAsync 是否异步发送
|
||||
* @return 生成的日志id
|
||||
*/
|
||||
// TODO FROM 芋艿 to ZZF: async 是针对发送的方式,对于日志不一定需要关心。这样,短信日志,实际就发送前插入,发送后更新结果
|
||||
// TODO FROM 芋艿 to ZZF: async 是针对发送的方式,对于日志不一定需要关心。这样,短信日志,实际就发送前插入,发送后更新结果.
|
||||
// 这里只用于记录状态,毕竟异步可能推送失败,此时日志可记录该状态。
|
||||
|
||||
// TODO FROM 芋艿 to ZZF:短信日志,群发的情况,应该是每个手机一条哈。虽然是群发,但是可能部分成功,部分失败;对应到短信平台,实际也是多条。
|
||||
Long beforeSendLog(SmsBody smsBody, List<String> targetPhones, AbstractSmsClient<?> client, Boolean isAsync);
|
||||
Long beforeSendLog(SmsBody smsBody, List<String> targetPhones, AbstractSmsClient client, Boolean isAsync);
|
||||
|
||||
/**
|
||||
* 发送消息后的日志处理
|
||||
@ -32,6 +34,6 @@ public interface SmsLogService {
|
||||
* @param logId 日志id
|
||||
* @param result 消息结果
|
||||
*/
|
||||
void afterSendLog(Long logId, SmsResult<?> result);
|
||||
void afterSendLog(Long logId, SmsResult result);
|
||||
|
||||
}
|
@ -14,7 +14,7 @@ import java.util.List;
|
||||
* @author zzf
|
||||
* @date 2021/1/25 9:24
|
||||
*/
|
||||
public interface SmsService {
|
||||
public interface SysSmsService {
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
@ -23,7 +23,7 @@ public interface SmsService {
|
||||
* @param targetPhones 发送对象手机号列表
|
||||
* @return 是否发送成功
|
||||
*/
|
||||
SmsResult<?> send(SmsBody smsBody, List<String> targetPhones);
|
||||
SmsResult send(SmsBody smsBody, List<String> targetPhones);
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
@ -32,7 +32,7 @@ public interface SmsService {
|
||||
* @param targetPhone 发送对象手机号
|
||||
* @return 是否发送成功
|
||||
*/
|
||||
default SmsResult<?> send(SmsBody smsBody, String targetPhone) {
|
||||
default SmsResult send(SmsBody smsBody, String targetPhone) {
|
||||
if (StringUtils.isBlank(targetPhone)) {
|
||||
return failResult("targetPhone must not null.");
|
||||
}
|
||||
@ -47,7 +47,7 @@ public interface SmsService {
|
||||
* @param targetPhones 发送对象手机号数组
|
||||
* @return 是否发送成功
|
||||
*/
|
||||
default SmsResult<?> send(SmsBody smsBody, String... targetPhones) {
|
||||
default SmsResult send(SmsBody smsBody, String... targetPhones) {
|
||||
if (targetPhones == null) {
|
||||
return failResult("targetPhones must not null.");
|
||||
}
|
||||
@ -91,8 +91,8 @@ public interface SmsService {
|
||||
}
|
||||
|
||||
|
||||
default SmsResult<?> failResult(String message) {
|
||||
SmsResult<?> resultBody = new SmsResult<>();
|
||||
default SmsResult failResult(String message) {
|
||||
SmsResult resultBody = new SmsResult();
|
||||
resultBody.setSuccess(false);
|
||||
resultBody.setMessage(message);
|
||||
return resultBody;
|
@ -6,5 +6,5 @@ package cn.iocoder.dashboard.modules.system.service.sms;
|
||||
* @author zzf
|
||||
* @date 2021/1/25 9:24
|
||||
*/
|
||||
public interface SmsTemplateService {
|
||||
public interface SysSmsTemplateService {
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.sms.impl;
|
||||
|
||||
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsBody;
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsResult;
|
||||
import cn.iocoder.dashboard.modules.system.mq.producer.sms.SmsProducer;
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService;
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SmsLogService;
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SmsService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 短信日志Service实现类
|
||||
*
|
||||
* @author zzf
|
||||
* @date 2021/1/25 9:25
|
||||
*/
|
||||
@Service
|
||||
public class SmsServiceImpl implements SmsService {
|
||||
|
||||
@Resource
|
||||
private SmsChannelService channelService;
|
||||
|
||||
@Resource
|
||||
private SmsLogService smsLogService;
|
||||
|
||||
@Resource
|
||||
private SmsProducer smsProducer;
|
||||
|
||||
@Override
|
||||
public SmsResult<?> send(SmsBody smsBody, List<String> targetPhones) {
|
||||
AbstractSmsClient<?> client = channelService.getClient(smsBody.getTemplateCode());
|
||||
Long logId = smsLogService.beforeSendLog(smsBody, targetPhones, client, false);
|
||||
|
||||
SmsResult<?> result = client.send(smsBody, targetPhones);
|
||||
|
||||
smsLogService.afterSendLog(logId, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO FROM 芋艿 to ZZF:可能要讨论下,对于短信发送来说,貌似只提供异步发送即可。对于业务来说,一定不能依赖短信的发送结果。
|
||||
@Override
|
||||
public void sendAsync(SmsBody smsBody, List<String> targetPhones) {
|
||||
AbstractSmsClient<?> client = channelService.getClient(smsBody.getTemplateCode());
|
||||
smsLogService.beforeSendLog(smsBody, targetPhones, client, true);
|
||||
smsProducer.sendSmsSendMessage(smsBody, targetPhones);
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.sms.impl;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.dashboard.common.enums.SmsChannelEnum;
|
||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory;
|
||||
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
|
||||
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
|
||||
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
|
||||
@ -12,11 +12,11 @@ import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageR
|
||||
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.convert.sms.SmsTemplateConvert;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsChannelMapper;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsTemplateMapper;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsTemplateDO;
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsChannelMapper;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsTemplateMapper;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsTemplateDO;
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -35,12 +35,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* @date 2021/1/25 9:25
|
||||
*/
|
||||
@Service
|
||||
public class SmsChannelServiceImpl implements SmsChannelService {
|
||||
public class SysSmsChannelServiceImpl implements SysSmsChannelService {
|
||||
|
||||
private final Map<String, Long> templateCode2ChannelIdMap = new ConcurrentHashMap<>(32);
|
||||
|
||||
@Autowired
|
||||
private SmsClientFactory smsClientFactory;
|
||||
private SmsClientFactory clientFactory;
|
||||
|
||||
/**
|
||||
* 初始化短信客户端
|
||||
@ -48,51 +48,60 @@ public class SmsChannelServiceImpl implements SmsChannelService {
|
||||
@PostConstruct
|
||||
@Override
|
||||
public void initSmsClient() {
|
||||
List<SmsChannelAllVO> smsChannelAllVOList = listChannelAllEnabledInfo();
|
||||
if (ObjectUtil.isEmpty(smsChannelAllVOList)) {
|
||||
return;
|
||||
}
|
||||
List<SmsChannelProperty> channelPropertyList = SmsChannelConvert.INSTANCE.convertProperty(smsChannelAllVOList);
|
||||
channelPropertyList.forEach(smsChannelProperty -> {
|
||||
Long clientId = smsClientFactory.createClient(smsChannelProperty);
|
||||
smsChannelProperty.getTemplateList().forEach(smsTemplateVO -> {
|
||||
templateCode2ChannelIdMap.put(smsTemplateVO.getCode(), clientId);
|
||||
});
|
||||
// 查询有效渠道信息
|
||||
List<SysSmsChannelDO> channelDOList = channelMapper.selectEnabledList();
|
||||
List<SmsChannelProperty> propertyList = SmsChannelConvert.INSTANCE.convertProperties(channelDOList);
|
||||
|
||||
// 遍历渠道生成client并获取模板缓存
|
||||
propertyList.forEach(channelProperty -> {
|
||||
Long clientId = clientFactory.createClient(channelProperty);
|
||||
List<SysSmsTemplateDO> templateDOList = templateMapper.selectListByChannelId(channelProperty.getId());
|
||||
if (ObjectUtil.isNotEmpty(templateDOList)) {
|
||||
templateDOList.forEach(template -> {
|
||||
templateCode2ChannelIdMap.put(template.getCode(), clientId);
|
||||
});
|
||||
SmsTemplateConvert.INSTANCE.convert(templateDOList);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TODO FROM 芋艿 to ZZF:channelMapper 嘿,保持命名统一。
|
||||
// TODO FROM 芋艿 to ZZF:channelMapper 嘿,保持命名统一。 DONE
|
||||
@Resource
|
||||
private SmsChannelMapper mapper;
|
||||
private SysSmsChannelMapper channelMapper;
|
||||
|
||||
@Resource
|
||||
private SmsTemplateMapper templateMapper;
|
||||
private SysSmsTemplateMapper templateMapper;
|
||||
|
||||
@Override
|
||||
public PageResult<SmsChannelDO> pageChannels(SmsChannelPageReqVO reqVO) {
|
||||
return SmsChannelConvert.INSTANCE.convertPage(mapper.selectChannelPage(reqVO));
|
||||
public PageResult<SysSmsChannelDO> pageSmsChannels(SmsChannelPageReqVO reqVO) {
|
||||
return SmsChannelConvert.INSTANCE.convertPage(channelMapper.selectChannelPage(reqVO));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long createChannel(SmsChannelCreateReqVO reqVO) {
|
||||
SmsChannelDO channelDO = SmsChannelConvert.INSTANCE.convert(reqVO);
|
||||
mapper.insert(channelDO);
|
||||
public Long createSmsChannel(SmsChannelCreateReqVO reqVO) {
|
||||
SysSmsChannelDO channelDO = SmsChannelConvert.INSTANCE.convert(reqVO);
|
||||
channelMapper.insert(channelDO);
|
||||
return channelDO.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SmsChannelEnumRespVO> getChannelEnums() {
|
||||
public List<SmsChannelEnumRespVO> getSmsChannelEnums() {
|
||||
return SmsChannelConvert.INSTANCE.convertEnum(Arrays.asList(SmsChannelEnum.values()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractSmsClient<?> getClient(String templateCode) {
|
||||
return smsClientFactory.getClient(templateCode2ChannelIdMap.get(templateCode));
|
||||
public AbstractSmsClient getSmsClient(String templateCode) {
|
||||
return clientFactory.getClient(templateCode2ChannelIdMap.get(templateCode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SmsChannelAllVO> listChannelAllEnabledInfo() {
|
||||
List<SmsChannelDO> channelDOList = mapper.selectEnabledList();
|
||||
public String getSmsTemplateApiIdByCode(String templateCode) {
|
||||
return clientFactory.getTemplateApiIdByCode(templateCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SmsChannelAllVO> listSmsChannelAllEnabledInfo() {
|
||||
List<SysSmsChannelDO> channelDOList = channelMapper.selectEnabledList();
|
||||
if (ObjectUtil.isNull(channelDOList)) {
|
||||
return null;
|
||||
}
|
||||
@ -100,7 +109,7 @@ public class SmsChannelServiceImpl implements SmsChannelService {
|
||||
|
||||
channelAllVOList.forEach(smsChannelDO -> {
|
||||
|
||||
List<SmsTemplateDO> templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId());
|
||||
List<SysSmsTemplateDO> templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId());
|
||||
if (ObjectUtil.isNull(templateDOList)) {
|
||||
templateDOList = new ArrayList<>();
|
||||
}
|
@ -3,14 +3,12 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl;
|
||||
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsBody;
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsResult;
|
||||
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO;
|
||||
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsLogMapper;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsLogDO;
|
||||
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsLogMapper;
|
||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsLogDO;
|
||||
import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum;
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SmsLogService;
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService;
|
||||
import cn.iocoder.dashboard.util.json.JsonUtils;
|
||||
import cn.iocoder.dashboard.util.string.StrUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@ -23,42 +21,41 @@ import java.util.List;
|
||||
* @date 2021/1/25 9:25
|
||||
*/
|
||||
@Service
|
||||
public class SmsLogServiceImpl implements SmsLogService {
|
||||
public class SysSmsLogServiceImpl implements SysSmsLogService {
|
||||
|
||||
@Resource
|
||||
private SmsLogMapper smsLogMapper;
|
||||
private SysSmsLogMapper logMapper;
|
||||
|
||||
@Override
|
||||
public Long beforeSendLog(SmsBody smsBody, List<String> targetPhones, AbstractSmsClient<?> client, Boolean isAsync) {
|
||||
SmsLogDO smsLog = new SmsLogDO();
|
||||
public Long beforeSendLog(SmsBody smsBody, List<String> targetPhones, AbstractSmsClient client, Boolean isAsync) {
|
||||
SysSmsLogDO smsLog = new SysSmsLogDO();
|
||||
if (smsBody.getSmsLogId() != null) {
|
||||
smsLog.setId(smsBody.getSmsLogId());
|
||||
smsLog.setSendStatus(SmsSendStatusEnum.SENDING.getStatus());
|
||||
smsLogMapper.updateById(smsLog);
|
||||
logMapper.updateById(smsLog);
|
||||
return smsBody.getSmsLogId();
|
||||
} else {
|
||||
SmsChannelAllVO property = client.getProperty();
|
||||
SmsTemplateVO smsTemplate = property.getTemplateByTemplateCode(smsBody.getTemplateCode());
|
||||
SmsChannelProperty property = client.getProperty();
|
||||
|
||||
smsLog.setChannelCode(property.getCode())
|
||||
.setChannelId(property.getId())
|
||||
.setTemplateCode(smsTemplate.getCode())
|
||||
.setTemplateCode(smsBody.getTemplateCode())
|
||||
.setPhones(JsonUtils.toJsonString(targetPhones))
|
||||
.setContent(StrUtils.replace(smsTemplate.getContent(), smsBody.getParams()));
|
||||
.setContent(smsBody.getParams().toString());
|
||||
|
||||
if (isAsync) {
|
||||
smsLog.setSendStatus(SmsSendStatusEnum.ASYNC.getStatus());
|
||||
} else {
|
||||
smsLog.setSendStatus(SmsSendStatusEnum.SENDING.getStatus());
|
||||
}
|
||||
smsLogMapper.insert(smsLog);
|
||||
logMapper.insert(smsLog);
|
||||
return smsLog.getId();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSendLog(Long logId, SmsResult<?> result) {
|
||||
SmsLogDO smsLog = new SmsLogDO();
|
||||
public void afterSendLog(Long logId, SmsResult result) {
|
||||
SysSmsLogDO smsLog = new SysSmsLogDO();
|
||||
smsLog.setId(logId);
|
||||
if (result.getSuccess()) {
|
||||
smsLog.setSendStatus(SmsSendStatusEnum.SUCCESS.getStatus());
|
||||
@ -66,7 +63,7 @@ public class SmsLogServiceImpl implements SmsLogService {
|
||||
smsLog.setSendStatus(SmsSendStatusEnum.FAIL.getStatus());
|
||||
smsLog.setRemark(result.getMessage() + JsonUtils.toJsonString(result.getResult()));
|
||||
}
|
||||
smsLogMapper.updateById(smsLog);
|
||||
logMapper.updateById(smsLog);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.sms.impl;
|
||||
|
||||
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsBody;
|
||||
import cn.iocoder.dashboard.framework.sms.core.SmsResult;
|
||||
import cn.iocoder.dashboard.modules.system.mq.producer.sms.SmsProducer;
|
||||
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 org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 短信日志Service实现类
|
||||
*
|
||||
* @author zzf
|
||||
* @date 2021/1/25 9:25
|
||||
*/
|
||||
@Service
|
||||
public class SysSmsServiceImpl implements SysSmsService {
|
||||
|
||||
@Resource
|
||||
private SysSmsChannelService channelService;
|
||||
|
||||
@Resource
|
||||
private SysSmsLogService logService;
|
||||
|
||||
@Resource
|
||||
private SmsProducer smsProducer;
|
||||
|
||||
@Override
|
||||
public SmsResult send(SmsBody smsBody, List<String> targetPhones) {
|
||||
AbstractSmsClient client = channelService.getSmsClient(smsBody.getTemplateCode());
|
||||
String templateApiId = channelService.getSmsTemplateApiIdByCode(smsBody.getTemplateCode());
|
||||
Long logId = logService.beforeSendLog(smsBody, targetPhones, client, false);
|
||||
|
||||
SmsResult result = client.send(templateApiId, smsBody, targetPhones);
|
||||
|
||||
logService.afterSendLog(logId, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO FROM 芋艿 to ZZF:可能要讨论下,对于短信发送来说,貌似只提供异步发送即可。对于业务来说,一定不能依赖短信的发送结果。
|
||||
// 我的想法是1、很多短信,比如验证码,总还是需要知道是否发送成功的。2、别人可以不用,我们不能没有。3、实现挺简单的,个人觉得无需纠结。
|
||||
@Override
|
||||
public void sendAsync(SmsBody smsBody, List<String> targetPhones) {
|
||||
AbstractSmsClient client = channelService.getSmsClient(smsBody.getTemplateCode());
|
||||
logService.beforeSendLog(smsBody, targetPhones, client, true);
|
||||
smsProducer.sendSmsSendMessage(smsBody, targetPhones);
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package cn.iocoder.dashboard.modules.system.service.sms.impl;
|
||||
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SmsTemplateService;
|
||||
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
@ -10,5 +10,5 @@ import org.springframework.stereotype.Service;
|
||||
* @date 2021/1/25 9:25
|
||||
*/
|
||||
@Service
|
||||
public class SmsTemplateServiceImpl implements SmsTemplateService {
|
||||
public class SysSmsTemplateServiceImpl implements SysSmsTemplateService {
|
||||
}
|
Loading…
Reference in New Issue
Block a user