短信渠道的 CRUD 后端代码的完成

This commit is contained in:
YunaiV 2021-04-05 02:52:58 +08:00
parent 86cbf21d6d
commit d8d458a024
22 changed files with 520 additions and 270 deletions

View File

@ -1,6 +1,8 @@
package cn.iocoder.dashboard.modules.system.controller.sms; package cn.iocoder.dashboard.modules.system.controller.sms;
import cn.hutool.core.util.URLUtil; import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog; import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService;
@ -13,6 +15,9 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
@Api(tags = "短信回调") @Api(tags = "短信回调")
@RestController @RestController
@ -32,4 +37,13 @@ public class SmsCallbackController {
return "SUCCESS"; // 约定返回 SUCCESS 为成功 return "SUCCESS"; // 约定返回 SUCCESS 为成功
} }
@PostMapping("/sms/aliyun")
@ApiOperation(value = "阿里云短信的回调", notes = "参见 https://help.aliyun.com/document_detail/120998.html 文档")
@OperateLog(enable = false)
public CommonResult<Boolean> receiveAliyunSmsStatus(HttpServletRequest request) throws Throwable {
String text = ServletUtil.getBody(request);
smsService.receiveSmsStatus(SmsChannelEnum.ALIYUN.getCode(), text);
return success(true);
}
} }

View File

@ -2,37 +2,71 @@ package cn.iocoder.dashboard.modules.system.controller.sms;
import cn.iocoder.dashboard.common.pojo.CommonResult; import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.common.pojo.PageResult; 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.channel.SysSmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelRespVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO;
import cn.iocoder.dashboard.modules.system.convert.sms.SysSmsChannelConvert;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.iocoder.dashboard.common.pojo.CommonResult.success; import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
@Api("短信 渠道/签名 API") @Api(tags = "短信渠道")
@RestController @RestController
@RequestMapping("/sms/channel") @RequestMapping("/sms/channel")
public class SmsChannelController { public class SmsChannelController {
@Resource @Resource
private SysSmsChannelService service; private SysSmsChannelService smsChannelService;
@ApiOperation("获取渠道/签名分页") @PostMapping("/create")
@GetMapping("/page") @ApiOperation("创建短信渠道")
public CommonResult<PageResult<SysSmsChannelDO>> getPermissionInfo(@Validated SmsChannelPageReqVO reqVO) { @PreAuthorize("@ss.hasPermission('system:sms-channel:create')")
return success(service.pageSmsChannels(reqVO)); public CommonResult<Long> createSmsChannel(@Valid @RequestBody SysSmsChannelCreateReqVO createReqVO) {
return success(smsChannelService.createSmsChannel(createReqVO));
} }
@ApiOperation("添加消息渠道") @PutMapping("/update")
@PostMapping("/create") @ApiOperation("更新短信渠道")
public CommonResult<Long> add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) { @PreAuthorize("@ss.hasPermission('system:sms-channel:update')")
return success(service.createSmsChannel(reqVO)); public CommonResult<Boolean> updateSmsChannel(@Valid @RequestBody SysSmsChannelUpdateReqVO updateReqVO) {
smsChannelService.updateSmsChannel(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除短信渠道")
@ApiImplicitParam(name = "id", value = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:sms-channel:delete')")
public CommonResult<Boolean> deleteSmsChannel(@RequestParam("id") Long id) {
smsChannelService.deleteSmsChannel(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得短信渠道")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:sms-channel:query')")
public CommonResult<SysSmsChannelRespVO> getSmsChannel(@RequestParam("id") Long id) {
SysSmsChannelDO smsChannel = smsChannelService.getSmsChannel(id);
return success(SysSmsChannelConvert.INSTANCE.convert(smsChannel));
}
@GetMapping("/page")
@ApiOperation("获得短信渠道分页")
@PreAuthorize("@ss.hasPermission('system:sms-channel:query')")
public CommonResult<PageResult<SysSmsChannelRespVO>> getSmsChannelPage(@Valid SysSmsChannelPageReqVO pageVO) {
PageResult<SysSmsChannelDO> pageResult = smsChannelService.getSmsChannelPage(pageVO);
return success(SysSmsChannelConvert.INSTANCE.convertPage(pageResult));
} }
} }

View File

@ -1,58 +0,0 @@
package cn.iocoder.dashboard.modules.system.controller.sms.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.List;
/**
* 渠道(包含模板)信息VO类
*
* @author zzf
* @date 2021/1/25 17:01
*/
@Data
@EqualsAndHashCode
public class SmsChannelAllVO implements Serializable {
/**
* id
*/
private Long id;
/**
* 编码(来自枚举类 阿里华为七牛等)
*/
private String code;
/**
* 渠道账号id
*/
private String apiKey;
/**
* 渠道账号秘钥
*/
private String apiSecret;
/**
* 实际渠道签名唯一标识
*/
private String apiSignatureId;
/**
* 签名值
*/
private String signature;
/**
* 该渠道名下的短信模板集合
*/
private List<SmsTemplateVO> templateList;
public SmsTemplateVO getTemplateByTemplateCode(String tempCode) {
return templateList.stream().filter(s -> s.getCode().equals(tempCode)).findFirst().get();
}
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 短信渠道 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class SysSmsChannelBaseVO {
@ApiModelProperty(value = "短信签名", required = true, example = "芋道源码")
@NotNull(message = "短信签名不能为空")
private String signature;
@ApiModelProperty(value = "任务状态", required = true, example = "1")
@NotNull(message = "任务状态不能为空")
private Integer status;
@ApiModelProperty(value = "备注", example = "好吃!")
private String remark;
@ApiModelProperty(value = "短信 API 的账号", required = true, example = "yudao")
@NotNull(message = "短信 API 的账号不能为空")
private String apiKey;
@ApiModelProperty(value = "短信 API 的秘钥", example = "yuanma")
private String apiSecret;
@ApiModelProperty(value = "短信发送回调 URL", example = "http://www.iocoder.cn")
private String callbackUrl;
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
@ApiModel("短信渠道创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysSmsChannelCreateReqVO extends SysSmsChannelBaseVO {
@ApiModelProperty(value = "渠道编码", required = true, example = "YUN_PIAN", notes = "参见 SmsChannelEnum 枚举类")
@NotNull(message = "渠道编码不能为空")
private String code;
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel;
import cn.iocoder.dashboard.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("短信渠道分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysSmsChannelPageReqVO extends PageParam {
@ApiModelProperty(value = "任务状态", example = "1")
private Integer status;
@ApiModelProperty(value = "短信签名", example = "芋道源码", notes = "模糊匹配")
private String signature;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
@ApiModel("短信渠道 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysSmsChannelRespVO extends SysSmsChannelBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "渠道编码", required = true, example = "YUN_PIAN", notes = "参见 SmsChannelEnum 枚举类")
private String code;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
@ApiModel("短信渠道更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysSmsChannelUpdateReqVO extends SysSmsChannelBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
@NotNull(message = "编号不能为空")
private Long id;
}

View File

@ -1,44 +0,0 @@
package cn.iocoder.dashboard.modules.system.controller.sms.vo.req;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@ApiModel("消息渠道创建 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class SmsChannelCreateReqVO implements Serializable {
@ApiModelProperty("编码(来自枚举类 阿里、华为、七牛等)")
private String code;
@ApiModelProperty("渠道账号id")
private String apiKey;
@ApiModelProperty("渠道账号秘钥")
private String apiSecret;
@ApiModelProperty("优先级(存在多个签名时,选择值最小的,渠道不可用时,按优先级从小到大切换)")
private Integer priority;
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("签名值")
private String signature;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("启用状态0正常 1停用")
private Integer status;
}

View File

@ -1,21 +0,0 @@
package cn.iocoder.dashboard.modules.system.controller.sms.vo.req;
import cn.iocoder.dashboard.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@ApiModel("消息渠道分页 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class SmsChannelPageReqVO extends PageParam {
@ApiModelProperty(value = "签名值", example = "源码", notes = "模糊匹配")
private String signature;
}

View File

@ -1,43 +0,0 @@
package cn.iocoder.dashboard.modules.system.controller.sms.vo.resp;
import cn.iocoder.dashboard.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("用户分页 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class SmsChannelPageRespVO extends PageParam {
@ApiModelProperty(value = "用户账号", example = "yudao", notes = "模糊匹配")
private String username;
@ApiModelProperty(value = "手机号码", example = "yudao", notes = "模糊匹配")
private String mobile;
@ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类")
private Integer status;
@ApiModelProperty(value = "开始时间", example = "2020-10-24")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date beginTime;
@ApiModelProperty(value = "结束时间", example = "2020-10-24")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endTime;
@ApiModelProperty(value = "部门编号", example = "1024", notes = "同时筛选子部门")
private Long deptId;
}

View File

@ -1,28 +0,0 @@
package cn.iocoder.dashboard.modules.system.convert.sms;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface SmsChannelConvert {
SmsChannelConvert INSTANCE = Mappers.getMapper(SmsChannelConvert.class);
SysSmsChannelDO convert(SmsChannelCreateReqVO bean);
SysSmsChannelDO convert(SysUserUpdateReqVO bean);
List<SmsChannelAllVO> convert(List<SysSmsChannelDO> bean);
List<SmsChannelProperties> convertProperty(List<SmsChannelAllVO> list);
List<SmsChannelProperties> convertList(List<SysSmsChannelDO> list);
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.dashboard.modules.system.convert.sms;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelRespVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 短信渠道 Convert
*
* @author 芋道源码
*/
@Mapper
public interface SysSmsChannelConvert {
SysSmsChannelConvert INSTANCE = Mappers.getMapper(SysSmsChannelConvert.class);
SysSmsChannelDO convert(SysSmsChannelCreateReqVO bean);
SysSmsChannelDO convert(SysSmsChannelUpdateReqVO bean);
SysSmsChannelRespVO convert(SysSmsChannelDO bean);
List<SysSmsChannelRespVO> convertList(List<SysSmsChannelDO> list);
PageResult<SysSmsChannelRespVO> convertPage(PageResult<SysSmsChannelDO> page);
List<SmsChannelProperties> convertList02(List<SysSmsChannelDO> list);
}

View File

@ -1,9 +1,9 @@
package cn.iocoder.dashboard.modules.system.dal.mysql.sms; package cn.iocoder.dashboard.modules.system.dal.mysql.sms;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@ -13,14 +13,16 @@ import java.util.List;
@Mapper @Mapper
public interface SysSmsChannelMapper extends BaseMapperX<SysSmsChannelDO> { public interface SysSmsChannelMapper extends BaseMapperX<SysSmsChannelDO> {
default PageResult<SysSmsChannelDO> selectChannelPage(SmsChannelPageReqVO reqVO) { default PageResult<SysSmsChannelDO> selectPage(SysSmsChannelPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapper<SysSmsChannelDO>() return selectPage(reqVO, new QueryWrapperX<SysSmsChannelDO>()
.like(StrUtil.isNotBlank(reqVO.getSignature()), SysSmsChannelDO::getSignature, reqVO.getSignature())); .likeIfPresent("signature", reqVO.getSignature())
.eqIfPresent("status", reqVO.getStatus())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id"));
} }
default List<SysSmsChannelDO> selectListByStatus(Integer status) { default List<SysSmsChannelDO> selectListByStatus(Integer status) {
return selectList(new LambdaQueryWrapper<SysSmsChannelDO>() return selectList(new LambdaQueryWrapper<SysSmsChannelDO>().eq(SysSmsChannelDO::getStatus, status)
.eq(SysSmsChannelDO::getStatus, status)
.orderByAsc(SysSmsChannelDO::getId)); .orderByAsc(SysSmsChannelDO::getId));
} }

View File

@ -78,19 +78,15 @@ public interface SysErrorCodeConstants {
ErrorCode FILE_UPLOAD_FAILED = new ErrorCode(1002009002, "文件上传失败"); ErrorCode FILE_UPLOAD_FAILED = new ErrorCode(1002009002, "文件上传失败");
ErrorCode FILE_IS_EMPTY= new ErrorCode(1002009003, "文件为空"); ErrorCode FILE_IS_EMPTY= new ErrorCode(1002009003, "文件为空");
// ========== 短信渠道 1002011000 ==========
ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1002011000, "短信渠道不存在");
// ========== 短信模板 1002010000 ========== // ========== 短信模板 1002011000 ==========
ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002010000, "短信模板不存在"); ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002011000, "短信模板不存在");
// ========== 短信发送 1002011000 ========== // ========== 短信发送 1002012000 ==========
ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1002011000, "手机号不存在"); ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1002012000, "手机号不存在");
ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1002011001, "模板参数({})缺失"); ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1002012001, "模板参数({})缺失");
ErrorCode SMS_CHANNEL_NOT_INIT = new ErrorCode(1003001001,
"短信渠道没有初始化, 请调用SmsClientWrapper#initSmsClient()或SmsClientWrapper#addSmsClient");
ErrorCode SMS_CHANNEL_NOT_FOUND = new ErrorCode(1003001002, "没有短信渠道信息, 请初始化sms_channel表数据。");
ErrorCode SMS_SENDER_NOT_FOUND = new ErrorCode(1003001004, "没有找到对应的短信发送对象请检查sms_channel表和sms_template表数据");
ErrorCode INVALID_CHANNEL_CODE = new ErrorCode(1003001005, "非法的短信渠道code请检查sms_channel表的code值是否与SmsChannelEnum中的code值一致。");
ErrorCode PARAM_VALUE_IS_NULL = new ErrorCode(1003001006, "参数【{}】不能为空");
} }

View File

@ -18,6 +18,7 @@ public enum SysDictTypeEnum {
SYS_LOGIN_RESULT("sys_login_result"), // 登陆结果 SYS_LOGIN_RESULT("sys_login_result"), // 登陆结果
SYS_CONFIG_TYPE("sys_config_type"), // 参数配置类型 SYS_CONFIG_TYPE("sys_config_type"), // 参数配置类型
SYS_BOOLEAN_STRING("sys_boolean_string"), // Boolean 是否类型 SYS_BOOLEAN_STRING("sys_boolean_string"), // Boolean 是否类型
SYS_SMS_CHANNEL_CODE("sys_sms_channel_code"), // 短信渠道编码
INF_REDIS_TIMEOUT_TYPE("inf_redis_timeout_type"), // Redis 超时类型 INF_REDIS_TIMEOUT_TYPE("inf_redis_timeout_type"), // Redis 超时类型
INF_JOB_STATUS("inf_job_status"), // 定时任务状态的枚举 INF_JOB_STATUS("inf_job_status"), // 定时任务状态的枚举

View File

@ -1,10 +1,15 @@
package cn.iocoder.dashboard.modules.system.service.sms; package cn.iocoder.dashboard.modules.system.service.sms;
import cn.iocoder.dashboard.common.pojo.PageResult; 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.channel.SysSmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
/** /**
* 短信渠道Service接口 * 短信渠道Service接口
* *
@ -19,19 +24,49 @@ public interface SysSmsChannelService {
void initSmsClients(); void initSmsClients();
/** /**
* 分页查询短信渠道信息 * 创建短信渠道
* *
* @param reqVO 参数对象 * @param createReqVO 创建信息
* @return 短信渠道分页对象 * @return 编号
*/ */
PageResult<SysSmsChannelDO> pageSmsChannels(SmsChannelPageReqVO reqVO); Long createSmsChannel(@Valid SysSmsChannelCreateReqVO createReqVO);
/** /**
* 创建新的渠道信息 * 更新短信渠道
* *
* @param reqVO 参数对象 * @param updateReqVO 更新信息
* @return 渠道id
*/ */
Long createSmsChannel(SmsChannelCreateReqVO reqVO); void updateSmsChannel(@Valid SysSmsChannelUpdateReqVO updateReqVO);
/**
* 删除短信渠道
*
* @param id 编号
*/
void deleteSmsChannel(Long id);
/**
* 获得短信渠道
*
* @param id 编号
* @return 短信渠道
*/
SysSmsChannelDO getSmsChannel(Long id);
/**
* 获得短信渠道列表
*
* @param ids 编号
* @return 短信渠道列表
*/
List<SysSmsChannelDO> getSmsChannelList(Collection<Long> ids);
/**
* 获得短信渠道分页
*
* @param pageReqVO 分页查询
* @return 短信渠道分页
*/
PageResult<SysSmsChannelDO> getSmsChannelPage(SysSmsChannelPageReqVO pageReqVO);
} }

View File

@ -4,9 +4,10 @@ import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO;
import cn.iocoder.dashboard.modules.system.convert.sms.SmsChannelConvert; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO;
import cn.iocoder.dashboard.modules.system.convert.sms.SysSmsChannelConvert;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsChannelMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsChannelMapper;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
@ -14,8 +15,12 @@ import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collection;
import java.util.List; import java.util.List;
import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS;
/** /**
* 短信渠道Service实现类 * 短信渠道Service实现类
* *
@ -29,46 +34,65 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService {
private SmsClientFactory smsClientFactory; private SmsClientFactory smsClientFactory;
@Resource @Resource
private SysSmsChannelMapper channelMapper; private SysSmsChannelMapper smsChannelMapper;
@Override @Override
@PostConstruct @PostConstruct
public void initSmsClients() { public void initSmsClients() {
// 查询有效渠道信息 // 查询有效渠道信息
List<SysSmsChannelDO> channelDOList = channelMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); List<SysSmsChannelDO> channelDOList = smsChannelMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
// 创建渠道 Client // 创建渠道 Client
List<SmsChannelProperties> propertiesList = SmsChannelConvert.INSTANCE.convertList(channelDOList); List<SmsChannelProperties> propertiesList = SysSmsChannelConvert.INSTANCE.convertList02(channelDOList);
propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties)); propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));
} }
// TODO 芋艿刷新缓存 // TODO 芋艿刷新缓存
@Override @Override
public PageResult<SysSmsChannelDO> pageSmsChannels(SmsChannelPageReqVO reqVO) { public Long createSmsChannel(SysSmsChannelCreateReqVO createReqVO) {
return channelMapper.selectChannelPage(reqVO); // 插入
SysSmsChannelDO smsChannel = SysSmsChannelConvert.INSTANCE.convert(createReqVO);
smsChannelMapper.insert(smsChannel);
// 返回
return smsChannel.getId();
} }
@Override @Override
public Long createSmsChannel(SmsChannelCreateReqVO reqVO) { public void updateSmsChannel(SysSmsChannelUpdateReqVO updateReqVO) {
SysSmsChannelDO channelDO = SmsChannelConvert.INSTANCE.convert(reqVO); // 校验存在
channelMapper.insert(channelDO); this.validateSmsChannelExists(updateReqVO.getId());
return channelDO.getId(); // 更新
SysSmsChannelDO updateObj = SysSmsChannelConvert.INSTANCE.convert(updateReqVO);
smsChannelMapper.updateById(updateObj);
}
@Override
public void deleteSmsChannel(Long id) {
// 校验存在
this.validateSmsChannelExists(id);
// 更新
smsChannelMapper.deleteById(id);
}
private void validateSmsChannelExists(Long id) {
if (smsChannelMapper.selectById(id) == null) {
throw exception(SMS_CHANNEL_NOT_EXISTS);
}
}
@Override
public SysSmsChannelDO getSmsChannel(Long id) {
return smsChannelMapper.selectById(id);
}
@Override
public List<SysSmsChannelDO> getSmsChannelList(Collection<Long> ids) {
return smsChannelMapper.selectBatchIds(ids);
}
@Override
public PageResult<SysSmsChannelDO> getSmsChannelPage(SysSmsChannelPageReqVO pageReqVO) {
return smsChannelMapper.selectPage(pageReqVO);
} }
// @Override
// public List<SmsChannelAllVO> listSmsChannelAllEnabledInfo() {
// List<SysSmsChannelDO> channelDOList = channelMapper.selectListByStatus();
// if (ObjectUtil.isNull(channelDOList)) {
// return null;
// }
// List<SmsChannelAllVO> channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList);
// channelAllVOList.forEach(smsChannelDO -> {
// List<SysSmsTemplateDO> templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId());
// if (ObjectUtil.isNull(templateDOList)) {
// templateDOList = new ArrayList<>();
// }
// smsChannelDO.setTemplateList(SmsTemplateConvert.INSTANCE.convert(templateDOList));
// });
// return channelAllVOList;
// }
} }

View File

@ -270,4 +270,5 @@ class SysDeptServiceTest extends BaseDbUnitTest {
}; };
return randomPojo(SysDeptDO.class, ArrayUtils.append(consumer, consumers)); return randomPojo(SysDeptDO.class, ArrayUtils.append(consumer, consumers));
} }
} }

View File

@ -0,0 +1,149 @@
package cn.iocoder.dashboard.modules.system.service.sms;
import cn.iocoder.dashboard.BaseDbUnitTest;
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsChannelMapper;
import cn.iocoder.dashboard.modules.system.service.sms.impl.SysSmsChannelServiceImpl;
import cn.iocoder.dashboard.util.collection.ArrayUtils;
import cn.iocoder.dashboard.util.object.ObjectUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import java.util.function.Consumer;
import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS;
import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
import static cn.iocoder.dashboard.util.RandomUtils.*;
import static cn.iocoder.dashboard.util.date.DateUtils.buildTime;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link SysSmsChannelServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import(SysSmsChannelServiceImpl.class)
public class SysSmsChannelServiceTest extends BaseDbUnitTest {
@Resource
private SysSmsChannelServiceImpl smsChannelService;
@MockBean
private SmsClientFactory smsClientFactory;
@Resource
private SysSmsChannelMapper smsChannelMapper;
@Test
public void testCreateSmsChannel_success() {
// 准备参数
SysSmsChannelCreateReqVO reqVO = randomPojo(SysSmsChannelCreateReqVO.class, o -> o.setStatus(randomCommonStatus()));
// 调用
Long smsChannelId = smsChannelService.createSmsChannel(reqVO);
// 断言
assertNotNull(smsChannelId);
// 校验记录的属性是否正确
SysSmsChannelDO smsChannel = smsChannelMapper.selectById(smsChannelId);
assertPojoEquals(reqVO, smsChannel);
}
@Test
public void testUpdateSmsChannel_success() {
// mock 数据
SysSmsChannelDO dbSmsChannel = randomSmsChannelDO();
smsChannelMapper.insert(dbSmsChannel);// @Sql: 先插入出一条存在的数据
// 准备参数
SysSmsChannelUpdateReqVO reqVO = randomPojo(SysSmsChannelUpdateReqVO.class, o -> {
o.setId(dbSmsChannel.getId()); // 设置更新的 ID
o.setStatus(randomCommonStatus());
});
// 调用
smsChannelService.updateSmsChannel(reqVO);
// 校验是否更新正确
SysSmsChannelDO smsChannel = smsChannelMapper.selectById(reqVO.getId()); // 获取最新的
assertPojoEquals(reqVO, smsChannel);
}
@Test
public void testUpdateSmsChannel_notExists() {
// 准备参数
SysSmsChannelUpdateReqVO reqVO = randomPojo(SysSmsChannelUpdateReqVO.class);
// 调用, 并断言异常
assertServiceException(() -> smsChannelService.updateSmsChannel(reqVO), SMS_CHANNEL_NOT_EXISTS);
}
@Test
public void testDeleteSmsChannel_success() {
// mock 数据
SysSmsChannelDO dbSmsChannel = randomSmsChannelDO();
smsChannelMapper.insert(dbSmsChannel);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbSmsChannel.getId();
// 调用
smsChannelService.deleteSmsChannel(id);
// 校验数据不存在了
assertNull(smsChannelMapper.selectById(id));
}
@Test
public void testDeleteSmsChannel_notExists() {
// 准备参数
Long id = randomLongId();
// 调用, 并断言异常
assertServiceException(() -> smsChannelService.deleteSmsChannel(id), SMS_CHANNEL_NOT_EXISTS);
}
@Test
public void testGetSmsChannelPage() {
// mock 数据
SysSmsChannelDO dbSmsChannel = randomPojo(SysSmsChannelDO.class, o -> { // 等会查询到
o.setSignature("芋道源码");
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCreateTime(buildTime(2020, 12, 12));
});
smsChannelMapper.insert(dbSmsChannel);
// 测试 signature 不匹配
smsChannelMapper.insert(ObjectUtils.clone(dbSmsChannel, o -> o.setSignature("源码")));
// 测试 status 不匹配
smsChannelMapper.insert(ObjectUtils.clone(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配
smsChannelMapper.insert(ObjectUtils.clone(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11))));
// 准备参数
SysSmsChannelPageReqVO reqVO = new SysSmsChannelPageReqVO();
reqVO.setSignature("芋道");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setBeginCreateTime(buildTime(2020, 12, 1));
reqVO.setEndCreateTime(buildTime(2020, 12, 24));
// 调用
PageResult<SysSmsChannelDO> pageResult = smsChannelService.getSmsChannelPage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbSmsChannel, pageResult.getList().get(0));
}
@SafeVarargs
private static SysSmsChannelDO randomSmsChannelDO(Consumer<SysSmsChannelDO>... consumers) {
Consumer<SysSmsChannelDO> consumer = (o) -> {
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
};
return randomPojo(SysSmsChannelDO.class, ArrayUtils.append(consumer, consumers));
}
}

View File

@ -19,3 +19,4 @@ DELETE FROM "sys_post";
DELETE FROM "sys_login_log"; DELETE FROM "sys_login_log";
DELETE FROM "sys_operate_log"; DELETE FROM "sys_operate_log";
DELETE FROM "sys_user"; DELETE FROM "sys_user";
DELETE FROM "sys_sms_channel";

View File

@ -47,8 +47,7 @@ CREATE TABLE IF NOT EXISTS "inf_job" (
PRIMARY KEY ("id") PRIMARY KEY ("id")
) COMMENT='定时任务表'; ) COMMENT='定时任务表';
DROP TABLE IF EXISTS "inf_job_log"; CREATE TABLE IF NOT EXISTS "inf_job_log" (
CREATE TABLE "inf_job_log" (
"id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '日志编号', "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '日志编号',
"job_id" bigint(20) NOT NULL COMMENT '任务编号', "job_id" bigint(20) NOT NULL COMMENT '任务编号',
"handler_name" varchar(64) NOT NULL COMMENT '处理器的名字', "handler_name" varchar(64) NOT NULL COMMENT '处理器的名字',
@ -192,8 +191,7 @@ CREATE TABLE IF NOT EXISTS `sys_user_session` (
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) COMMENT '用户在线 Session'; ) COMMENT '用户在线 Session';
CREATE TABLE IF NOT EXISTS "sys_post" CREATE TABLE IF NOT EXISTS "sys_post" (
(
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"code" varchar(64) NOT NULL, "code" varchar(64) NOT NULL,
"name" varchar(50) NOT NULL, "name" varchar(50) NOT NULL,
@ -208,7 +206,6 @@ CREATE TABLE IF NOT EXISTS "sys_post"
PRIMARY KEY ("id") PRIMARY KEY ("id")
) COMMENT '岗位信息表'; ) COMMENT '岗位信息表';
CREATE TABLE IF NOT EXISTS "sys_notice" ( CREATE TABLE IF NOT EXISTS "sys_notice" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"title" varchar(50) NOT NULL COMMENT '公告标题', "title" varchar(50) NOT NULL COMMENT '公告标题',
@ -223,7 +220,6 @@ CREATE TABLE IF NOT EXISTS "sys_notice" (
PRIMARY KEY("id") PRIMARY KEY("id")
) COMMENT '通知公告表'; ) COMMENT '通知公告表';
CREATE TABLE IF NOT EXISTS `sys_login_log` ( CREATE TABLE IF NOT EXISTS `sys_login_log` (
`id` bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY, `id` bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY,
`log_type` bigint(4) NOT NULL, `log_type` bigint(4) NOT NULL,
@ -240,7 +236,6 @@ CREATE TABLE IF NOT EXISTS `sys_login_log` (
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) COMMENT ='系统访问记录'; ) COMMENT ='系统访问记录';
CREATE TABLE IF NOT EXISTS `sys_operate_log` ( CREATE TABLE IF NOT EXISTS `sys_operate_log` (
`id` bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY, `id` bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY,
`trace_id` varchar(64) NOT NULL DEFAULT '', `trace_id` varchar(64) NOT NULL DEFAULT '',
@ -346,3 +341,20 @@ CREATE TABLE IF NOT EXISTS "inf_api_error_log" (
"deleted" bit not null default false, "deleted" bit not null default false,
primary key ("id") primary key ("id")
) COMMENT '系统异常日志'; ) COMMENT '系统异常日志';
CREATE TABLE IF NOT EXISTS "sys_sms_channel" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"signature" varchar(10) NOT NULL,
"code" varchar(63) NOT NULL,
"status" tinyint NOT NULL,
"remark" varchar(255) DEFAULT NULL,
"api_key" varchar(63) NOT NULL,
"api_secret" varchar(63) DEFAULT NULL,
"callback_url" varchar(255) DEFAULT NULL,
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '短信渠道';