Sfoglia il codice sorgente

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

YunaiV 4 anni fa
parent
commit
d8d458a024
22 ha cambiato i file con 520 aggiunte e 270 eliminazioni
  1. 14 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java
  2. 47 13
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java
  3. 0 58
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java
  4. 36 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelBaseVO.java
  5. 21 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelCreateReqVO.java
  6. 35 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelPageReqVO.java
  7. 26 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelRespVO.java
  8. 21 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelUpdateReqVO.java
  9. 0 44
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelCreateReqVO.java
  10. 0 21
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java
  11. 0 43
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelPageRespVO.java
  12. 0 28
      src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java
  13. 36 0
      src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsChannelConvert.java
  14. 9 7
      src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java
  15. 7 11
      src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java
  16. 1 0
      src/main/java/cn/iocoder/dashboard/modules/system/enums/dict/SysDictTypeEnum.java
  17. 45 10
      src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java
  18. 52 28
      src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java
  19. 1 0
      src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java
  20. 149 0
      src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java
  21. 1 0
      src/test/resources/sql/clean.sql
  22. 19 7
      src/test/resources/sql/create_tables.sql

+ 14 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java

@@ -1,6 +1,8 @@
 package cn.iocoder.dashboard.modules.system.controller.sms;
 
 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.sms.core.enums.SmsChannelEnum;
 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 javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
 
 @Api(tags = "短信回调")
 @RestController
@@ -32,4 +37,13 @@ public class SmsCallbackController {
         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);
+    }
+
 }

+ 47 - 13
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java

@@ -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.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.channel.SysSmsChannelCreateReqVO;
+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.service.sms.SysSmsChannelService;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
 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 javax.annotation.Resource;
+import javax.validation.Valid;
 
 import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
 
-@Api("短信 渠道/签名 API")
+@Api(tags = "短信渠道")
 @RestController
 @RequestMapping("/sms/channel")
 public class SmsChannelController {
 
     @Resource
-    private SysSmsChannelService service;
+    private SysSmsChannelService smsChannelService;
 
-    @ApiOperation("获取渠道/签名分页")
-    @GetMapping("/page")
-    public CommonResult<PageResult<SysSmsChannelDO>> getPermissionInfo(@Validated SmsChannelPageReqVO reqVO) {
-        return success(service.pageSmsChannels(reqVO));
+    @PostMapping("/create")
+    @ApiOperation("创建短信渠道")
+    @PreAuthorize("@ss.hasPermission('system:sms-channel:create')")
+    public CommonResult<Long> createSmsChannel(@Valid @RequestBody SysSmsChannelCreateReqVO createReqVO) {
+        return success(smsChannelService.createSmsChannel(createReqVO));
     }
 
-    @ApiOperation("添加消息渠道")
-    @PostMapping("/create")
-    public CommonResult<Long> add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) {
-        return success(service.createSmsChannel(reqVO));
+    @PutMapping("/update")
+    @ApiOperation("更新短信渠道")
+    @PreAuthorize("@ss.hasPermission('system:sms-channel:update')")
+    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));
     }
 
 }

+ 0 - 58
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java

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

+ 36 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelBaseVO.java

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

+ 21 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelCreateReqVO.java

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

+ 35 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelPageReqVO.java

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

+ 26 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelRespVO.java

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

+ 21 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelUpdateReqVO.java

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

+ 0 - 44
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelCreateReqVO.java

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

+ 0 - 21
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java

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

+ 0 - 43
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelPageRespVO.java

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

+ 0 - 28
src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java

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

+ 36 - 0
src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsChannelConvert.java

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

+ 9 - 7
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java

@@ -1,9 +1,9 @@
 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.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 com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
@@ -13,14 +13,16 @@ import java.util.List;
 @Mapper
 public interface SysSmsChannelMapper extends BaseMapperX<SysSmsChannelDO> {
 
-    default PageResult<SysSmsChannelDO> selectChannelPage(SmsChannelPageReqVO reqVO) {
-        return selectPage(reqVO, new LambdaQueryWrapper<SysSmsChannelDO>()
-                .like(StrUtil.isNotBlank(reqVO.getSignature()), SysSmsChannelDO::getSignature, reqVO.getSignature()));
+    default PageResult<SysSmsChannelDO> selectPage(SysSmsChannelPageReqVO reqVO) {
+        return selectPage(reqVO, new QueryWrapperX<SysSmsChannelDO>()
+                .likeIfPresent("signature", reqVO.getSignature())
+                .eqIfPresent("status", reqVO.getStatus())
+                .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
+                .orderByDesc("id"));
     }
 
     default List<SysSmsChannelDO> selectListByStatus(Integer status) {
-        return selectList(new LambdaQueryWrapper<SysSmsChannelDO>()
-                .eq(SysSmsChannelDO::getStatus, status)
+        return selectList(new LambdaQueryWrapper<SysSmsChannelDO>().eq(SysSmsChannelDO::getStatus, status)
                 .orderByAsc(SysSmsChannelDO::getId));
     }
 

+ 7 - 11
src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java

@@ -78,19 +78,15 @@ public interface SysErrorCodeConstants {
     ErrorCode FILE_UPLOAD_FAILED = new ErrorCode(1002009002, "文件上传失败");
     ErrorCode FILE_IS_EMPTY= new ErrorCode(1002009003, "文件为空");
 
+    // ========== 短信渠道 1002011000 ==========
+    ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1002011000, "短信渠道不存在");
 
-    // ========== 短信模板 1002010000 ==========
-    ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002010000, "短信模板不存在");
+    // ========== 短信模板 1002011000 ==========
+    ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002011000, "短信模板不存在");
 
-    // ========== 短信发送 1002011000 ==========
-    ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1002011000, "手机号不存在");
-    ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1002011001, "模板参数({})缺失");
+    // ========== 短信发送 1002012000 ==========
+    ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1002012000, "手机号不存在");
+    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, "参数【{}】不能为空");
 
 }

+ 1 - 0
src/main/java/cn/iocoder/dashboard/modules/system/enums/dict/SysDictTypeEnum.java

@@ -18,6 +18,7 @@ public enum SysDictTypeEnum {
     SYS_LOGIN_RESULT("sys_login_result"), // 登陆结果
     SYS_CONFIG_TYPE("sys_config_type"), // 参数配置类型
     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_JOB_STATUS("inf_job_status"), // 定时任务状态的枚举

+ 45 - 10
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java

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

+ 52 - 28
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java

@@ -4,9 +4,10 @@ import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
 import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
-import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
-import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO;
-import cn.iocoder.dashboard.modules.system.convert.sms.SmsChannelConvert;
+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.convert.sms.SysSmsChannelConvert;
 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.SysSmsChannelService;
@@ -14,8 +15,12 @@ import org.springframework.stereotype.Service;
 
 import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
+import java.util.Collection;
 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实现类
  *
@@ -29,46 +34,65 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService {
     private SmsClientFactory smsClientFactory;
 
     @Resource
-    private SysSmsChannelMapper channelMapper;
+    private SysSmsChannelMapper smsChannelMapper;
 
     @Override
     @PostConstruct
     public void initSmsClients() {
         // 查询有效渠道信息
-        List<SysSmsChannelDO> channelDOList = channelMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+        List<SysSmsChannelDO> channelDOList = smsChannelMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
         // 创建渠道 Client
-        List<SmsChannelProperties> propertiesList = SmsChannelConvert.INSTANCE.convertList(channelDOList);
+        List<SmsChannelProperties> propertiesList = SysSmsChannelConvert.INSTANCE.convertList02(channelDOList);
         propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));
     }
 
     // TODO 芋艿:刷新缓存
 
     @Override
-    public PageResult<SysSmsChannelDO> pageSmsChannels(SmsChannelPageReqVO reqVO) {
-        return channelMapper.selectChannelPage(reqVO);
+    public Long createSmsChannel(SysSmsChannelCreateReqVO createReqVO) {
+        // 插入
+        SysSmsChannelDO smsChannel = SysSmsChannelConvert.INSTANCE.convert(createReqVO);
+        smsChannelMapper.insert(smsChannel);
+        // 返回
+        return smsChannel.getId();
+    }
+
+    @Override
+    public void updateSmsChannel(SysSmsChannelUpdateReqVO updateReqVO) {
+        // 校验存在
+        this.validateSmsChannelExists(updateReqVO.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 Long createSmsChannel(SmsChannelCreateReqVO reqVO) {
-        SysSmsChannelDO channelDO = SmsChannelConvert.INSTANCE.convert(reqVO);
-        channelMapper.insert(channelDO);
-        return channelDO.getId();
+    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;
-//    }
 }

+ 1 - 0
src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java

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

+ 149 - 0
src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java

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

+ 1 - 0
src/test/resources/sql/clean.sql

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

+ 19 - 7
src/test/resources/sql/create_tables.sql

@@ -47,8 +47,7 @@ CREATE TABLE IF NOT EXISTS "inf_job" (
     PRIMARY KEY ("id")
 ) COMMENT='定时任务表';
 
-DROP TABLE IF EXISTS "inf_job_log";
-CREATE TABLE "inf_job_log" (
+CREATE TABLE IF NOT EXISTS "inf_job_log" (
     "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '日志编号',
     "job_id" bigint(20) 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`)
 ) 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,
     "code"        varchar(64) NOT NULL,
     "name"        varchar(50) NOT NULL,
@@ -208,7 +206,6 @@ CREATE TABLE IF NOT EXISTS "sys_post"
     PRIMARY KEY ("id")
 ) COMMENT '岗位信息表';
 
-
 CREATE TABLE IF NOT EXISTS "sys_notice" (
 	"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
 	"title" varchar(50) NOT NULL COMMENT '公告标题',
@@ -223,7 +220,6 @@ CREATE TABLE IF NOT EXISTS "sys_notice" (
 	PRIMARY KEY("id")
 ) COMMENT '通知公告表';
 
-
 CREATE TABLE IF NOT EXISTS `sys_login_log` (
     `id`          bigint(20)   NOT NULL GENERATED BY DEFAULT AS IDENTITY,
     `log_type`    bigint(4)    NOT NULL,
@@ -240,7 +236,6 @@ CREATE TABLE IF NOT EXISTS `sys_login_log` (
     PRIMARY KEY (`id`)
 ) COMMENT ='系统访问记录';
 
-
 CREATE TABLE IF NOT EXISTS `sys_operate_log` (
     `id`               bigint(20)    NOT NULL GENERATED BY DEFAULT AS IDENTITY,
     `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,
  primary key ("id")
 ) 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 '短信渠道';