Commit 7ce7baa2d2207657192b93845969ae200ee89f91
1 parent
c4020779
增加数据源管理
Showing
24 changed files
with
794 additions
and
3 deletions
yudao-dependencies/pom.xml
| ... | ... | @@ -45,6 +45,7 @@ |
| 45 | 45 | <activiti.version>7.1.0.M6</activiti.version> |
| 46 | 46 | <flowable.version>6.7.0</flowable.version> |
| 47 | 47 | <!-- 工具类相关 --> |
| 48 | + <jasypt-spring-boot-starter.version>3.0.4</jasypt-spring-boot-starter.version> | |
| 48 | 49 | <lombok.version>1.18.20</lombok.version> |
| 49 | 50 | <mapstruct.version>1.4.1.Final</mapstruct.version> |
| 50 | 51 | <hutool.version>5.6.1</hutool.version> |
| ... | ... | @@ -429,6 +430,12 @@ |
| 429 | 430 | </dependency> |
| 430 | 431 | |
| 431 | 432 | <dependency> |
| 433 | + <groupId>com.github.ulisesbocchio</groupId> | |
| 434 | + <artifactId>jasypt-spring-boot-starter</artifactId> <!-- 加解密 --> | |
| 435 | + <version>${jasypt-spring-boot-starter.version}</version> | |
| 436 | + </dependency> | |
| 437 | + | |
| 438 | + <dependency> | |
| 432 | 439 | <groupId>cn.iocoder.boot</groupId> |
| 433 | 440 | <artifactId>yudao-spring-boot-starter-excel</artifactId> |
| 434 | 441 | <version>${revision}</version> | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/DatabaseUtils.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.mybatis.core.util; | |
| 2 | + | |
| 3 | +import java.sql.Connection; | |
| 4 | +import java.sql.DriverManager; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 数据库工具类 | |
| 8 | + * | |
| 9 | + * @author 芋道源码 | |
| 10 | + */ | |
| 11 | +public class DatabaseUtils { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * 判断连接是否正确 | |
| 15 | + * | |
| 16 | + * @param url 数据源连接 | |
| 17 | + * @param username 账号 | |
| 18 | + * @param password 密码 | |
| 19 | + * @return 是否正确 | |
| 20 | + */ | |
| 21 | + public static boolean isConnectionOK(String url, String username, String password) { | |
| 22 | + try (Connection ignored = DriverManager.getConnection(url, username, password)) { | |
| 23 | + return true; | |
| 24 | + } catch (Exception ex) { | |
| 25 | + return false; | |
| 26 | + } | |
| 27 | + } | |
| 28 | + | |
| 29 | +} | ... | ... |
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 { |
| 49 | 49 | ErrorCode FILE_CONFIG_NOT_EXISTS = new ErrorCode(1001006000, "文件配置不存在"); |
| 50 | 50 | ErrorCode FILE_CONFIG_DELETE_FAIL_MASTER = new ErrorCode(1001006001, "该文件配置不允许删除,原因:它是主配置,删除会导致无法上传文件"); |
| 51 | 51 | |
| 52 | + // ========== 数据源配置 1001007000 ========== | |
| 53 | + ErrorCode DATA_SOURCE_CONFIG_NOT_EXISTS = new ErrorCode(1001007000, "数据源配置不存在"); | |
| 54 | + ErrorCode DATA_SOURCE_CONFIG_NOT_OK = new ErrorCode(1001007001, "数据源配置不正确,无法进行连接"); | |
| 55 | + | |
| 52 | 56 | } | ... | ... |
yudao-module-infra/yudao-module-infra-biz/pom.xml
| ... | ... | @@ -80,6 +80,11 @@ |
| 80 | 80 | |
| 81 | 81 | <!-- 工具类相关 --> |
| 82 | 82 | <dependency> |
| 83 | + <groupId>com.github.ulisesbocchio</groupId> | |
| 84 | + <artifactId>jasypt-spring-boot-starter</artifactId> <!-- 加解密 --> | |
| 85 | + </dependency> | |
| 86 | + | |
| 87 | + <dependency> | |
| 83 | 88 | <groupId>cn.iocoder.boot</groupId> |
| 84 | 89 | <artifactId>yudao-spring-boot-starter-excel</artifactId> |
| 85 | 90 | </dependency> | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DataSourceConfigController.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.controller.admin.db; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigCreateReqVO; | |
| 5 | +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigRespVO; | |
| 6 | +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigUpdateReqVO; | |
| 7 | +import cn.iocoder.yudao.module.infra.convert.db.DataSourceConfigConvert; | |
| 8 | +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; | |
| 9 | +import cn.iocoder.yudao.module.infra.service.db.DataSourceConfigService; | |
| 10 | +import io.swagger.annotations.Api; | |
| 11 | +import io.swagger.annotations.ApiImplicitParam; | |
| 12 | +import io.swagger.annotations.ApiOperation; | |
| 13 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 14 | +import org.springframework.validation.annotation.Validated; | |
| 15 | +import org.springframework.web.bind.annotation.*; | |
| 16 | + | |
| 17 | +import javax.annotation.Resource; | |
| 18 | +import javax.validation.Valid; | |
| 19 | +import java.util.List; | |
| 20 | + | |
| 21 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 22 | + | |
| 23 | +@Api(tags = "管理后台 - 数据源配置") | |
| 24 | +@RestController | |
| 25 | +@RequestMapping("/infra/data-source-config") | |
| 26 | +@Validated | |
| 27 | +public class DataSourceConfigController { | |
| 28 | + | |
| 29 | + @Resource | |
| 30 | + private DataSourceConfigService dataSourceConfigService; | |
| 31 | + | |
| 32 | + @PostMapping("/create") | |
| 33 | + @ApiOperation("创建数据源配置") | |
| 34 | + @PreAuthorize("@ss.hasPermission('infra:data-source-config:create')") | |
| 35 | + public CommonResult<Long> createDataSourceConfig(@Valid @RequestBody DataSourceConfigCreateReqVO createReqVO) { | |
| 36 | + return success(dataSourceConfigService.createDataSourceConfig(createReqVO)); | |
| 37 | + } | |
| 38 | + | |
| 39 | + @PutMapping("/update") | |
| 40 | + @ApiOperation("更新数据源配置") | |
| 41 | + @PreAuthorize("@ss.hasPermission('infra:data-source-config:update')") | |
| 42 | + public CommonResult<Boolean> updateDataSourceConfig(@Valid @RequestBody DataSourceConfigUpdateReqVO updateReqVO) { | |
| 43 | + dataSourceConfigService.updateDataSourceConfig(updateReqVO); | |
| 44 | + return success(true); | |
| 45 | + } | |
| 46 | + | |
| 47 | + @DeleteMapping("/delete") | |
| 48 | + @ApiOperation("删除数据源配置") | |
| 49 | + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) | |
| 50 | + @PreAuthorize("@ss.hasPermission('infra:data-source-config:delete')") | |
| 51 | + public CommonResult<Boolean> deleteDataSourceConfig(@RequestParam("id") Long id) { | |
| 52 | + dataSourceConfigService.deleteDataSourceConfig(id); | |
| 53 | + return success(true); | |
| 54 | + } | |
| 55 | + | |
| 56 | + @GetMapping("/get") | |
| 57 | + @ApiOperation("获得数据源配置") | |
| 58 | + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) | |
| 59 | + @PreAuthorize("@ss.hasPermission('infra:data-source-config:query')") | |
| 60 | + public CommonResult<DataSourceConfigRespVO> getDataSourceConfig(@RequestParam("id") Long id) { | |
| 61 | + DataSourceConfigDO dataSourceConfig = dataSourceConfigService.getDataSourceConfig(id); | |
| 62 | + return success(DataSourceConfigConvert.INSTANCE.convert(dataSourceConfig)); | |
| 63 | + } | |
| 64 | + | |
| 65 | + @GetMapping("/list") | |
| 66 | + @ApiOperation("获得数据源配置列表") | |
| 67 | + @PreAuthorize("@ss.hasPermission('infra:data-source-config:query')") | |
| 68 | + public CommonResult<List<DataSourceConfigRespVO>> getDataSourceConfigList() { | |
| 69 | + List<DataSourceConfigDO> list = dataSourceConfigService.getDataSourceConfigList(); | |
| 70 | + return success(DataSourceConfigConvert.INSTANCE.convertList(list)); | |
| 71 | + } | |
| 72 | + | |
| 73 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/doc/DbDocController.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java
| 1 | -package cn.iocoder.yudao.module.infra.controller.admin.doc; | |
| 1 | +package cn.iocoder.yudao.module.infra.controller.admin.db; | |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.io.FileUtil; |
| 4 | 4 | import cn.hutool.core.util.IdUtil; |
| ... | ... | @@ -30,7 +30,7 @@ import java.util.Arrays; |
| 30 | 30 | @Api(tags = "管理后台 - 数据库文档") |
| 31 | 31 | @RestController |
| 32 | 32 | @RequestMapping("/infra/db-doc") |
| 33 | -public class DbDocController { | |
| 33 | +public class DatabaseDocController { | |
| 34 | 34 | |
| 35 | 35 | @Resource |
| 36 | 36 | private DynamicDataSourceProperties dynamicDataSourceProperties; | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigBaseVO.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.controller.admin.db.vo; | |
| 2 | + | |
| 3 | +import lombok.*; | |
| 4 | +import java.util.*; | |
| 5 | +import io.swagger.annotations.*; | |
| 6 | +import javax.validation.constraints.*; | |
| 7 | + | |
| 8 | +/** | |
| 9 | +* 数据源配置 Base VO,提供给添加、修改、详细的子 VO 使用 | |
| 10 | +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | |
| 11 | +*/ | |
| 12 | +@Data | |
| 13 | +public class DataSourceConfigBaseVO { | |
| 14 | + | |
| 15 | + @ApiModelProperty(value = "参数名称", required = true, example = "test") | |
| 16 | + @NotNull(message = "参数名称不能为空") | |
| 17 | + private String name; | |
| 18 | + | |
| 19 | + @ApiModelProperty(value = "数据源连接", required = true, example = "jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro") | |
| 20 | + @NotNull(message = "数据源连接不能为空") | |
| 21 | + private String url; | |
| 22 | + | |
| 23 | + @ApiModelProperty(value = "用户名", required = true, example = "root") | |
| 24 | + @NotNull(message = "用户名不能为空") | |
| 25 | + private String username; | |
| 26 | + | |
| 27 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigCreateReqVO.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.controller.admin.db.vo; | |
| 2 | + | |
| 3 | +import lombok.*; | |
| 4 | +import java.util.*; | |
| 5 | +import io.swagger.annotations.*; | |
| 6 | +import javax.validation.constraints.*; | |
| 7 | + | |
| 8 | +@ApiModel("管理后台 - 数据源配置创建 Request VO") | |
| 9 | +@Data | |
| 10 | +@EqualsAndHashCode(callSuper = true) | |
| 11 | +@ToString(callSuper = true) | |
| 12 | +public class DataSourceConfigCreateReqVO extends DataSourceConfigBaseVO { | |
| 13 | + | |
| 14 | + @ApiModelProperty(value = "密码", required = true, example = "123456") | |
| 15 | + @NotNull(message = "密码不能为空") | |
| 16 | + private String password; | |
| 17 | + | |
| 18 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigRespVO.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.controller.admin.db.vo; | |
| 2 | + | |
| 3 | +import lombok.*; | |
| 4 | +import java.util.*; | |
| 5 | +import io.swagger.annotations.*; | |
| 6 | + | |
| 7 | +@ApiModel("管理后台 - 数据源配置 Response VO") | |
| 8 | +@Data | |
| 9 | +@EqualsAndHashCode(callSuper = true) | |
| 10 | +@ToString(callSuper = true) | |
| 11 | +public class DataSourceConfigRespVO extends DataSourceConfigBaseVO { | |
| 12 | + | |
| 13 | + @ApiModelProperty(value = "主键编号", required = true, example = "1024") | |
| 14 | + private Integer id; | |
| 15 | + | |
| 16 | + @ApiModelProperty(value = "创建时间", required = true) | |
| 17 | + private Date createTime; | |
| 18 | + | |
| 19 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigUpdateReqVO.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.controller.admin.db.vo; | |
| 2 | + | |
| 3 | +import lombok.*; | |
| 4 | +import java.util.*; | |
| 5 | +import io.swagger.annotations.*; | |
| 6 | +import javax.validation.constraints.*; | |
| 7 | + | |
| 8 | +@ApiModel("管理后台 - 数据源配置更新 Request VO") | |
| 9 | +@Data | |
| 10 | +@EqualsAndHashCode(callSuper = true) | |
| 11 | +@ToString(callSuper = true) | |
| 12 | +public class DataSourceConfigUpdateReqVO extends DataSourceConfigBaseVO { | |
| 13 | + | |
| 14 | + @ApiModelProperty(value = "主键编号", required = true, example = "1024") | |
| 15 | + @NotNull(message = "主键编号不能为空") | |
| 16 | + private Long id; | |
| 17 | + | |
| 18 | + @ApiModelProperty(value = "密码", required = true, example = "123456") | |
| 19 | + @NotNull(message = "密码不能为空") | |
| 20 | + private String password; | |
| 21 | + | |
| 22 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/db/DataSourceConfigConvert.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.convert.db; | |
| 2 | + | |
| 3 | +import java.util.*; | |
| 4 | + | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 6 | + | |
| 7 | +import org.mapstruct.Mapper; | |
| 8 | +import org.mapstruct.factory.Mappers; | |
| 9 | +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.*; | |
| 10 | +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * 数据源配置 Convert | |
| 14 | + * | |
| 15 | + * @author 芋道源码 | |
| 16 | + */ | |
| 17 | +@Mapper | |
| 18 | +public interface DataSourceConfigConvert { | |
| 19 | + | |
| 20 | + DataSourceConfigConvert INSTANCE = Mappers.getMapper(DataSourceConfigConvert.class); | |
| 21 | + | |
| 22 | + DataSourceConfigDO convert(DataSourceConfigCreateReqVO bean); | |
| 23 | + | |
| 24 | + DataSourceConfigDO convert(DataSourceConfigUpdateReqVO bean); | |
| 25 | + | |
| 26 | + DataSourceConfigRespVO convert(DataSourceConfigDO bean); | |
| 27 | + | |
| 28 | + List<DataSourceConfigRespVO> convertList(List<DataSourceConfigDO> list); | |
| 29 | + | |
| 30 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.infra.dal.dataobject.db; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 4 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 数据源配置 | |
| 9 | + * | |
| 10 | + * @author 芋道源码 | |
| 11 | + */ | |
| 12 | +@TableName("infra_data_source_config") | |
| 13 | +@Data | |
| 14 | +public class DataSourceConfigDO extends BaseDO { | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 主键编号 | |
| 18 | + */ | |
| 19 | + private Long id; | |
| 20 | + /** | |
| 21 | + * 连接名 | |
| 22 | + */ | |
| 23 | + private String name; | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 数据源连接 | |
| 27 | + */ | |
| 28 | + private String url; | |
| 29 | + /** | |
| 30 | + * 用户名 | |
| 31 | + */ | |
| 32 | + private String username; | |
| 33 | + /** | |
| 34 | + * 密码 | |
| 35 | + */ | |
| 36 | + private String password; | |
| 37 | + | |
| 38 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DataSourceConfigMapper.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.dal.mysql.db; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 4 | +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; | |
| 5 | +import org.apache.ibatis.annotations.Mapper; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 数据源配置 Mapper | |
| 9 | + * | |
| 10 | + * @author 芋道源码 | |
| 11 | + */ | |
| 12 | +@Mapper | |
| 13 | +public interface DataSourceConfigMapper extends BaseMapperX<DataSourceConfigDO> { | |
| 14 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigService.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.service.db; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigCreateReqVO; | |
| 5 | +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigUpdateReqVO; | |
| 6 | +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; | |
| 7 | +import org.w3c.dom.stylesheets.LinkStyle; | |
| 8 | + | |
| 9 | +import javax.validation.Valid; | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * 数据源配置 Service 接口 | |
| 14 | + * | |
| 15 | + * @author 芋道源码 | |
| 16 | + */ | |
| 17 | +public interface DataSourceConfigService { | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 创建数据源配置 | |
| 21 | + * | |
| 22 | + * @param createReqVO 创建信息 | |
| 23 | + * @return 编号 | |
| 24 | + */ | |
| 25 | + Long createDataSourceConfig(@Valid DataSourceConfigCreateReqVO createReqVO); | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 更新数据源配置 | |
| 29 | + * | |
| 30 | + * @param updateReqVO 更新信息 | |
| 31 | + */ | |
| 32 | + void updateDataSourceConfig(@Valid DataSourceConfigUpdateReqVO updateReqVO); | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 删除数据源配置 | |
| 36 | + * | |
| 37 | + * @param id 编号 | |
| 38 | + */ | |
| 39 | + void deleteDataSourceConfig(Long id); | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * 获得数据源配置 | |
| 43 | + * | |
| 44 | + * @param id 编号 | |
| 45 | + * @return 数据源配置 | |
| 46 | + */ | |
| 47 | + DataSourceConfigDO getDataSourceConfig(Long id); | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * 获得数据源配置列表 | |
| 51 | + * | |
| 52 | + * @return 数据源配置列表 | |
| 53 | + */ | |
| 54 | + List<DataSourceConfigDO> getDataSourceConfigList(); | |
| 55 | + | |
| 56 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.service.db; | |
| 2 | + | |
| 3 | +import cn.hutool.db.DbUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.util.DatabaseUtils; | |
| 6 | +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigCreateReqVO; | |
| 7 | +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigUpdateReqVO; | |
| 8 | +import cn.iocoder.yudao.module.infra.convert.db.DataSourceConfigConvert; | |
| 9 | +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; | |
| 10 | +import cn.iocoder.yudao.module.infra.dal.mysql.db.DataSourceConfigMapper; | |
| 11 | +import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils; | |
| 12 | +import org.jasypt.encryption.StringEncryptor; | |
| 13 | +import org.springframework.stereotype.Service; | |
| 14 | +import org.springframework.validation.annotation.Validated; | |
| 15 | + | |
| 16 | +import javax.annotation.Resource; | |
| 17 | + | |
| 18 | +import java.sql.Connection; | |
| 19 | +import java.util.List; | |
| 20 | + | |
| 21 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 22 | +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_EXISTS; | |
| 23 | +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_OK; | |
| 24 | + | |
| 25 | +/** | |
| 26 | + * 数据源配置 Service 实现类 | |
| 27 | + * | |
| 28 | + * @author 芋道源码 | |
| 29 | + */ | |
| 30 | +@Service | |
| 31 | +@Validated | |
| 32 | +public class DataSourceConfigServiceImpl implements DataSourceConfigService { | |
| 33 | + | |
| 34 | + @Resource | |
| 35 | + private DataSourceConfigMapper dataSourceConfigMapper; | |
| 36 | + | |
| 37 | + @Resource | |
| 38 | + private StringEncryptor stringEncryptor; | |
| 39 | + | |
| 40 | + @Override | |
| 41 | + public Long createDataSourceConfig(DataSourceConfigCreateReqVO createReqVO) { | |
| 42 | + DataSourceConfigDO dataSourceConfig = DataSourceConfigConvert.INSTANCE.convert(createReqVO); | |
| 43 | + checkConnectionOK(dataSourceConfig); | |
| 44 | + | |
| 45 | + // 插入 | |
| 46 | + dataSourceConfig.setPassword(stringEncryptor.encrypt(createReqVO.getPassword())); | |
| 47 | + dataSourceConfigMapper.insert(dataSourceConfig); | |
| 48 | + // 返回 | |
| 49 | + return dataSourceConfig.getId(); | |
| 50 | + } | |
| 51 | + | |
| 52 | + @Override | |
| 53 | + public void updateDataSourceConfig(DataSourceConfigUpdateReqVO updateReqVO) { | |
| 54 | + // 校验存在 | |
| 55 | + validateDataSourceConfigExists(updateReqVO.getId()); | |
| 56 | + DataSourceConfigDO updateObj = DataSourceConfigConvert.INSTANCE.convert(updateReqVO); | |
| 57 | + checkConnectionOK(updateObj); | |
| 58 | + | |
| 59 | + // 更新 | |
| 60 | + updateObj.setPassword(stringEncryptor.encrypt(updateObj.getPassword())); | |
| 61 | + dataSourceConfigMapper.updateById(updateObj); | |
| 62 | + } | |
| 63 | + | |
| 64 | + @Override | |
| 65 | + public void deleteDataSourceConfig(Long id) { | |
| 66 | + // 校验存在 | |
| 67 | + validateDataSourceConfigExists(id); | |
| 68 | + // 删除 | |
| 69 | + dataSourceConfigMapper.deleteById(id); | |
| 70 | + } | |
| 71 | + | |
| 72 | + private void validateDataSourceConfigExists(Long id) { | |
| 73 | + if (dataSourceConfigMapper.selectById(id) == null) { | |
| 74 | + throw exception(DATA_SOURCE_CONFIG_NOT_EXISTS); | |
| 75 | + } | |
| 76 | + } | |
| 77 | + | |
| 78 | + @Override | |
| 79 | + public DataSourceConfigDO getDataSourceConfig(Long id) { | |
| 80 | + DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(id); | |
| 81 | + dataSourceConfig.setPassword(stringEncryptor.decrypt(dataSourceConfig.getPassword())); | |
| 82 | + return dataSourceConfig; | |
| 83 | + } | |
| 84 | + | |
| 85 | + @Override | |
| 86 | + public List<DataSourceConfigDO> getDataSourceConfigList() { | |
| 87 | + return dataSourceConfigMapper.selectList(); | |
| 88 | + } | |
| 89 | + | |
| 90 | + private void checkConnectionOK(DataSourceConfigDO config) { | |
| 91 | + boolean success = DatabaseUtils.isConnectionOK(config.getUrl(), config.getUsername(), config.getPassword()); | |
| 92 | + if (!success) { | |
| 93 | + throw exception(DATA_SOURCE_CONFIG_NOT_OK); | |
| 94 | + } | |
| 95 | + } | |
| 96 | + | |
| 97 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.service.db; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.util.DatabaseUtils; | |
| 4 | +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | |
| 5 | +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigCreateReqVO; | |
| 6 | +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigUpdateReqVO; | |
| 7 | +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; | |
| 8 | +import cn.iocoder.yudao.module.infra.dal.mysql.db.DataSourceConfigMapper; | |
| 9 | +import org.jasypt.encryption.StringEncryptor; | |
| 10 | +import org.junit.jupiter.api.Test; | |
| 11 | +import org.mockito.MockedStatic; | |
| 12 | +import org.springframework.boot.test.mock.mockito.MockBean; | |
| 13 | +import org.springframework.context.annotation.Import; | |
| 14 | + | |
| 15 | +import javax.annotation.Resource; | |
| 16 | + | |
| 17 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | |
| 18 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; | |
| 19 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; | |
| 20 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | |
| 21 | +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_EXISTS; | |
| 22 | +import static org.junit.jupiter.api.Assertions.*; | |
| 23 | +import static org.mockito.Mockito.*; | |
| 24 | + | |
| 25 | +/** | |
| 26 | + * {@link DataSourceConfigServiceImpl} 的单元测试类 | |
| 27 | + * | |
| 28 | + * @author 芋道源码 | |
| 29 | + */ | |
| 30 | +@Import(DataSourceConfigServiceImpl.class) | |
| 31 | +public class DataSourceConfigServiceImplTest extends BaseDbUnitTest { | |
| 32 | + | |
| 33 | + @Resource | |
| 34 | + private DataSourceConfigServiceImpl dataSourceConfigService; | |
| 35 | + | |
| 36 | + @Resource | |
| 37 | + private DataSourceConfigMapper dataSourceConfigMapper; | |
| 38 | + | |
| 39 | + @MockBean | |
| 40 | + private StringEncryptor stringEncryptor; | |
| 41 | + | |
| 42 | + @Test | |
| 43 | + public void testCreateDataSourceConfig_success() { | |
| 44 | + try (MockedStatic<DatabaseUtils> databaseUtilsMock = mockStatic(DatabaseUtils.class)) { | |
| 45 | + // 准备参数 | |
| 46 | + DataSourceConfigCreateReqVO reqVO = randomPojo(DataSourceConfigCreateReqVO.class); | |
| 47 | + // mock 方法 | |
| 48 | + when(stringEncryptor.encrypt(eq(reqVO.getPassword()))).thenReturn("123456"); | |
| 49 | + databaseUtilsMock.when(() -> DatabaseUtils.isConnectionOK(eq(reqVO.getUrl()), | |
| 50 | + eq(reqVO.getUsername()), eq(reqVO.getPassword()))).thenReturn(true); | |
| 51 | + | |
| 52 | + // 调用 | |
| 53 | + Long dataSourceConfigId = dataSourceConfigService.createDataSourceConfig(reqVO); | |
| 54 | + // 断言 | |
| 55 | + assertNotNull(dataSourceConfigId); | |
| 56 | + // 校验记录的属性是否正确 | |
| 57 | + DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(dataSourceConfigId); | |
| 58 | + assertPojoEquals(reqVO, dataSourceConfig, "password"); | |
| 59 | + assertEquals("123456", dataSourceConfig.getPassword()); | |
| 60 | + } | |
| 61 | + } | |
| 62 | + | |
| 63 | + @Test | |
| 64 | + public void testUpdateDataSourceConfig_success() { | |
| 65 | + try (MockedStatic<DatabaseUtils> databaseUtilsMock = mockStatic(DatabaseUtils.class)) { | |
| 66 | + // mock 数据 | |
| 67 | + DataSourceConfigDO dbDataSourceConfig = randomPojo(DataSourceConfigDO.class); | |
| 68 | + dataSourceConfigMapper.insert(dbDataSourceConfig);// @Sql: 先插入出一条存在的数据 | |
| 69 | + // 准备参数 | |
| 70 | + DataSourceConfigUpdateReqVO reqVO = randomPojo(DataSourceConfigUpdateReqVO.class, o -> { | |
| 71 | + o.setId(dbDataSourceConfig.getId()); // 设置更新的 ID | |
| 72 | + }); | |
| 73 | + // mock 方法 | |
| 74 | + when(stringEncryptor.encrypt(eq(reqVO.getPassword()))).thenReturn("123456"); | |
| 75 | + databaseUtilsMock.when(() -> DatabaseUtils.isConnectionOK(eq(reqVO.getUrl()), | |
| 76 | + eq(reqVO.getUsername()), eq(reqVO.getPassword()))).thenReturn(true); | |
| 77 | + | |
| 78 | + // 调用 | |
| 79 | + dataSourceConfigService.updateDataSourceConfig(reqVO); | |
| 80 | + // 校验是否更新正确 | |
| 81 | + DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(reqVO.getId()); // 获取最新的 | |
| 82 | + assertPojoEquals(reqVO, dataSourceConfig, "password"); | |
| 83 | + assertEquals("123456", dataSourceConfig.getPassword()); | |
| 84 | + } | |
| 85 | + } | |
| 86 | + | |
| 87 | + @Test | |
| 88 | + public void testUpdateDataSourceConfig_notExists() { | |
| 89 | + // 准备参数 | |
| 90 | + DataSourceConfigUpdateReqVO reqVO = randomPojo(DataSourceConfigUpdateReqVO.class); | |
| 91 | + | |
| 92 | + // 调用, 并断言异常 | |
| 93 | + assertServiceException(() -> dataSourceConfigService.updateDataSourceConfig(reqVO), DATA_SOURCE_CONFIG_NOT_EXISTS); | |
| 94 | + } | |
| 95 | + | |
| 96 | + @Test | |
| 97 | + public void testDeleteDataSourceConfig_success() { | |
| 98 | + // mock 数据 | |
| 99 | + DataSourceConfigDO dbDataSourceConfig = randomPojo(DataSourceConfigDO.class); | |
| 100 | + dataSourceConfigMapper.insert(dbDataSourceConfig);// @Sql: 先插入出一条存在的数据 | |
| 101 | + // 准备参数 | |
| 102 | + Long id = dbDataSourceConfig.getId(); | |
| 103 | + | |
| 104 | + // 调用 | |
| 105 | + dataSourceConfigService.deleteDataSourceConfig(id); | |
| 106 | + // 校验数据不存在了 | |
| 107 | + assertNull(dataSourceConfigMapper.selectById(id)); | |
| 108 | + } | |
| 109 | + | |
| 110 | + @Test | |
| 111 | + public void testDeleteDataSourceConfig_notExists() { | |
| 112 | + // 准备参数 | |
| 113 | + Long id = randomLongId(); | |
| 114 | + | |
| 115 | + // 调用, 并断言异常 | |
| 116 | + assertServiceException(() -> dataSourceConfigService.deleteDataSourceConfig(id), DATA_SOURCE_CONFIG_NOT_EXISTS); | |
| 117 | + } | |
| 118 | + | |
| 119 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql
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" ( |
| 168 | 168 | "deleted" bit NOT NULL DEFAULT FALSE, |
| 169 | 169 | PRIMARY KEY ("id") |
| 170 | 170 | ) COMMENT '字典类型表'; |
| 171 | + | |
| 172 | +CREATE TABLE IF NOT EXISTS "infra_data_source_config" ( | |
| 173 | + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, | |
| 174 | + "name" varchar(100) NOT NULL, | |
| 175 | + "url" varchar(1024) NOT NULL, | |
| 176 | + "username" varchar(255) NOT NULL, | |
| 177 | + "password" varchar(255) NOT NULL, | |
| 178 | + "creator" varchar(64) DEFAULT '', | |
| 179 | + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
| 180 | + "updater" varchar(64) DEFAULT '', | |
| 181 | + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | |
| 182 | + "deleted" bit NOT NULL DEFAULT FALSE, | |
| 183 | + PRIMARY KEY ("id") | |
| 184 | +) COMMENT '数据源配置表'; | ... | ... |
yudao-module-member/yudao-module-member-biz/pom.xml
yudao-server/src/main/resources/application-dev.yaml
yudao-server/src/main/resources/application-local.yaml
yudao-server/src/main/resources/application.yaml
yudao-ui-admin/src/api/infra/dataSourceConfig.js
0 → 100755
| 1 | +import request from '@/utils/request' | |
| 2 | + | |
| 3 | +// 创建数据源配置 | |
| 4 | +export function createDataSourceConfig(data) { | |
| 5 | + return request({ | |
| 6 | + url: '/infra/data-source-config/create', | |
| 7 | + method: 'post', | |
| 8 | + data: data | |
| 9 | + }) | |
| 10 | +} | |
| 11 | + | |
| 12 | +// 更新数据源配置 | |
| 13 | +export function updateDataSourceConfig(data) { | |
| 14 | + return request({ | |
| 15 | + url: '/infra/data-source-config/update', | |
| 16 | + method: 'put', | |
| 17 | + data: data | |
| 18 | + }) | |
| 19 | +} | |
| 20 | + | |
| 21 | +// 删除数据源配置 | |
| 22 | +export function deleteDataSourceConfig(id) { | |
| 23 | + return request({ | |
| 24 | + url: '/infra/data-source-config/delete?id=' + id, | |
| 25 | + method: 'delete' | |
| 26 | + }) | |
| 27 | +} | |
| 28 | + | |
| 29 | +// 获得数据源配置 | |
| 30 | +export function getDataSourceConfig(id) { | |
| 31 | + return request({ | |
| 32 | + url: '/infra/data-source-config/get?id=' + id, | |
| 33 | + method: 'get' | |
| 34 | + }) | |
| 35 | +} | |
| 36 | + | |
| 37 | +// 获得数据源配置列表 | |
| 38 | +export function getDataSourceConfigList() { | |
| 39 | + return request({ | |
| 40 | + url: '/infra/data-source-config/list', | |
| 41 | + method: 'get', | |
| 42 | + }) | |
| 43 | +} | ... | ... |
yudao-ui-admin/src/views/infra/dataSourceConfig/index.vue
0 → 100755
| 1 | +<template> | |
| 2 | + <div class="app-container"> | |
| 3 | + <!-- 操作工具栏 --> | |
| 4 | + <el-row :gutter="10" class="mb8"> | |
| 5 | + <el-col :span="1.5"> | |
| 6 | + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" | |
| 7 | + v-hasPermi="['infra:data-source-config:create']">新增</el-button> | |
| 8 | + </el-col> | |
| 9 | + </el-row> | |
| 10 | + | |
| 11 | + <!-- 列表 --> | |
| 12 | + <el-table v-loading="loading" :data="list"> | |
| 13 | + <el-table-column label="主键编号" align="center" prop="id" /> | |
| 14 | + <el-table-column label="参数名称" align="center" prop="name" /> | |
| 15 | + <el-table-column label="数据源连接" align="center" prop="url" /> | |
| 16 | + <el-table-column label="用户名" align="center" prop="username" /> | |
| 17 | + <el-table-column label="创建时间" align="center" prop="createTime" width="180"> | |
| 18 | + <template slot-scope="scope"> | |
| 19 | + <span>{{ parseTime(scope.row.createTime) }}</span> | |
| 20 | + </template> | |
| 21 | + </el-table-column> | |
| 22 | + <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | |
| 23 | + <template slot-scope="scope"> | |
| 24 | + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" | |
| 25 | + v-hasPermi="['infra:data-source-config:update']">修改</el-button> | |
| 26 | + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" | |
| 27 | + v-hasPermi="['infra:data-source-config:delete']">删除</el-button> | |
| 28 | + </template> | |
| 29 | + </el-table-column> | |
| 30 | + </el-table> | |
| 31 | + | |
| 32 | + <!-- 对话框(添加 / 修改) --> | |
| 33 | + <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> | |
| 34 | + <el-form ref="form" :model="form" :rules="rules" label-width="100px"> | |
| 35 | + <el-form-item label="参数名称" prop="name"> | |
| 36 | + <el-input v-model="form.name" placeholder="请输入参数名称" /> | |
| 37 | + </el-form-item> | |
| 38 | + <el-form-item label="数据源连接" prop="url"> | |
| 39 | + <el-input v-model="form.url" placeholder="请输入数据源连接" /> | |
| 40 | + </el-form-item> | |
| 41 | + <el-form-item label="用户名" prop="username"> | |
| 42 | + <el-input v-model="form.username" placeholder="请输入用户名" /> | |
| 43 | + </el-form-item> | |
| 44 | + <el-form-item label="密码" prop="password"> | |
| 45 | + <el-input v-model="form.password" placeholder="请输入密码" /> | |
| 46 | + </el-form-item> | |
| 47 | + </el-form> | |
| 48 | + <div slot="footer" class="dialog-footer"> | |
| 49 | + <el-button type="primary" @click="submitForm">确 定</el-button> | |
| 50 | + <el-button @click="cancel">取 消</el-button> | |
| 51 | + </div> | |
| 52 | + </el-dialog> | |
| 53 | + </div> | |
| 54 | +</template> | |
| 55 | + | |
| 56 | +<script> | |
| 57 | +import { createDataSourceConfig, updateDataSourceConfig, deleteDataSourceConfig, getDataSourceConfig, getDataSourceConfigList } from "@/api/infra/dataSourceConfig"; | |
| 58 | + | |
| 59 | +export default { | |
| 60 | + name: "DataSourceConfig", | |
| 61 | + components: { | |
| 62 | + }, | |
| 63 | + data() { | |
| 64 | + return { | |
| 65 | + // 遮罩层 | |
| 66 | + loading: true, | |
| 67 | + // 总条数 | |
| 68 | + total: 0, | |
| 69 | + // 数据源配置列表 | |
| 70 | + list: [], | |
| 71 | + // 弹出层标题 | |
| 72 | + title: "", | |
| 73 | + // 是否显示弹出层 | |
| 74 | + open: false, | |
| 75 | + // 表单参数 | |
| 76 | + form: {}, | |
| 77 | + // 表单校验 | |
| 78 | + rules: { | |
| 79 | + name: [{ required: true, message: "参数名称不能为空", trigger: "blur" }], | |
| 80 | + url: [{ required: true, message: "数据源连接不能为空", trigger: "blur" }], | |
| 81 | + username: [{ required: true, message: "用户名不能为空", trigger: "blur" }], | |
| 82 | + password: [{ required: true, message: "密码不能为空", trigger: "blur" }], | |
| 83 | + } | |
| 84 | + }; | |
| 85 | + }, | |
| 86 | + created() { | |
| 87 | + this.getList(); | |
| 88 | + }, | |
| 89 | + methods: { | |
| 90 | + /** 查询列表 */ | |
| 91 | + getList() { | |
| 92 | + this.loading = true; | |
| 93 | + // 执行查询 | |
| 94 | + getDataSourceConfigList().then(response => { | |
| 95 | + this.list = response.data; | |
| 96 | + this.loading = false; | |
| 97 | + }); | |
| 98 | + }, | |
| 99 | + /** 取消按钮 */ | |
| 100 | + cancel() { | |
| 101 | + this.open = false; | |
| 102 | + this.reset(); | |
| 103 | + }, | |
| 104 | + /** 表单重置 */ | |
| 105 | + reset() { | |
| 106 | + this.form = { | |
| 107 | + id: undefined, | |
| 108 | + name: undefined, | |
| 109 | + url: undefined, | |
| 110 | + username: undefined, | |
| 111 | + password: undefined, | |
| 112 | + }; | |
| 113 | + this.resetForm("form"); | |
| 114 | + }, | |
| 115 | + /** 新增按钮操作 */ | |
| 116 | + handleAdd() { | |
| 117 | + this.reset(); | |
| 118 | + this.open = true; | |
| 119 | + this.title = "添加数据源配置"; | |
| 120 | + }, | |
| 121 | + /** 修改按钮操作 */ | |
| 122 | + handleUpdate(row) { | |
| 123 | + this.reset(); | |
| 124 | + const id = row.id; | |
| 125 | + getDataSourceConfig(id).then(response => { | |
| 126 | + this.form = response.data; | |
| 127 | + this.open = true; | |
| 128 | + this.title = "修改数据源配置"; | |
| 129 | + }); | |
| 130 | + }, | |
| 131 | + /** 提交按钮 */ | |
| 132 | + submitForm() { | |
| 133 | + this.$refs["form"].validate(valid => { | |
| 134 | + if (!valid) { | |
| 135 | + return; | |
| 136 | + } | |
| 137 | + // 修改的提交 | |
| 138 | + if (this.form.id != null) { | |
| 139 | + updateDataSourceConfig(this.form).then(response => { | |
| 140 | + this.$modal.msgSuccess("修改成功"); | |
| 141 | + this.open = false; | |
| 142 | + this.getList(); | |
| 143 | + }); | |
| 144 | + return; | |
| 145 | + } | |
| 146 | + // 添加的提交 | |
| 147 | + createDataSourceConfig(this.form).then(response => { | |
| 148 | + this.$modal.msgSuccess("新增成功"); | |
| 149 | + this.open = false; | |
| 150 | + this.getList(); | |
| 151 | + }); | |
| 152 | + }); | |
| 153 | + }, | |
| 154 | + /** 删除按钮操作 */ | |
| 155 | + handleDelete(row) { | |
| 156 | + const id = row.id; | |
| 157 | + this.$modal.confirm('是否确认删除数据源配置编号为"' + id + '"的数据项?').then(function() { | |
| 158 | + return deleteDataSourceConfig(id); | |
| 159 | + }).then(() => { | |
| 160 | + this.getList(); | |
| 161 | + this.$modal.msgSuccess("删除成功"); | |
| 162 | + }).catch(() => {}); | |
| 163 | + } | |
| 164 | + } | |
| 165 | +}; | |
| 166 | +</script> | ... | ... |