临时提交

pull/2/head
zengzefeng 2021-02-23 15:33:05 +08:00
parent a50db6bf7f
commit b4be8e987a
29 changed files with 418 additions and 263 deletions

View File

@ -1,6 +1,11 @@
package cn.iocoder.dashboard.framework.sms.client; 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 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 * @author zzf
* @date 2021/2/1 9:28 * @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; 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;
}
} }

View File

@ -1,10 +1,14 @@
package cn.iocoder.dashboard.framework.sms.client; 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.SmsBody;
import cn.iocoder.dashboard.framework.sms.core.SmsResult; 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 cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient; 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.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.http.MethodType; import com.aliyuncs.http.MethodType;
@ -13,7 +17,9 @@ import com.aliyuncs.profile.IClientProfile;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
/** /**
* *
@ -22,7 +28,7 @@ import java.util.Collection;
* @date 2021/1/25 14:17 * @date 2021/1/25 14:17
*/ */
@Slf4j @Slf4j
public class AliyunSmsClient extends AbstractSmsClient<SendSmsResponse> { public class AliyunSmsClient extends AbstractSmsClient {
private static final String OK = "OK"; private static final String OK = "OK";
@ -53,35 +59,36 @@ public class AliyunSmsClient extends AbstractSmsClient<SendSmsResponse> {
@Override @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(); SendSmsRequest request = new SendSmsRequest();
request.setSysMethod(MethodType.POST); request.setSysMethod(MethodType.POST);
request.setPhoneNumbers(StringUtils.join(targets, ",")); request.setPhoneNumbers(StringUtils.join(targets, ","));
request.setSignName(channelVO.getApiSignatureId()); request.setSignName(channelVO.getApiSignatureId());
request.setTemplateCode(channelVO.getTemplateByTemplateCode(smsBody.getTemplateCode()).getApiTemplateId()); request.setTemplateCode(templateApiId);
request.setTemplateParam(smsBody.getParamsStr()); request.setTemplateParam(smsBody.getParamsStr());
// TODO FROM 芋艿 TO zzftry catch 咱是不是可以交给 abstract 来做。这样,异常处理,重试,限流等等,都可以酱紫 // TODO FROM 芋艿 TO zzftry catch 咱是不是可以交给 abstract 来做。这样,异常处理,重试,限流等等,都可以酱紫 DONE
try {
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
boolean result = OK.equals(sendSmsResponse.getCode()); boolean result = OK.equals(sendSmsResponse.getCode());
if (!result) { if (!result) {
log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage());
} }
SmsResult<SendSmsResponse> resultBody = new SmsResult<>(); SmsResult resultBody = new SmsResult();
resultBody.setSuccess(result); resultBody.setSuccess(result);
resultBody.setResult(sendSmsResponse); QuerySendDetailsRequest querySendDetailsRequest = new QuerySendDetailsRequest();
return resultBody; querySendDetailsRequest.setBizId(sendSmsResponse.getBizId());
} catch (Exception e) {
log.debug(e.getMessage(), e);
return failResult("发送异常: " + e.getMessage());
}
}
SmsResult<SendSmsResponse> failResult(String message) { QuerySendDetailsResponse acsResponse = acsClient.getAcsResponse(querySendDetailsRequest);
SmsResult<SendSmsResponse> resultBody = new SmsResult<>(); List<SmsResultDetail> resultDetailList = new ArrayList<>(Integer.parseInt(acsResponse.getTotalCount()));
resultBody.setSuccess(false); acsResponse.getSmsSendDetailDTOs().forEach(s -> {
resultBody.setMessage(message); 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; return resultBody;
} }

View File

@ -11,15 +11,16 @@ import java.util.Collection;
* @author zzf * @author zzf
* @date 2021/1/25 14:14 * @date 2021/1/25 14:14
*/ */
public interface SmsClient<R> { public interface SmsClient {
/** /**
* *
* *
* @param templateApiId
* @param smsBody * @param smsBody
* @param targets * @param targets
* @return * @return
*/ */
SmsResult<R> send(SmsBody smsBody, Collection<String> targets); SmsResult send(String templateApiId, SmsBody smsBody, Collection<String> targets);
} }

View File

@ -1,15 +1,14 @@
package cn.iocoder.dashboard.framework.sms.core; 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.ServiceException;
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.client.AliyunSmsClient; 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.SmsChannelProperty;
import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -24,7 +23,17 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
@Component @Component
public class SmsClientFactory { 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) * @return id(channelId)
*/ */
public Long createClient(SmsChannelProperty propertyVO) { public Long createClient(SmsChannelProperty propertyVO) {
// TODO FROM 芋艿 TO zzf参数的校验可以考虑统一使用 validation。 // TODO FROM 芋艿 TO zzf参数的校验可以考虑统一使用 validation。 DONE
if (StrUtil.isBlank(propertyVO.getCode())) { AbstractSmsClient sender = createClient(SmsChannelEnum.getByCode(propertyVO.getCode()), propertyVO);
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);
smsSenderMap.put(propertyVO.getId(), sender); smsSenderMap.put(propertyVO.getId(), sender);
return propertyVO.getId(); return propertyVO.getId();
} }
private AbstractSmsClient<?> createClient(SmsChannelEnum channelEnum, SmsChannelProperty channelVO) { private AbstractSmsClient createClient(SmsChannelEnum channelEnum, SmsChannelProperty channelVO) {
if (channelEnum == null) { if (channelEnum == null) {
throw new ServiceException(INVALID_CHANNEL_CODE); throw new ServiceException(INVALID_CHANNEL_CODE);
} }
@ -66,7 +68,38 @@ public class SmsClientFactory {
* @param channelId id * @param channelId id
* @return id * @return id
*/ */
public AbstractSmsClient<?> getClient(Long channelId) { public AbstractSmsClient getClient(Long channelId) {
return smsSenderMap.get(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();
}
} }

View File

@ -3,17 +3,24 @@ package cn.iocoder.dashboard.framework.sms.core;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
/** /**
* *
*/ */
@Data @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;
} }

View File

@ -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;
}

View File

@ -1,13 +1,10 @@
package cn.iocoder.dashboard.common.enums; package cn.iocoder.dashboard.framework.sms.core.enums;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; 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 * @author zzf
* @date 2021/1/25 10:56 * @date 2021/1/25 10:56
@ -19,7 +16,7 @@ public enum SmsChannelEnum {
ALI("ALI", "阿里"), ALI("ALI", "阿里"),
HUA_WEI("HUA_WEI", "华为"), HUA_WEI("HUA_WEI", "华为"),
QI_NIU("QI_NIU", "七牛"), QI_NIU("QI_NIU", "七牛"),
TEN_XUN("TEN_XUN", "腾讯"); // TODO FROM 芋艿 to zzfTEN 有后鼻音哈,要被马爸爸打了。。。 TENCENT("TENCENT", "腾讯"); // TODO FROM 芋艿 to zzfTEN 有后鼻音哈,要被马爸爸打了。。。 DONE
private final String code; private final String code;

View File

@ -3,6 +3,8 @@ package cn.iocoder.dashboard.framework.sms.core.property;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
@ -19,40 +21,37 @@ public class SmsChannelProperty implements Serializable {
/** /**
* id * id
*/ */
@NotNull(message = "短信渠道ID不能为空")
private Long id; private Long id;
/** /**
* ( ) * ( )
*/ */
@NotEmpty(message = "短信渠道编码不能为空")
private String code; private String code;
/** /**
* id * id
*/ */
@NotEmpty(message = "渠道账号id不能为空")
private String apiKey; private String apiKey;
/** /**
* *
*/ */
@NotEmpty(message = "渠道账号秘钥不能为空")
private String apiSecret; private String apiSecret;
/** /**
* *
*/ */
@NotEmpty(message = "实际渠道签名唯一标识不能为空")
private String apiSignatureId; private String apiSignatureId;
/** /**
* *
*/ */
@NotEmpty(message = "签名值不能为空")
private String signature; private String signature;
/**
*
*/
private List<SmsTemplateProperty> templateList;
public SmsTemplateProperty getTemplateByTemplateCode(String tempCode) {
return templateList.stream().filter(s -> s.getCode().equals(tempCode)).findFirst().get();
}
} }

View File

@ -3,8 +3,12 @@ package cn.iocoder.dashboard.framework.sms.core.property;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; 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 * @author zzf
* @date 2021/1/25 17:03 * @date 2021/1/25 17:03
@ -13,6 +17,12 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode @EqualsAndHashCode
public class SmsTemplateProperty { public class SmsTemplateProperty {
/**
* id
*/
@NotEmpty(message = "短信渠道编码不能为空")
private Long channelId;
/** /**
* (, ) * (, )
*/ */
@ -21,18 +31,19 @@ public class SmsTemplateProperty {
/** /**
* *
*/ */
@NotEmpty(message = "短信模板编码不能为空")
private String code; private String code;
/** /**
* *
*/ */
@NotEmpty(message = "短信模板唯一标识不能为空")
private String apiTemplateId; private String apiTemplateId;
/** /**
* *
*/ */
@NotEmpty(message = "短信模板内容不能为空")
private String content; private String content;
} }

View File

@ -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.SmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; 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.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 cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -23,25 +23,25 @@ import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
public class SmsChannelController { public class SmsChannelController {
@Resource @Resource
private SmsChannelService service; private SysSmsChannelService service;
@ApiOperation("获取渠道/签名分页") @ApiOperation("获取渠道/签名分页")
@GetMapping("/page") @GetMapping("/page")
public CommonResult<PageResult<SmsChannelDO>> getPermissionInfo(@Validated SmsChannelPageReqVO reqVO) { public CommonResult<PageResult<SysSmsChannelDO>> getPermissionInfo(@Validated SmsChannelPageReqVO reqVO) {
return success(service.pageChannels(reqVO)); return success(service.pageSmsChannels(reqVO));
} }
@ApiOperation("获取渠道枚举") @ApiOperation("获取渠道枚举")
@GetMapping("/list/channel-enum") @GetMapping("/list/channel-enum")
public CommonResult<List<SmsChannelEnumRespVO>> getChannelEnums() { public CommonResult<List<SmsChannelEnumRespVO>> getChannelEnums() {
return success(service.getChannelEnums()); return success(service.getSmsChannelEnums());
} }
@ApiOperation("添加消息渠道") @ApiOperation("添加消息渠道")
@PostMapping("/create") @PostMapping("/create")
public CommonResult<Long> add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) { public CommonResult<Long> add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) {
return success(service.createChannel(reqVO)); return success(service.createSmsChannel(reqVO));
} }

View File

@ -1,13 +1,13 @@
package cn.iocoder.dashboard.modules.system.convert.sms; 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.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; 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.SmsChannelAllVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; 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.sms.vo.resp.SmsChannelEnumRespVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO; 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 com.baomidou.mybatisplus.core.metadata.IPage;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
@ -21,17 +21,19 @@ public interface SmsChannelConvert {
SmsChannelConvert INSTANCE = Mappers.getMapper(SmsChannelConvert.class); SmsChannelConvert INSTANCE = Mappers.getMapper(SmsChannelConvert.class);
@Mapping(source = "records", target = "list") @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<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> convertProperty(List<SmsChannelAllVO> list);
List<SmsChannelProperty> convertProperties(List<SysSmsChannelDO> list);
} }

View File

@ -2,8 +2,8 @@ package cn.iocoder.dashboard.modules.system.convert.sms;
import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; 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.SysSmsChannelDO;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsTemplateDO;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
@ -17,10 +17,10 @@ public interface SmsTemplateConvert {
SmsTemplateConvert INSTANCE = Mappers.getMapper(SmsTemplateConvert.class); SmsTemplateConvert INSTANCE = Mappers.getMapper(SmsTemplateConvert.class);
@Mapping(source = "records", target = "list") @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);
} }

View File

@ -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)
);
}
}

View File

@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils; 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.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.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
@ -13,19 +13,19 @@ import org.apache.ibatis.annotations.Mapper;
import java.util.List; import java.util.List;
@Mapper @Mapper
public interface SmsChannelMapper extends BaseMapper<SmsChannelDO> { public interface SysSmsChannelMapper extends BaseMapper<SysSmsChannelDO> {
default IPage<SmsChannelDO> selectChannelPage(SmsChannelPageReqVO reqVO) { default IPage<SysSmsChannelDO> selectChannelPage(SmsChannelPageReqVO reqVO) {
return selectPage(MyBatisUtils.buildPage(reqVO), new LambdaQueryWrapper<SmsChannelDO>() return selectPage(MyBatisUtils.buildPage(reqVO), new LambdaQueryWrapper<SysSmsChannelDO>()
.like(StrUtil.isNotBlank(reqVO.getName()), SmsChannelDO::getName, reqVO.getName()) .like(StrUtil.isNotBlank(reqVO.getName()), SysSmsChannelDO::getName, reqVO.getName())
.like(StrUtil.isNotBlank(reqVO.getSignature()), SmsChannelDO::getName, reqVO.getSignature()) .like(StrUtil.isNotBlank(reqVO.getSignature()), SysSmsChannelDO::getName, reqVO.getSignature())
); );
} }
default List<SmsChannelDO> selectEnabledList() { default List<SysSmsChannelDO> selectEnabledList() {
return selectList(new LambdaQueryWrapper<SmsChannelDO>() return selectList(new LambdaQueryWrapper<SysSmsChannelDO>()
.eq(SmsChannelDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) .eq(SysSmsChannelDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
.orderByAsc(SmsChannelDO::getId) .orderByAsc(SysSmsChannelDO::getId)
); );
} }
} }

View File

@ -1,10 +1,10 @@
package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; 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 com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface SmsLogMapper extends BaseMapper<SmsLogDO> { public interface SysSmsLogMapper extends BaseMapper<SysSmsLogDO> {
} }

View File

@ -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)
);
}
}

View File

@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@TableName(value = "sms_channel", autoResultMap = true) @TableName(value = "sms_channel", autoResultMap = true)
public class SmsChannelDO extends BaseDO { public class SysSmsChannelDO extends BaseDO {
/** /**
* *

View File

@ -18,7 +18,7 @@ import java.util.Date;
@EqualsAndHashCode @EqualsAndHashCode
@Accessors(chain = true) @Accessors(chain = true)
@TableName(value = "sms_log", autoResultMap = true) @TableName(value = "sms_log", autoResultMap = true)
public class SmsLogDO implements Serializable { public class SysSmsLogDO implements Serializable {
/** /**
* *

View File

@ -16,7 +16,7 @@ import java.util.Date;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@TableName(value = "sms_template", autoResultMap = true) @TableName(value = "sms_template", autoResultMap = true)
public class SmsTemplateDO extends BaseDO { public class SysSmsTemplateDO extends BaseDO {
/** /**
* *

View File

@ -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.framework.sms.core.SmsResult;
import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage; 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.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 lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -20,12 +20,12 @@ import javax.annotation.Resource;
public class SmsSendConsumer extends AbstractChannelMessageListener<SmsSendMessage> { public class SmsSendConsumer extends AbstractChannelMessageListener<SmsSendMessage> {
@Resource @Resource
private SmsService smsService; private SysSmsService sysSmsService;
@Override @Override
public void onMessage(SmsSendMessage message) { public void onMessage(SmsSendMessage message) {
log.info("[onMessage][收到 发送短信 消息]"); log.info("[onMessage][收到 发送短信 消息]");
SmsResult<?> send = smsService.send(message.getSmsBody(), message.getTargetPhones()); SmsResult send = sysSmsService.send(message.getSmsBody(), message.getTargetPhones());
} }
} }

View File

@ -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.SmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; 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.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; import java.util.List;
@ -16,7 +16,7 @@ import java.util.List;
* @author zzf * @author zzf
* @date 2021/1/25 9:24 * @date 2021/1/25 9:24
*/ */
public interface SmsChannelService { public interface SysSmsChannelService {
// TODO FROM 芋艿 to ZZFSmsChannelService=》SysSmsChannelService增加 Sys 前缀,算在系统模块里 // TODO FROM 芋艿 to ZZFSmsChannelService=》SysSmsChannelService增加 Sys 前缀,算在系统模块里
// TODO FROM 芋艿 to ZZF方法名保持不去掉 Sms 前缀。虽然长点,嘿嘿 // TODO FROM 芋艿 to ZZF方法名保持不去掉 Sms 前缀。虽然长点,嘿嘿
@ -32,7 +32,7 @@ public interface SmsChannelService {
* @param reqVO * @param reqVO
* @return * @return
*/ */
PageResult<SmsChannelDO> pageChannels(SmsChannelPageReqVO reqVO); PageResult<SysSmsChannelDO> pageSmsChannels(SmsChannelPageReqVO reqVO);
/** /**
* *
@ -40,14 +40,14 @@ public interface SmsChannelService {
* @param reqVO * @param reqVO
* @return id * @return id
*/ */
Long createChannel(SmsChannelCreateReqVO reqVO); Long createSmsChannel(SmsChannelCreateReqVO reqVO);
/** /**
* / * /
* *
* @return / * @return /
*/ */
List<SmsChannelEnumRespVO> getChannelEnums(); List<SmsChannelEnumRespVO> getSmsChannelEnums();
/** /**
* *
@ -55,12 +55,20 @@ public interface SmsChannelService {
* @param templateCode * @param templateCode
* @return * @return
*/ */
AbstractSmsClient<?> getClient(String templateCode); AbstractSmsClient getSmsClient(String templateCode);
/**
*
*
* @param templateCode
* @return
*/
String getSmsTemplateApiIdByCode(String templateCode);
/** /**
* () * ()
* *
* @return () * @return ()
*/ */
List<SmsChannelAllVO> listChannelAllEnabledInfo(); List<SmsChannelAllVO> listSmsChannelAllEnabledInfo();
} }

View File

@ -12,7 +12,7 @@ import java.util.List;
* @author zzf * @author zzf
* @date 2021/1/25 9:24 * @date 2021/1/25 9:24
*/ */
public interface SmsLogService { public interface SysSmsLogService {
/** /**
* *
* *
@ -22,9 +22,11 @@ public interface SmsLogService {
* @param isAsync * @param isAsync
* @return id * @return id
*/ */
// TODO FROM 芋艿 to ZZF: async 是针对发送的方式,对于日志不一定需要关心。这样,短信日志,实际就发送前插入,发送后更新结果 // TODO FROM 芋艿 to ZZF: async 是针对发送的方式,对于日志不一定需要关心。这样,短信日志,实际就发送前插入,发送后更新结果.
// 这里只用于记录状态,毕竟异步可能推送失败,此时日志可记录该状态。
// TODO FROM 芋艿 to ZZF短信日志群发的情况应该是每个手机一条哈。虽然是群发但是可能部分成功部分失败对应到短信平台实际也是多条。 // 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 logId id
* @param result * @param result
*/ */
void afterSendLog(Long logId, SmsResult<?> result); void afterSendLog(Long logId, SmsResult result);
} }

View File

@ -14,7 +14,7 @@ import java.util.List;
* @author zzf * @author zzf
* @date 2021/1/25 9:24 * @date 2021/1/25 9:24
*/ */
public interface SmsService { public interface SysSmsService {
/** /**
* *
@ -23,7 +23,7 @@ public interface SmsService {
* @param targetPhones * @param targetPhones
* @return * @return
*/ */
SmsResult<?> send(SmsBody smsBody, List<String> targetPhones); SmsResult send(SmsBody smsBody, List<String> targetPhones);
/** /**
* *
@ -32,7 +32,7 @@ public interface SmsService {
* @param targetPhone * @param targetPhone
* @return * @return
*/ */
default SmsResult<?> send(SmsBody smsBody, String targetPhone) { default SmsResult send(SmsBody smsBody, String targetPhone) {
if (StringUtils.isBlank(targetPhone)) { if (StringUtils.isBlank(targetPhone)) {
return failResult("targetPhone must not null."); return failResult("targetPhone must not null.");
} }
@ -47,7 +47,7 @@ public interface SmsService {
* @param targetPhones * @param targetPhones
* @return * @return
*/ */
default SmsResult<?> send(SmsBody smsBody, String... targetPhones) { default SmsResult send(SmsBody smsBody, String... targetPhones) {
if (targetPhones == null) { if (targetPhones == null) {
return failResult("targetPhones must not null."); return failResult("targetPhones must not null.");
} }
@ -91,8 +91,8 @@ public interface SmsService {
} }
default SmsResult<?> failResult(String message) { default SmsResult failResult(String message) {
SmsResult<?> resultBody = new SmsResult<>(); SmsResult resultBody = new SmsResult();
resultBody.setSuccess(false); resultBody.setSuccess(false);
resultBody.setMessage(message); resultBody.setMessage(message);
return resultBody; return resultBody;

View File

@ -6,5 +6,5 @@ package cn.iocoder.dashboard.modules.system.service.sms;
* @author zzf * @author zzf
* @date 2021/1/25 9:24 * @date 2021/1/25 9:24
*/ */
public interface SmsTemplateService { public interface SysSmsTemplateService {
} }

View File

@ -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);
}
}

View File

@ -1,10 +1,10 @@
package cn.iocoder.dashboard.modules.system.service.sms.impl; package cn.iocoder.dashboard.modules.system.service.sms.impl;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.dashboard.common.enums.SmsChannelEnum;
import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory; 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.framework.sms.core.property.SmsChannelProperty;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; 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.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.controller.sms.vo.resp.SmsChannelEnumRespVO;
import cn.iocoder.dashboard.modules.system.convert.sms.SmsChannelConvert; import cn.iocoder.dashboard.modules.system.convert.sms.SmsChannelConvert;
import cn.iocoder.dashboard.modules.system.convert.sms.SmsTemplateConvert; 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.SysSmsChannelMapper;
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsTemplateMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsTemplateMapper;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -35,12 +35,12 @@ import java.util.concurrent.ConcurrentHashMap;
* @date 2021/1/25 9:25 * @date 2021/1/25 9:25
*/ */
@Service @Service
public class SmsChannelServiceImpl implements SmsChannelService { public class SysSmsChannelServiceImpl implements SysSmsChannelService {
private final Map<String, Long> templateCode2ChannelIdMap = new ConcurrentHashMap<>(32); private final Map<String, Long> templateCode2ChannelIdMap = new ConcurrentHashMap<>(32);
@Autowired @Autowired
private SmsClientFactory smsClientFactory; private SmsClientFactory clientFactory;
/** /**
* *
@ -48,51 +48,60 @@ public class SmsChannelServiceImpl implements SmsChannelService {
@PostConstruct @PostConstruct
@Override @Override
public void initSmsClient() { public void initSmsClient() {
List<SmsChannelAllVO> smsChannelAllVOList = listChannelAllEnabledInfo(); // 查询有效渠道信息
if (ObjectUtil.isEmpty(smsChannelAllVOList)) { List<SysSmsChannelDO> channelDOList = channelMapper.selectEnabledList();
return; List<SmsChannelProperty> propertyList = SmsChannelConvert.INSTANCE.convertProperties(channelDOList);
}
List<SmsChannelProperty> channelPropertyList = SmsChannelConvert.INSTANCE.convertProperty(smsChannelAllVOList); // 遍历渠道生成client并获取模板缓存
channelPropertyList.forEach(smsChannelProperty -> { propertyList.forEach(channelProperty -> {
Long clientId = smsClientFactory.createClient(smsChannelProperty); Long clientId = clientFactory.createClient(channelProperty);
smsChannelProperty.getTemplateList().forEach(smsTemplateVO -> { List<SysSmsTemplateDO> templateDOList = templateMapper.selectListByChannelId(channelProperty.getId());
templateCode2ChannelIdMap.put(smsTemplateVO.getCode(), clientId); if (ObjectUtil.isNotEmpty(templateDOList)) {
templateDOList.forEach(template -> {
templateCode2ChannelIdMap.put(template.getCode(), clientId);
}); });
SmsTemplateConvert.INSTANCE.convert(templateDOList);
}
}); });
} }
// TODO FROM 芋艿 to ZZFchannelMapper 嘿,保持命名统一。 // TODO FROM 芋艿 to ZZFchannelMapper 嘿,保持命名统一。 DONE
@Resource @Resource
private SmsChannelMapper mapper; private SysSmsChannelMapper channelMapper;
@Resource @Resource
private SmsTemplateMapper templateMapper; private SysSmsTemplateMapper templateMapper;
@Override @Override
public PageResult<SmsChannelDO> pageChannels(SmsChannelPageReqVO reqVO) { public PageResult<SysSmsChannelDO> pageSmsChannels(SmsChannelPageReqVO reqVO) {
return SmsChannelConvert.INSTANCE.convertPage(mapper.selectChannelPage(reqVO)); return SmsChannelConvert.INSTANCE.convertPage(channelMapper.selectChannelPage(reqVO));
} }
@Override @Override
public Long createChannel(SmsChannelCreateReqVO reqVO) { public Long createSmsChannel(SmsChannelCreateReqVO reqVO) {
SmsChannelDO channelDO = SmsChannelConvert.INSTANCE.convert(reqVO); SysSmsChannelDO channelDO = SmsChannelConvert.INSTANCE.convert(reqVO);
mapper.insert(channelDO); channelMapper.insert(channelDO);
return channelDO.getId(); return channelDO.getId();
} }
@Override @Override
public List<SmsChannelEnumRespVO> getChannelEnums() { public List<SmsChannelEnumRespVO> getSmsChannelEnums() {
return SmsChannelConvert.INSTANCE.convertEnum(Arrays.asList(SmsChannelEnum.values())); return SmsChannelConvert.INSTANCE.convertEnum(Arrays.asList(SmsChannelEnum.values()));
} }
@Override @Override
public AbstractSmsClient<?> getClient(String templateCode) { public AbstractSmsClient getSmsClient(String templateCode) {
return smsClientFactory.getClient(templateCode2ChannelIdMap.get(templateCode)); return clientFactory.getClient(templateCode2ChannelIdMap.get(templateCode));
} }
@Override @Override
public List<SmsChannelAllVO> listChannelAllEnabledInfo() { public String getSmsTemplateApiIdByCode(String templateCode) {
List<SmsChannelDO> channelDOList = mapper.selectEnabledList(); return clientFactory.getTemplateApiIdByCode(templateCode);
}
@Override
public List<SmsChannelAllVO> listSmsChannelAllEnabledInfo() {
List<SysSmsChannelDO> channelDOList = channelMapper.selectEnabledList();
if (ObjectUtil.isNull(channelDOList)) { if (ObjectUtil.isNull(channelDOList)) {
return null; return null;
} }
@ -100,7 +109,7 @@ public class SmsChannelServiceImpl implements SmsChannelService {
channelAllVOList.forEach(smsChannelDO -> { channelAllVOList.forEach(smsChannelDO -> {
List<SmsTemplateDO> templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId()); List<SysSmsTemplateDO> templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId());
if (ObjectUtil.isNull(templateDOList)) { if (ObjectUtil.isNull(templateDOList)) {
templateDOList = new ArrayList<>(); templateDOList = new ArrayList<>();
} }

View File

@ -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.client.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsBody;
import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResult;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsLogMapper;
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsLogMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsLogDO;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsLogDO;
import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; 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.json.JsonUtils;
import cn.iocoder.dashboard.util.string.StrUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -23,42 +21,41 @@ import java.util.List;
* @date 2021/1/25 9:25 * @date 2021/1/25 9:25
*/ */
@Service @Service
public class SmsLogServiceImpl implements SmsLogService { public class SysSmsLogServiceImpl implements SysSmsLogService {
@Resource @Resource
private SmsLogMapper smsLogMapper; private SysSmsLogMapper logMapper;
@Override @Override
public Long beforeSendLog(SmsBody smsBody, List<String> targetPhones, AbstractSmsClient<?> client, Boolean isAsync) { public Long beforeSendLog(SmsBody smsBody, List<String> targetPhones, AbstractSmsClient client, Boolean isAsync) {
SmsLogDO smsLog = new SmsLogDO(); SysSmsLogDO smsLog = new SysSmsLogDO();
if (smsBody.getSmsLogId() != null) { if (smsBody.getSmsLogId() != null) {
smsLog.setId(smsBody.getSmsLogId()); smsLog.setId(smsBody.getSmsLogId());
smsLog.setSendStatus(SmsSendStatusEnum.SENDING.getStatus()); smsLog.setSendStatus(SmsSendStatusEnum.SENDING.getStatus());
smsLogMapper.updateById(smsLog); logMapper.updateById(smsLog);
return smsBody.getSmsLogId(); return smsBody.getSmsLogId();
} else { } else {
SmsChannelAllVO property = client.getProperty(); SmsChannelProperty property = client.getProperty();
SmsTemplateVO smsTemplate = property.getTemplateByTemplateCode(smsBody.getTemplateCode());
smsLog.setChannelCode(property.getCode()) smsLog.setChannelCode(property.getCode())
.setChannelId(property.getId()) .setChannelId(property.getId())
.setTemplateCode(smsTemplate.getCode()) .setTemplateCode(smsBody.getTemplateCode())
.setPhones(JsonUtils.toJsonString(targetPhones)) .setPhones(JsonUtils.toJsonString(targetPhones))
.setContent(StrUtils.replace(smsTemplate.getContent(), smsBody.getParams())); .setContent(smsBody.getParams().toString());
if (isAsync) { if (isAsync) {
smsLog.setSendStatus(SmsSendStatusEnum.ASYNC.getStatus()); smsLog.setSendStatus(SmsSendStatusEnum.ASYNC.getStatus());
} else { } else {
smsLog.setSendStatus(SmsSendStatusEnum.SENDING.getStatus()); smsLog.setSendStatus(SmsSendStatusEnum.SENDING.getStatus());
} }
smsLogMapper.insert(smsLog); logMapper.insert(smsLog);
return smsLog.getId(); return smsLog.getId();
} }
} }
@Override @Override
public void afterSendLog(Long logId, SmsResult<?> result) { public void afterSendLog(Long logId, SmsResult result) {
SmsLogDO smsLog = new SmsLogDO(); SysSmsLogDO smsLog = new SysSmsLogDO();
smsLog.setId(logId); smsLog.setId(logId);
if (result.getSuccess()) { if (result.getSuccess()) {
smsLog.setSendStatus(SmsSendStatusEnum.SUCCESS.getStatus()); smsLog.setSendStatus(SmsSendStatusEnum.SUCCESS.getStatus());
@ -66,7 +63,7 @@ public class SmsLogServiceImpl implements SmsLogService {
smsLog.setSendStatus(SmsSendStatusEnum.FAIL.getStatus()); smsLog.setSendStatus(SmsSendStatusEnum.FAIL.getStatus());
smsLog.setRemark(result.getMessage() + JsonUtils.toJsonString(result.getResult())); smsLog.setRemark(result.getMessage() + JsonUtils.toJsonString(result.getResult()));
} }
smsLogMapper.updateById(smsLog); logMapper.updateById(smsLog);
} }
} }

View File

@ -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);
}
}

View File

@ -1,6 +1,6 @@
package cn.iocoder.dashboard.modules.system.service.sms.impl; 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; import org.springframework.stereotype.Service;
/** /**
@ -10,5 +10,5 @@ import org.springframework.stereotype.Service;
* @date 2021/1/25 9:25 * @date 2021/1/25 9:25
*/ */
@Service @Service
public class SmsTemplateServiceImpl implements SmsTemplateService { public class SysSmsTemplateServiceImpl implements SysSmsTemplateService {
} }