From 7ce7baa2d2207657192b93845969ae200ee89f91 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 27 Apr 2022 23:15:43 +0800 Subject: [PATCH] 增加数据源管理 --- yudao-dependencies/pom.xml | 7 +++++++ yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/DatabaseUtils.java | 29 +++++++++++++++++++++++++++++ yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java | 4 ++++ yudao-module-infra/yudao-module-infra-biz/pom.xml | 5 +++++ yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DataSourceConfigController.java | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigBaseVO.java | 27 +++++++++++++++++++++++++++ yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigCreateReqVO.java | 18 ++++++++++++++++++ yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigRespVO.java | 19 +++++++++++++++++++ yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigUpdateReqVO.java | 22 ++++++++++++++++++++++ yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/doc/DbDocController.java | 157 ------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/db/DataSourceConfigConvert.java | 30 ++++++++++++++++++++++++++++++ yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java | 38 ++++++++++++++++++++++++++++++++++++++ yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DataSourceConfigMapper.java | 14 ++++++++++++++ yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigService.java | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql | 1 + yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql | 14 ++++++++++++++ yudao-module-member/yudao-module-member-biz/pom.xml | 2 +- yudao-server/src/main/resources/application-dev.yaml | 4 ++++ yudao-server/src/main/resources/application-local.yaml | 4 ++++ yudao-server/src/main/resources/application.yaml | 1 + yudao-ui-admin/src/api/infra/dataSourceConfig.js | 43 +++++++++++++++++++++++++++++++++++++++++++ yudao-ui-admin/src/views/infra/dataSourceConfig/index.vue | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 25 files changed, 949 insertions(+), 158 deletions(-) create mode 100644 yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/DatabaseUtils.java create mode 100755 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DataSourceConfigController.java create mode 100644 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java create mode 100755 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigBaseVO.java create mode 100755 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigCreateReqVO.java create mode 100755 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigRespVO.java create mode 100755 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigUpdateReqVO.java delete mode 100644 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/doc/DbDocController.java create mode 100755 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/db/DataSourceConfigConvert.java create mode 100644 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java create mode 100755 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DataSourceConfigMapper.java create mode 100755 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigService.java create mode 100755 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java create mode 100755 yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java create mode 100755 yudao-ui-admin/src/api/infra/dataSourceConfig.js create mode 100755 yudao-ui-admin/src/views/infra/dataSourceConfig/index.vue diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 1c871cf..14a4b1d 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -45,6 +45,7 @@ 7.1.0.M6 6.7.0 + 3.0.4 1.18.20 1.4.1.Final 5.6.1 @@ -429,6 +430,12 @@ + com.github.ulisesbocchio + jasypt-spring-boot-starter + ${jasypt-spring-boot-starter.version} + + + cn.iocoder.boot yudao-spring-boot-starter-excel ${revision} diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/DatabaseUtils.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/DatabaseUtils.java new file mode 100644 index 0000000..b282656 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/DatabaseUtils.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.framework.mybatis.core.util; + +import java.sql.Connection; +import java.sql.DriverManager; + +/** + * 数据库工具类 + * + * @author 芋道源码 + */ +public class DatabaseUtils { + + /** + * 判断连接是否正确 + * + * @param url 数据源连接 + * @param username 账号 + * @param password 密码 + * @return 是否正确 + */ + public static boolean isConnectionOK(String url, String username, String password) { + try (Connection ignored = DriverManager.getConnection(url, username, password)) { + return true; + } catch (Exception ex) { + return false; + } + } + +} diff --git a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java index 1528955..8dd1a99 100644 --- a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java +++ b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java @@ -49,4 +49,8 @@ public interface ErrorCodeConstants { ErrorCode FILE_CONFIG_NOT_EXISTS = new ErrorCode(1001006000, "文件配置不存在"); ErrorCode FILE_CONFIG_DELETE_FAIL_MASTER = new ErrorCode(1001006001, "该文件配置不允许删除,原因:它是主配置,删除会导致无法上传文件"); + // ========== 数据源配置 1001007000 ========== + ErrorCode DATA_SOURCE_CONFIG_NOT_EXISTS = new ErrorCode(1001007000, "数据源配置不存在"); + ErrorCode DATA_SOURCE_CONFIG_NOT_OK = new ErrorCode(1001007001, "数据源配置不正确,无法进行连接"); + } diff --git a/yudao-module-infra/yudao-module-infra-biz/pom.xml b/yudao-module-infra/yudao-module-infra-biz/pom.xml index 5c4c16d..cd30fd2 100644 --- a/yudao-module-infra/yudao-module-infra-biz/pom.xml +++ b/yudao-module-infra/yudao-module-infra-biz/pom.xml @@ -80,6 +80,11 @@ + com.github.ulisesbocchio + jasypt-spring-boot-starter + + + cn.iocoder.boot yudao-spring-boot-starter-excel diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DataSourceConfigController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DataSourceConfigController.java new file mode 100755 index 0000000..6b535ae --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DataSourceConfigController.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.infra.controller.admin.db; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigCreateReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigUpdateReqVO; +import cn.iocoder.yudao.module.infra.convert.db.DataSourceConfigConvert; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; +import cn.iocoder.yudao.module.infra.service.db.DataSourceConfigService; +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.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - 数据源配置") +@RestController +@RequestMapping("/infra/data-source-config") +@Validated +public class DataSourceConfigController { + + @Resource + private DataSourceConfigService dataSourceConfigService; + + @PostMapping("/create") + @ApiOperation("创建数据源配置") + @PreAuthorize("@ss.hasPermission('infra:data-source-config:create')") + public CommonResult createDataSourceConfig(@Valid @RequestBody DataSourceConfigCreateReqVO createReqVO) { + return success(dataSourceConfigService.createDataSourceConfig(createReqVO)); + } + + @PutMapping("/update") + @ApiOperation("更新数据源配置") + @PreAuthorize("@ss.hasPermission('infra:data-source-config:update')") + public CommonResult updateDataSourceConfig(@Valid @RequestBody DataSourceConfigUpdateReqVO updateReqVO) { + dataSourceConfigService.updateDataSourceConfig(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除数据源配置") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('infra:data-source-config:delete')") + public CommonResult deleteDataSourceConfig(@RequestParam("id") Long id) { + dataSourceConfigService.deleteDataSourceConfig(id); + return success(true); + } + + @GetMapping("/get") + @ApiOperation("获得数据源配置") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('infra:data-source-config:query')") + public CommonResult getDataSourceConfig(@RequestParam("id") Long id) { + DataSourceConfigDO dataSourceConfig = dataSourceConfigService.getDataSourceConfig(id); + return success(DataSourceConfigConvert.INSTANCE.convert(dataSourceConfig)); + } + + @GetMapping("/list") + @ApiOperation("获得数据源配置列表") + @PreAuthorize("@ss.hasPermission('infra:data-source-config:query')") + public CommonResult> getDataSourceConfigList() { + List list = dataSourceConfigService.getDataSourceConfigList(); + return success(DataSourceConfigConvert.INSTANCE.convertList(list)); + } + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java new file mode 100644 index 0000000..eb35d45 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java @@ -0,0 +1,157 @@ +package cn.iocoder.yudao.module.infra.controller.admin.db; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.smallbun.screw.core.Configuration; +import cn.smallbun.screw.core.engine.EngineConfig; +import cn.smallbun.screw.core.engine.EngineFileType; +import cn.smallbun.screw.core.engine.EngineTemplateType; +import cn.smallbun.screw.core.execute.DocumentationExecute; +import cn.smallbun.screw.core.process.ProcessConfig; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; + +@Api(tags = "管理后台 - 数据库文档") +@RestController +@RequestMapping("/infra/db-doc") +public class DatabaseDocController { + + @Resource + private DynamicDataSourceProperties dynamicDataSourceProperties; + + private static final String FILE_OUTPUT_DIR = System.getProperty("java.io.tmpdir") + File.separator + + "db-doc"; + private static final String DOC_FILE_NAME = "数据库文档"; + private static final String DOC_VERSION = "1.0.0"; + private static final String DOC_DESCRIPTION = "文档描述"; + + @GetMapping("/export-html") + @ApiOperation("导出 html 格式的数据文档") + @ApiImplicitParam(name = "deleteFile", value = "是否删除在服务器本地生成的数据库文档", example = "true", + dataTypeClass = Boolean.class) + public void exportHtml(@RequestParam(defaultValue = "true") Boolean deleteFile, + HttpServletResponse response) throws IOException { + doExportFile(EngineFileType.HTML, deleteFile, response); + } + + @GetMapping("/export-word") + @ApiOperation("导出 word 格式的数据文档") + @ApiImplicitParam(name = "deleteFile", value = "是否删除在服务器本地生成的数据库文档", example = "true", + dataTypeClass = Boolean.class) + public void exportWord(@RequestParam(defaultValue = "true") Boolean deleteFile, + HttpServletResponse response) throws IOException { + doExportFile(EngineFileType.WORD, deleteFile, response); + } + + @GetMapping("/export-markdown") + @ApiOperation("导出 markdown 格式的数据文档") + @ApiImplicitParam(name = "deleteFile", value = "是否删除在服务器本地生成的数据库文档", example = "true", + dataTypeClass = Boolean.class) + public void exportMarkdown(@RequestParam(defaultValue = "true") Boolean deleteFile, + HttpServletResponse response) throws IOException { + doExportFile(EngineFileType.MD, deleteFile, response); + } + + private void doExportFile(EngineFileType fileOutputType, Boolean deleteFile, + HttpServletResponse response) throws IOException { + String docFileName = DOC_FILE_NAME + "_" + IdUtil.fastSimpleUUID(); + String filePath = doExportFile(fileOutputType, docFileName); + String downloadFileName = DOC_FILE_NAME + fileOutputType.getFileSuffix(); //下载后的文件名 + try { + // 读取,返回 + ServletUtils.writeAttachment(response, downloadFileName, FileUtil.readBytes(filePath)); + } finally { + handleDeleteFile(deleteFile, filePath); + } + } + + /** + * 输出文件,返回文件路径 + * + * @param fileOutputType 文件类型 + * @param fileName 文件名, 无需 ".docx" 等文件后缀 + * @return 生成的文件所在路径 + */ + private String doExportFile(EngineFileType fileOutputType, String fileName) { + try (HikariDataSource dataSource = buildDataSource()) { + // 创建 screw 的配置 + Configuration config = Configuration.builder() + .version(DOC_VERSION) // 版本 + .description(DOC_DESCRIPTION) // 描述 + .dataSource(dataSource) // 数据源 + .engineConfig(buildEngineConfig(fileOutputType, fileName)) // 引擎配置 + .produceConfig(buildProcessConfig()) // 处理配置 + .build(); + + // 执行 screw,生成数据库文档 + new DocumentationExecute(config).execute(); + + return FILE_OUTPUT_DIR + File.separator + fileName + fileOutputType.getFileSuffix(); + } + } + + private void handleDeleteFile(Boolean deleteFile, String filePath) { + if (!deleteFile) { + return; + } + FileUtil.del(filePath); + } + + /** + * 创建数据源 + */ + // TODO 芋艿:screw 暂时不支持 druid,尴尬 + private HikariDataSource buildDataSource() { + // 获得 DataSource 数据源,目前只支持首个 + String primary = dynamicDataSourceProperties.getPrimary(); + DataSourceProperty dataSourceProperty = dynamicDataSourceProperties.getDatasource().get(primary); + // 创建 HikariConfig 配置类 + HikariConfig hikariConfig = new HikariConfig(); + hikariConfig.setJdbcUrl(dataSourceProperty.getUrl()); + hikariConfig.setUsername(dataSourceProperty.getUsername()); + hikariConfig.setPassword(dataSourceProperty.getPassword()); + hikariConfig.addDataSourceProperty("useInformationSchema", "true"); // 设置可以获取 tables remarks 信息 + // 创建数据源 + return new HikariDataSource(hikariConfig); + } + + /** + * 创建 screw 的引擎配置 + */ + private static EngineConfig buildEngineConfig(EngineFileType fileOutputType, String docFileName) { + return EngineConfig.builder() + .fileOutputDir(FILE_OUTPUT_DIR) // 生成文件路径 + .openOutputDir(false) // 打开目录 + .fileType(fileOutputType) // 文件类型 + .produceType(EngineTemplateType.velocity) // 文件类型 + .fileName(docFileName) // 自定义文件名称 + .build(); + } + + /** + * 创建 screw 的处理配置,一般可忽略 + * 指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时,将生成指定表,其余表不生成、并跳过忽略表配置 + */ + private static ProcessConfig buildProcessConfig() { + return ProcessConfig.builder() + .ignoreTablePrefix(Arrays.asList("QRTZ_", "ACT_")) // 忽略表前缀 + .build(); + } + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigBaseVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigBaseVO.java new file mode 100755 index 0000000..ae3d97d --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigBaseVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.infra.controller.admin.db.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; + +/** +* 数据源配置 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class DataSourceConfigBaseVO { + + @ApiModelProperty(value = "参数名称", required = true, example = "test") + @NotNull(message = "参数名称不能为空") + private String name; + + @ApiModelProperty(value = "数据源连接", required = true, example = "jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro") + @NotNull(message = "数据源连接不能为空") + private String url; + + @ApiModelProperty(value = "用户名", required = true, example = "root") + @NotNull(message = "用户名不能为空") + private String username; + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigCreateReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigCreateReqVO.java new file mode 100755 index 0000000..13085f9 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigCreateReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.infra.controller.admin.db.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; + +@ApiModel("管理后台 - 数据源配置创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DataSourceConfigCreateReqVO extends DataSourceConfigBaseVO { + + @ApiModelProperty(value = "密码", required = true, example = "123456") + @NotNull(message = "密码不能为空") + private String password; + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigRespVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigRespVO.java new file mode 100755 index 0000000..af63aa0 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.infra.controller.admin.db.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; + +@ApiModel("管理后台 - 数据源配置 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DataSourceConfigRespVO extends DataSourceConfigBaseVO { + + @ApiModelProperty(value = "主键编号", required = true, example = "1024") + private Integer id; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigUpdateReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigUpdateReqVO.java new file mode 100755 index 0000000..134f3e9 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigUpdateReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.infra.controller.admin.db.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; + +@ApiModel("管理后台 - 数据源配置更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DataSourceConfigUpdateReqVO extends DataSourceConfigBaseVO { + + @ApiModelProperty(value = "主键编号", required = true, example = "1024") + @NotNull(message = "主键编号不能为空") + private Long id; + + @ApiModelProperty(value = "密码", required = true, example = "123456") + @NotNull(message = "密码不能为空") + private String password; + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/doc/DbDocController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/doc/DbDocController.java deleted file mode 100644 index 83d9db7..0000000 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/doc/DbDocController.java +++ /dev/null @@ -1,157 +0,0 @@ -package cn.iocoder.yudao.module.infra.controller.admin.doc; - -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.util.IdUtil; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.smallbun.screw.core.Configuration; -import cn.smallbun.screw.core.engine.EngineConfig; -import cn.smallbun.screw.core.engine.EngineFileType; -import cn.smallbun.screw.core.engine.EngineTemplateType; -import cn.smallbun.screw.core.execute.DocumentationExecute; -import cn.smallbun.screw.core.process.ProcessConfig; -import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; -import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiOperation; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.IOException; -import java.util.Arrays; - -@Api(tags = "管理后台 - 数据库文档") -@RestController -@RequestMapping("/infra/db-doc") -public class DbDocController { - - @Resource - private DynamicDataSourceProperties dynamicDataSourceProperties; - - private static final String FILE_OUTPUT_DIR = System.getProperty("java.io.tmpdir") + File.separator - + "db-doc"; - private static final String DOC_FILE_NAME = "数据库文档"; - private static final String DOC_VERSION = "1.0.0"; - private static final String DOC_DESCRIPTION = "文档描述"; - - @GetMapping("/export-html") - @ApiOperation("导出 html 格式的数据文档") - @ApiImplicitParam(name = "deleteFile", value = "是否删除在服务器本地生成的数据库文档", example = "true", - dataTypeClass = Boolean.class) - public void exportHtml(@RequestParam(defaultValue = "true") Boolean deleteFile, - HttpServletResponse response) throws IOException { - doExportFile(EngineFileType.HTML, deleteFile, response); - } - - @GetMapping("/export-word") - @ApiOperation("导出 word 格式的数据文档") - @ApiImplicitParam(name = "deleteFile", value = "是否删除在服务器本地生成的数据库文档", example = "true", - dataTypeClass = Boolean.class) - public void exportWord(@RequestParam(defaultValue = "true") Boolean deleteFile, - HttpServletResponse response) throws IOException { - doExportFile(EngineFileType.WORD, deleteFile, response); - } - - @GetMapping("/export-markdown") - @ApiOperation("导出 markdown 格式的数据文档") - @ApiImplicitParam(name = "deleteFile", value = "是否删除在服务器本地生成的数据库文档", example = "true", - dataTypeClass = Boolean.class) - public void exportMarkdown(@RequestParam(defaultValue = "true") Boolean deleteFile, - HttpServletResponse response) throws IOException { - doExportFile(EngineFileType.MD, deleteFile, response); - } - - private void doExportFile(EngineFileType fileOutputType, Boolean deleteFile, - HttpServletResponse response) throws IOException { - String docFileName = DOC_FILE_NAME + "_" + IdUtil.fastSimpleUUID(); - String filePath = doExportFile(fileOutputType, docFileName); - String downloadFileName = DOC_FILE_NAME + fileOutputType.getFileSuffix(); //下载后的文件名 - try { - // 读取,返回 - ServletUtils.writeAttachment(response, downloadFileName, FileUtil.readBytes(filePath)); - } finally { - handleDeleteFile(deleteFile, filePath); - } - } - - /** - * 输出文件,返回文件路径 - * - * @param fileOutputType 文件类型 - * @param fileName 文件名, 无需 ".docx" 等文件后缀 - * @return 生成的文件所在路径 - */ - private String doExportFile(EngineFileType fileOutputType, String fileName) { - try (HikariDataSource dataSource = buildDataSource()) { - // 创建 screw 的配置 - Configuration config = Configuration.builder() - .version(DOC_VERSION) // 版本 - .description(DOC_DESCRIPTION) // 描述 - .dataSource(dataSource) // 数据源 - .engineConfig(buildEngineConfig(fileOutputType, fileName)) // 引擎配置 - .produceConfig(buildProcessConfig()) // 处理配置 - .build(); - - // 执行 screw,生成数据库文档 - new DocumentationExecute(config).execute(); - - return FILE_OUTPUT_DIR + File.separator + fileName + fileOutputType.getFileSuffix(); - } - } - - private void handleDeleteFile(Boolean deleteFile, String filePath) { - if (!deleteFile) { - return; - } - FileUtil.del(filePath); - } - - /** - * 创建数据源 - */ - // TODO 芋艿:screw 暂时不支持 druid,尴尬 - private HikariDataSource buildDataSource() { - // 获得 DataSource 数据源,目前只支持首个 - String primary = dynamicDataSourceProperties.getPrimary(); - DataSourceProperty dataSourceProperty = dynamicDataSourceProperties.getDatasource().get(primary); - // 创建 HikariConfig 配置类 - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl(dataSourceProperty.getUrl()); - hikariConfig.setUsername(dataSourceProperty.getUsername()); - hikariConfig.setPassword(dataSourceProperty.getPassword()); - hikariConfig.addDataSourceProperty("useInformationSchema", "true"); // 设置可以获取 tables remarks 信息 - // 创建数据源 - return new HikariDataSource(hikariConfig); - } - - /** - * 创建 screw 的引擎配置 - */ - private static EngineConfig buildEngineConfig(EngineFileType fileOutputType, String docFileName) { - return EngineConfig.builder() - .fileOutputDir(FILE_OUTPUT_DIR) // 生成文件路径 - .openOutputDir(false) // 打开目录 - .fileType(fileOutputType) // 文件类型 - .produceType(EngineTemplateType.velocity) // 文件类型 - .fileName(docFileName) // 自定义文件名称 - .build(); - } - - /** - * 创建 screw 的处理配置,一般可忽略 - * 指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时,将生成指定表,其余表不生成、并跳过忽略表配置 - */ - private static ProcessConfig buildProcessConfig() { - return ProcessConfig.builder() - .ignoreTablePrefix(Arrays.asList("QRTZ_", "ACT_")) // 忽略表前缀 - .build(); - } - -} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/db/DataSourceConfigConvert.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/db/DataSourceConfigConvert.java new file mode 100755 index 0000000..d81d85c --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/db/DataSourceConfigConvert.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.convert.db; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; + +/** + * 数据源配置 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface DataSourceConfigConvert { + + DataSourceConfigConvert INSTANCE = Mappers.getMapper(DataSourceConfigConvert.class); + + DataSourceConfigDO convert(DataSourceConfigCreateReqVO bean); + + DataSourceConfigDO convert(DataSourceConfigUpdateReqVO bean); + + DataSourceConfigRespVO convert(DataSourceConfigDO bean); + + List convertList(List list); + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java new file mode 100644 index 0000000..6508d1d --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.db; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 数据源配置 + * + * @author 芋道源码 + */ +@TableName("infra_data_source_config") +@Data +public class DataSourceConfigDO extends BaseDO { + + /** + * 主键编号 + */ + private Long id; + /** + * 连接名 + */ + private String name; + + /** + * 数据源连接 + */ + private String url; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DataSourceConfigMapper.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DataSourceConfigMapper.java new file mode 100755 index 0000000..5ad8be4 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DataSourceConfigMapper.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.db; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 数据源配置 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface DataSourceConfigMapper extends BaseMapperX { +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigService.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigService.java new file mode 100755 index 0000000..b5e9e21 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigService.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.infra.service.db; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigCreateReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigUpdateReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; +import org.w3c.dom.stylesheets.LinkStyle; + +import javax.validation.Valid; +import java.util.List; + +/** + * 数据源配置 Service 接口 + * + * @author 芋道源码 + */ +public interface DataSourceConfigService { + + /** + * 创建数据源配置 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDataSourceConfig(@Valid DataSourceConfigCreateReqVO createReqVO); + + /** + * 更新数据源配置 + * + * @param updateReqVO 更新信息 + */ + void updateDataSourceConfig(@Valid DataSourceConfigUpdateReqVO updateReqVO); + + /** + * 删除数据源配置 + * + * @param id 编号 + */ + void deleteDataSourceConfig(Long id); + + /** + * 获得数据源配置 + * + * @param id 编号 + * @return 数据源配置 + */ + DataSourceConfigDO getDataSourceConfig(Long id); + + /** + * 获得数据源配置列表 + * + * @return 数据源配置列表 + */ + List getDataSourceConfigList(); + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java new file mode 100755 index 0000000..e2f1a65 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.infra.service.db; + +import cn.hutool.db.DbUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.util.DatabaseUtils; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigCreateReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigUpdateReqVO; +import cn.iocoder.yudao.module.infra.convert.db.DataSourceConfigConvert; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; +import cn.iocoder.yudao.module.infra.dal.mysql.db.DataSourceConfigMapper; +import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils; +import org.jasypt.encryption.StringEncryptor; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import java.sql.Connection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_EXISTS; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_OK; + +/** + * 数据源配置 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class DataSourceConfigServiceImpl implements DataSourceConfigService { + + @Resource + private DataSourceConfigMapper dataSourceConfigMapper; + + @Resource + private StringEncryptor stringEncryptor; + + @Override + public Long createDataSourceConfig(DataSourceConfigCreateReqVO createReqVO) { + DataSourceConfigDO dataSourceConfig = DataSourceConfigConvert.INSTANCE.convert(createReqVO); + checkConnectionOK(dataSourceConfig); + + // 插入 + dataSourceConfig.setPassword(stringEncryptor.encrypt(createReqVO.getPassword())); + dataSourceConfigMapper.insert(dataSourceConfig); + // 返回 + return dataSourceConfig.getId(); + } + + @Override + public void updateDataSourceConfig(DataSourceConfigUpdateReqVO updateReqVO) { + // 校验存在 + validateDataSourceConfigExists(updateReqVO.getId()); + DataSourceConfigDO updateObj = DataSourceConfigConvert.INSTANCE.convert(updateReqVO); + checkConnectionOK(updateObj); + + // 更新 + updateObj.setPassword(stringEncryptor.encrypt(updateObj.getPassword())); + dataSourceConfigMapper.updateById(updateObj); + } + + @Override + public void deleteDataSourceConfig(Long id) { + // 校验存在 + validateDataSourceConfigExists(id); + // 删除 + dataSourceConfigMapper.deleteById(id); + } + + private void validateDataSourceConfigExists(Long id) { + if (dataSourceConfigMapper.selectById(id) == null) { + throw exception(DATA_SOURCE_CONFIG_NOT_EXISTS); + } + } + + @Override + public DataSourceConfigDO getDataSourceConfig(Long id) { + DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(id); + dataSourceConfig.setPassword(stringEncryptor.decrypt(dataSourceConfig.getPassword())); + return dataSourceConfig; + } + + @Override + public List getDataSourceConfigList() { + return dataSourceConfigMapper.selectList(); + } + + private void checkConnectionOK(DataSourceConfigDO config) { + boolean success = DatabaseUtils.isConnectionOK(config.getUrl(), config.getUsername(), config.getPassword()); + if (!success) { + throw exception(DATA_SOURCE_CONFIG_NOT_OK); + } + } + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java new file mode 100755 index 0000000..5c51b19 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java @@ -0,0 +1,119 @@ +package cn.iocoder.yudao.module.infra.service.db; + +import cn.iocoder.yudao.framework.mybatis.core.util.DatabaseUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigCreateReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigUpdateReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; +import cn.iocoder.yudao.module.infra.dal.mysql.db.DataSourceConfigMapper; +import org.jasypt.encryption.StringEncryptor; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link DataSourceConfigServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(DataSourceConfigServiceImpl.class) +public class DataSourceConfigServiceImplTest extends BaseDbUnitTest { + + @Resource + private DataSourceConfigServiceImpl dataSourceConfigService; + + @Resource + private DataSourceConfigMapper dataSourceConfigMapper; + + @MockBean + private StringEncryptor stringEncryptor; + + @Test + public void testCreateDataSourceConfig_success() { + try (MockedStatic databaseUtilsMock = mockStatic(DatabaseUtils.class)) { + // 准备参数 + DataSourceConfigCreateReqVO reqVO = randomPojo(DataSourceConfigCreateReqVO.class); + // mock 方法 + when(stringEncryptor.encrypt(eq(reqVO.getPassword()))).thenReturn("123456"); + databaseUtilsMock.when(() -> DatabaseUtils.isConnectionOK(eq(reqVO.getUrl()), + eq(reqVO.getUsername()), eq(reqVO.getPassword()))).thenReturn(true); + + // 调用 + Long dataSourceConfigId = dataSourceConfigService.createDataSourceConfig(reqVO); + // 断言 + assertNotNull(dataSourceConfigId); + // 校验记录的属性是否正确 + DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(dataSourceConfigId); + assertPojoEquals(reqVO, dataSourceConfig, "password"); + assertEquals("123456", dataSourceConfig.getPassword()); + } + } + + @Test + public void testUpdateDataSourceConfig_success() { + try (MockedStatic databaseUtilsMock = mockStatic(DatabaseUtils.class)) { + // mock 数据 + DataSourceConfigDO dbDataSourceConfig = randomPojo(DataSourceConfigDO.class); + dataSourceConfigMapper.insert(dbDataSourceConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + DataSourceConfigUpdateReqVO reqVO = randomPojo(DataSourceConfigUpdateReqVO.class, o -> { + o.setId(dbDataSourceConfig.getId()); // 设置更新的 ID + }); + // mock 方法 + when(stringEncryptor.encrypt(eq(reqVO.getPassword()))).thenReturn("123456"); + databaseUtilsMock.when(() -> DatabaseUtils.isConnectionOK(eq(reqVO.getUrl()), + eq(reqVO.getUsername()), eq(reqVO.getPassword()))).thenReturn(true); + + // 调用 + dataSourceConfigService.updateDataSourceConfig(reqVO); + // 校验是否更新正确 + DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, dataSourceConfig, "password"); + assertEquals("123456", dataSourceConfig.getPassword()); + } + } + + @Test + public void testUpdateDataSourceConfig_notExists() { + // 准备参数 + DataSourceConfigUpdateReqVO reqVO = randomPojo(DataSourceConfigUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> dataSourceConfigService.updateDataSourceConfig(reqVO), DATA_SOURCE_CONFIG_NOT_EXISTS); + } + + @Test + public void testDeleteDataSourceConfig_success() { + // mock 数据 + DataSourceConfigDO dbDataSourceConfig = randomPojo(DataSourceConfigDO.class); + dataSourceConfigMapper.insert(dbDataSourceConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDataSourceConfig.getId(); + + // 调用 + dataSourceConfigService.deleteDataSourceConfig(id); + // 校验数据不存在了 + assertNull(dataSourceConfigMapper.selectById(id)); + } + + @Test + public void testDeleteDataSourceConfig_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> dataSourceConfigService.deleteDataSourceConfig(id), DATA_SOURCE_CONFIG_NOT_EXISTS); + } + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql index cc83168..eb05d3d 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql @@ -9,3 +9,4 @@ DELETE FROM "infra_file"; DELETE FROM "infra_api_error_log"; DELETE FROM "infra_test_demo"; DELETE FROM "infra_file_config"; +DELETE FROM "infra_data_source_config"; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql index 3c86102..53d8594 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql @@ -168,3 +168,17 @@ CREATE TABLE IF NOT EXISTS "infra_test_demo" ( "deleted" bit NOT NULL DEFAULT FALSE, PRIMARY KEY ("id") ) COMMENT '字典类型表'; + +CREATE TABLE IF NOT EXISTS "infra_data_source_config" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(100) NOT NULL, + "url" varchar(1024) NOT NULL, + "username" varchar(255) NOT NULL, + "password" varchar(255) NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '数据源配置表'; diff --git a/yudao-module-member/yudao-module-member-biz/pom.xml b/yudao-module-member/yudao-module-member-biz/pom.xml index f1b48a8..11780b8 100644 --- a/yudao-module-member/yudao-module-member-biz/pom.xml +++ b/yudao-module-member/yudao-module-member-biz/pom.xml @@ -77,8 +77,8 @@ yudao-spring-boot-starter-test test - + diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index 256c5be..0c11d2f 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -61,6 +61,10 @@ spring: port: 6379 # 端口 database: 1 # 数据库索引 +jasypt: + encryptor: + password: yuanma # 加解密的秘钥 + --- #################### 定时任务相关配置 #################### # Quartz 配置项,对应 QuartzProperties 配置类 diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 0d5f777..d8ce9de 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -61,6 +61,10 @@ spring: port: 6379 # 端口 database: 0 # 数据库索引 +jasypt: + encryptor: + password: yuanma # 加解密的秘钥 + --- #################### 定时任务相关配置 #################### # Quartz 配置项,对应 QuartzProperties 配置类 diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 76d5e04..247af4d 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -123,6 +123,7 @@ yudao: - infra_job - infra_job_log - infra_job_log + - infra_data_source_config sms-code: # 短信验证码相关的配置项 expire-times: 10m send-frequency: 1m diff --git a/yudao-ui-admin/src/api/infra/dataSourceConfig.js b/yudao-ui-admin/src/api/infra/dataSourceConfig.js new file mode 100755 index 0000000..2d96b49 --- /dev/null +++ b/yudao-ui-admin/src/api/infra/dataSourceConfig.js @@ -0,0 +1,43 @@ +import request from '@/utils/request' + +// 创建数据源配置 +export function createDataSourceConfig(data) { + return request({ + url: '/infra/data-source-config/create', + method: 'post', + data: data + }) +} + +// 更新数据源配置 +export function updateDataSourceConfig(data) { + return request({ + url: '/infra/data-source-config/update', + method: 'put', + data: data + }) +} + +// 删除数据源配置 +export function deleteDataSourceConfig(id) { + return request({ + url: '/infra/data-source-config/delete?id=' + id, + method: 'delete' + }) +} + +// 获得数据源配置 +export function getDataSourceConfig(id) { + return request({ + url: '/infra/data-source-config/get?id=' + id, + method: 'get' + }) +} + +// 获得数据源配置列表 +export function getDataSourceConfigList() { + return request({ + url: '/infra/data-source-config/list', + method: 'get', + }) +} diff --git a/yudao-ui-admin/src/views/infra/dataSourceConfig/index.vue b/yudao-ui-admin/src/views/infra/dataSourceConfig/index.vue new file mode 100755 index 0000000..ddd2800 --- /dev/null +++ b/yudao-ui-admin/src/views/infra/dataSourceConfig/index.vue @@ -0,0 +1,166 @@ + + + -- libgit2 0.21.4