diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
index f38ea15ec..44264322c 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
@@ -59,13 +59,6 @@
dynamic-datasource-spring-boot-starter
-
-
- com.github.ulisesbocchio
- jasypt-spring-boot-starter
- true
-
-
diff --git a/yudao-module-infra/yudao-module-infra-biz/pom.xml b/yudao-module-infra/yudao-module-infra-biz/pom.xml
index c6e61d6e8..ed8b5e2d2 100644
--- a/yudao-module-infra/yudao-module-infra-biz/pom.xml
+++ b/yudao-module-infra/yudao-module-infra-biz/pom.xml
@@ -114,10 +114,6 @@
-
- com.github.ulisesbocchio
- jasypt-spring-boot-starter
-
cn.iocoder.cloud
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/ConfigController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/ConfigController.java
new file mode 100644
index 000000000..c48a582c4
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/ConfigController.java
@@ -0,0 +1,105 @@
+package cn.iocoder.yudao.module.infra.controller.admin.config;
+
+import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.*;
+import cn.iocoder.yudao.module.infra.convert.config.ConfigConvert;
+import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO;
+import cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants;
+import cn.iocoder.yudao.module.infra.service.config.ConfigService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
+
+@Api(tags = "管理后台 - 参数配置")
+@RestController
+@RequestMapping("/infra/config")
+@Validated
+public class ConfigController {
+
+ @Resource
+ private ConfigService configService;
+
+ @PostMapping("/create")
+ @ApiOperation("创建参数配置")
+ @PreAuthorize("@ss.hasPermission('infra:config:create')")
+ public CommonResult createConfig(@Valid @RequestBody ConfigCreateReqVO reqVO) {
+ return success(configService.createConfig(reqVO));
+ }
+
+ @PutMapping("/update")
+ @ApiOperation("修改参数配置")
+ @PreAuthorize("@ss.hasPermission('infra:config:update')")
+ public CommonResult updateConfig(@Valid @RequestBody ConfigUpdateReqVO reqVO) {
+ configService.updateConfig(reqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @ApiOperation("删除参数配置")
+ @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
+ @PreAuthorize("@ss.hasPermission('infra:config:delete')")
+ public CommonResult deleteConfig(@RequestParam("id") Long id) {
+ configService.deleteConfig(id);
+ return success(true);
+ }
+
+ @GetMapping(value = "/get")
+ @ApiOperation("获得参数配置")
+ @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
+ @PreAuthorize("@ss.hasPermission('infra:config:query')")
+ public CommonResult getConfig(@RequestParam("id") Long id) {
+ return success(ConfigConvert.INSTANCE.convert(configService.getConfig(id)));
+ }
+
+ @GetMapping(value = "/get-value-by-key")
+ @ApiOperation(value = "根据参数键名查询参数值", notes = "不可见的配置,不允许返回给前端")
+ @ApiImplicitParam(name = "key", value = "参数键", required = true, example = "yunai.biz.username", dataTypeClass = String.class)
+ public CommonResult getConfigKey(@RequestParam("key") String key) {
+ ConfigDO config = configService.getConfigByKey(key);
+ if (config == null) {
+ return null;
+ }
+ if (config.getVisible()) {
+ throw ServiceExceptionUtil.exception(ErrorCodeConstants.CONFIG_GET_VALUE_ERROR_IF_VISIBLE);
+ }
+ return success(config.getValue());
+ }
+
+ @GetMapping("/page")
+ @ApiOperation("获取参数配置分页")
+ @PreAuthorize("@ss.hasPermission('infra:config:query')")
+ public CommonResult> getConfigPage(@Valid ConfigPageReqVO reqVO) {
+ PageResult page = configService.getConfigPage(reqVO);
+ return success(ConfigConvert.INSTANCE.convertPage(page));
+ }
+
+ @GetMapping("/export")
+ @ApiOperation("导出参数配置")
+ @PreAuthorize("@ss.hasPermission('infra:config:export')")
+ @OperateLog(type = EXPORT)
+ public void exportSysConfig(@Valid ConfigExportReqVO reqVO,
+ HttpServletResponse response) throws IOException {
+ List list = configService.getConfigList(reqVO);
+ // 拼接数据
+ List datas = ConfigConvert.INSTANCE.convertList(list);
+ // 输出
+ ExcelUtils.write(response, "参数配置.xls", "数据", ConfigExcelVO.class, datas);
+ }
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigBaseVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigBaseVO.java
new file mode 100644
index 000000000..774b0ac81
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigBaseVO.java
@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.infra.controller.admin.config.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+/**
+ * 参数配置 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class ConfigBaseVO {
+
+ @ApiModelProperty(value = "参数分组", required = true, example = "biz")
+ @NotEmpty(message = "参数分组不能为空")
+ @Size(max = 50, message = "参数名称不能超过50个字符")
+ private String category;
+
+ @ApiModelProperty(value = "参数名称", required = true, example = "数据库名")
+ @NotBlank(message = "参数名称不能为空")
+ @Size(max = 100, message = "参数名称不能超过100个字符")
+ private String name;
+
+ @ApiModelProperty(value = "参数键值", required = true, example = "1024")
+ @NotBlank(message = "参数键值不能为空")
+ @Size(max = 500, message = "参数键值长度不能超过500个字符")
+ private String value;
+
+ @ApiModelProperty(value = "是否敏感", required = true, example = "true")
+ @NotNull(message = "是否敏感不能为空")
+ private Boolean visible;
+
+ @ApiModelProperty(value = "备注", example = "备注一下很帅气!")
+ private String remark;
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigCreateReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigCreateReqVO.java
new file mode 100644
index 000000000..7a2118ae1
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigCreateReqVO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.infra.controller.admin.config.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+@ApiModel("管理后台 - 参数配置创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ConfigCreateReqVO extends ConfigBaseVO {
+
+ @ApiModelProperty(value = "参数键名", required = true, example = "yunai.db.username")
+ @NotBlank(message = "参数键名长度不能为空")
+ @Size(max = 100, message = "参数键名长度不能超过100个字符")
+ private String key;
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigExcelVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigExcelVO.java
new file mode 100644
index 000000000..5780b04cd
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigExcelVO.java
@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.infra.controller.admin.config.vo;
+
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.module.infra.enums.DictTypeConstants;
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 参数配置 Excel 导出响应 VO
+ */
+@Data
+public class ConfigExcelVO {
+
+ @ExcelProperty("参数配置序号")
+ private Long id;
+
+ @ExcelProperty("参数键名")
+ private String key;
+
+ @ExcelProperty("参数分组")
+ private String group;
+
+ @ExcelProperty("参数名称")
+ private String name;
+
+ @ExcelProperty("参数键值")
+ private String value;
+
+ @ExcelProperty(value = "参数类型", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.CONFIG_TYPE)
+ private Integer type;
+
+ @ExcelProperty(value = "是否敏感", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.BOOLEAN_STRING)
+ private Boolean sensitive;
+
+ @ExcelProperty("备注")
+ private String remark;
+
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigExportReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigExportReqVO.java
new file mode 100644
index 000000000..7c679e2d1
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigExportReqVO.java
@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.infra.controller.admin.config.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("管理后台 - 参数配置导出 Request VO")
+@Data
+public class ConfigExportReqVO {
+
+ @ApiModelProperty(value = "参数名称", example = "模糊匹配")
+ private String name;
+
+ @ApiModelProperty(value = "参数键名", example = "yunai.db.username", notes = "模糊匹配")
+ private String key;
+
+ @ApiModelProperty(value = "参数类型", example = "1", notes = "参见 SysConfigTypeEnum 枚举")
+ private Integer type;
+
+ @ApiModelProperty(value = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigPageReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigPageReqVO.java
new file mode 100644
index 000000000..5ca206d46
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigPageReqVO.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.infra.controller.admin.config.vo;
+
+import cn.iocoder.yudao.framework.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.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("管理后台 - 参数配置分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ConfigPageReqVO extends PageParam {
+
+ @ApiModelProperty(value = "数据源名称", example = "模糊匹配")
+ private String name;
+
+ @ApiModelProperty(value = "参数键名", example = "yunai.db.username", notes = "模糊匹配")
+ private String key;
+
+ @ApiModelProperty(value = "参数类型", example = "1", notes = "参见 SysConfigTypeEnum 枚举")
+ private Integer type;
+
+ @ApiModelProperty(value = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigRespVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigRespVO.java
new file mode 100644
index 000000000..0c952eecb
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigRespVO.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.infra.controller.admin.config.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import java.time.LocalDateTime;
+
+@ApiModel("管理后台 - 参数配置信息 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ConfigRespVO extends ConfigBaseVO {
+
+ @ApiModelProperty(value = "参数配置序号", required = true, example = "1024")
+ private Long id;
+
+ @ApiModelProperty(value = "参数键名", required = true, example = "yunai.db.username")
+ @NotBlank(message = "参数键名长度不能为空")
+ @Size(max = 100, message = "参数键名长度不能超过100个字符")
+ private String key;
+
+ @ApiModelProperty(value = "参数类型", required = true, example = "1", notes = "参见 SysConfigTypeEnum 枚举")
+ private Integer type;
+
+ @ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式")
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigUpdateReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigUpdateReqVO.java
new file mode 100644
index 000000000..2335d6169
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigUpdateReqVO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.infra.controller.admin.config.vo;
+
+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 ConfigUpdateReqVO extends ConfigBaseVO {
+
+ @ApiModelProperty(value = "参数配置序号", required = true, example = "1024")
+ @NotNull(message = "参数配置编号不能为空")
+ private Long id;
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/config/ConfigConvert.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/config/ConfigConvert.java
new file mode 100644
index 000000000..94bcc0eae
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/config/ConfigConvert.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.infra.convert.config;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigCreateReqVO;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigExcelVO;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigRespVO;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigUpdateReqVO;
+import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+@Mapper
+public interface ConfigConvert {
+
+ ConfigConvert INSTANCE = Mappers.getMapper(ConfigConvert.class);
+
+ PageResult convertPage(PageResult page);
+
+ @Mapping(source = "configKey", target = "key")
+ ConfigRespVO convert(ConfigDO bean);
+
+ @Mapping(source = "key", target = "configKey")
+ ConfigDO convert(ConfigCreateReqVO bean);
+
+ ConfigDO convert(ConfigUpdateReqVO bean);
+
+ @Mapping(source = "configKey", target = "key")
+ List convertList(List list);
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/config/ConfigDO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/config/ConfigDO.java
new file mode 100644
index 000000000..03b677072
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/config/ConfigDO.java
@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.infra.dal.dataobject.config;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.infra.enums.config.ConfigTypeEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+/**
+ * 参数配置表
+ *
+ * @author 芋道源码
+ */
+@TableName("infra_config")
+@KeySequence("infra_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ConfigDO extends BaseDO {
+
+ /**
+ * 参数主键
+ */
+ @TableId
+ private Long id;
+ /**
+ * 参数分类
+ */
+ private String category;
+ /**
+ * 参数名称
+ */
+ private String name;
+ /**
+ * 参数键名
+ *
+ * 支持多 DB 类型时,无法直接使用 key + @TableField("config_key") 来实现转换,原因是 "config_key" AS key 而存在报错
+ */
+ private String configKey;
+ /**
+ * 参数键值
+ */
+ private String value;
+ /**
+ * 参数类型
+ *
+ * 枚举 {@link ConfigTypeEnum}
+ */
+ private Integer type;
+ /**
+ * 是否可见
+ *
+ * 不可见的参数,一般是敏感参数,前端不可获取
+ */
+ private Boolean visible;
+ /**
+ * 备注
+ */
+ private String remark;
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/config/ConfigMapper.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/config/ConfigMapper.java
new file mode 100644
index 000000000..49eea5517
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/config/ConfigMapper.java
@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.infra.dal.mysql.config;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigExportReqVO;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigPageReqVO;
+import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface ConfigMapper extends BaseMapperX {
+
+ default ConfigDO selectByKey(String key) {
+ return selectOne(ConfigDO::getConfigKey, key);
+ }
+
+ default PageResult selectPage(ConfigPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .likeIfPresent(ConfigDO::getName, reqVO.getName())
+ .likeIfPresent(ConfigDO::getConfigKey, reqVO.getKey())
+ .eqIfPresent(ConfigDO::getType, reqVO.getType())
+ .betweenIfPresent(ConfigDO::getCreateTime, reqVO.getCreateTime()));
+ }
+
+ default List selectList(ConfigExportReqVO reqVO) {
+ return selectList(new LambdaQueryWrapperX()
+ .likeIfPresent(ConfigDO::getName, reqVO.getName())
+ .likeIfPresent(ConfigDO::getConfigKey, reqVO.getKey())
+ .eqIfPresent(ConfigDO::getType, reqVO.getType())
+ .betweenIfPresent(ConfigDO::getCreateTime, reqVO.getCreateTime()));
+ }
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/config/ConfigTypeEnum.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/config/ConfigTypeEnum.java
new file mode 100644
index 000000000..15c20152f
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/config/ConfigTypeEnum.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.infra.enums.config;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum ConfigTypeEnum {
+
+ /**
+ * 系统配置
+ */
+ SYSTEM(1),
+ /**
+ * 自定义配置
+ */
+ CUSTOM(2);
+
+ private final Integer type;
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/config/ConfigService.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/config/ConfigService.java
new file mode 100644
index 000000000..abd82e54a
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/config/ConfigService.java
@@ -0,0 +1,75 @@
+package cn.iocoder.yudao.module.infra.service.config;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigCreateReqVO;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigExportReqVO;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigPageReqVO;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigUpdateReqVO;
+import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 参数配置 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface ConfigService {
+
+ /**
+ * 创建参数配置
+ *
+ * @param reqVO 创建信息
+ * @return 配置编号
+ */
+ Long createConfig(@Valid ConfigCreateReqVO reqVO);
+
+ /**
+ * 更新参数配置
+ *
+ * @param reqVO 更新信息
+ */
+ void updateConfig(@Valid ConfigUpdateReqVO reqVO);
+
+ /**
+ * 删除参数配置
+ *
+ * @param id 配置编号
+ */
+ void deleteConfig(Long id);
+
+ /**
+ * 获得参数配置
+ *
+ * @param id 配置编号
+ * @return 参数配置
+ */
+ ConfigDO getConfig(Long id);
+
+ /**
+ * 根据参数键,获得参数配置
+ *
+ * @param key 配置键
+ * @return 参数配置
+ */
+ ConfigDO getConfigByKey(String key);
+
+ /**
+ * 获得参数配置分页列表
+ *
+ * @param reqVO 分页条件
+ * @return 分页列表
+ */
+ PageResult getConfigPage(@Valid ConfigPageReqVO reqVO);
+
+ /**
+ * 获得参数配置列表
+ *
+ * @param reqVO 列表
+ * @return 列表
+ */
+ List getConfigList(@Valid ConfigExportReqVO reqVO);
+
+
+}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/config/ConfigServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/config/ConfigServiceImpl.java
new file mode 100644
index 000000000..5c354c989
--- /dev/null
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/config/ConfigServiceImpl.java
@@ -0,0 +1,123 @@
+package cn.iocoder.yudao.module.infra.service.config;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigCreateReqVO;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigExportReqVO;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigPageReqVO;
+import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigUpdateReqVO;
+import cn.iocoder.yudao.module.infra.convert.config.ConfigConvert;
+import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO;
+import cn.iocoder.yudao.module.infra.dal.mysql.config.ConfigMapper;
+import cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants;
+import cn.iocoder.yudao.module.infra.enums.config.ConfigTypeEnum;
+import com.google.common.annotations.VisibleForTesting;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+
+/**
+ * 参数配置 Service 实现类
+ */
+@Service
+@Slf4j
+@Validated
+public class ConfigServiceImpl implements ConfigService {
+
+ @Resource
+ private ConfigMapper configMapper;
+
+ @Override
+ public Long createConfig(ConfigCreateReqVO reqVO) {
+ // 校验正确性
+ checkCreateOrUpdate(null, reqVO.getKey());
+ // 插入参数配置
+ ConfigDO config = ConfigConvert.INSTANCE.convert(reqVO);
+ config.setType(ConfigTypeEnum.CUSTOM.getType());
+ configMapper.insert(config);
+ return config.getId();
+ }
+
+ @Override
+ public void updateConfig(ConfigUpdateReqVO reqVO) {
+ // 校验正确性
+ checkCreateOrUpdate(reqVO.getId(), null); // 不允许更新 key
+ // 更新参数配置
+ ConfigDO updateObj = ConfigConvert.INSTANCE.convert(reqVO);
+ configMapper.updateById(updateObj);;
+ }
+
+ @Override
+ public void deleteConfig(Long id) {
+ // 校验配置存在
+ ConfigDO config = checkConfigExists(id);
+ // 内置配置,不允许删除
+ if (ConfigTypeEnum.SYSTEM.getType().equals(config.getType())) {
+ throw exception(ErrorCodeConstants.CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE);
+ }
+ // 删除
+ configMapper.deleteById(id);
+ }
+
+ @Override
+ public ConfigDO getConfig(Long id) {
+ return configMapper.selectById(id);
+ }
+
+ @Override
+ public ConfigDO getConfigByKey(String key) {
+ return configMapper.selectByKey(key);
+ }
+
+ @Override
+ public PageResult getConfigPage(ConfigPageReqVO reqVO) {
+ return configMapper.selectPage(reqVO);
+ }
+
+ @Override
+ public List getConfigList(ConfigExportReqVO reqVO) {
+ return configMapper.selectList(reqVO);
+ }
+
+ private void checkCreateOrUpdate(Long id, String key) {
+ // 校验自己存在
+ checkConfigExists(id);
+ // 校验参数配置 key 的唯一性
+ if (StrUtil.isNotEmpty(key)) {
+ checkConfigKeyUnique(id, key);
+ }
+ }
+
+ @VisibleForTesting
+ public ConfigDO checkConfigExists(Long id) {
+ if (id == null) {
+ return null;
+ }
+ ConfigDO config = configMapper.selectById(id);
+ if (config == null) {
+ throw exception(ErrorCodeConstants.CONFIG_NOT_EXISTS);
+ }
+ return config;
+ }
+
+ @VisibleForTesting
+ public void checkConfigKeyUnique(Long id, String key) {
+ ConfigDO config = configMapper.selectByKey(key);
+ if (config == null) {
+ return;
+ }
+ // 如果 id 为空,说明不用比较是否为相同 id 的参数配置
+ if (id == null) {
+ throw exception(ErrorCodeConstants.CONFIG_KEY_DUPLICATE);
+ }
+ if (!config.getId().equals(id)) {
+ throw exception(ErrorCodeConstants.CONFIG_KEY_DUPLICATE);
+ }
+ }
+
+}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/application.yaml b/yudao-module-system/yudao-module-system-biz/src/main/resources/application.yaml
index 72b04a061..9a6d513d9 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/resources/application.yaml
+++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/application.yaml
@@ -125,7 +125,7 @@ yudao:
version: ${yudao.info.version}
base-package: ${yudao.info.base-package}
captcha:
- enable: true # 验证码的开关,默认为 true;注意,优先读取数据库 infra_config 的 yudao.captcha.enable,所以请从数据库修改,可能需要重启项目
+ enable: true # 验证码的开关,默认为 true;
error-code: # 错误码相关配置项
constants-class-list:
- cn.iocoder.yudao.module.system.enums.ErrorCodeConstants