Commit b34e2691f82023e0b1b43ec8014f715fb21a2f73

Authored by YunaiV
1 parent f1069aa3

支持主流数据库的代码生成

Showing 30 changed files with 270 additions and 1018 deletions
yudao-dependencies/pom.xml
... ... @@ -25,6 +25,7 @@
25 25 <mysql.version>5.1.46</mysql.version>
26 26 <druid.version>1.2.8</druid.version>
27 27 <mybatis-plus.version>3.4.3.4</mybatis-plus.version>
  28 + <mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
28 29 <dynamic-datasource.version>3.5.0</dynamic-datasource.version>
29 30 <redisson.version>3.17.0</redisson.version>
30 31 <!-- Config 配置中心相关 -->
... ... @@ -195,6 +196,11 @@
195 196 </dependency>
196 197 <dependency>
197 198 <groupId>com.baomidou</groupId>
  199 + <artifactId>mybatis-plus-generator</artifactId> <!-- 代码生成器,使用它解析表结构 -->
  200 + <version>${mybatis-plus-generator.version}</version>
  201 + </dependency>
  202 + <dependency>
  203 + <groupId>com.baomidou</groupId>
198 204 <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->
199 205 <version>${dynamic-datasource.version}</version>
200 206 </dependency>
... ...
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java
1 1 package cn.iocoder.yudao.framework.mybatis.core.util;
2 2  
3   -import com.baomidou.mybatisplus.annotation.DbType;
4   -import lombok.SneakyThrows;
5   -import org.springframework.dao.DataAccessException;
6   -import org.springframework.jdbc.core.JdbcTemplate;
7   -import org.springframework.jdbc.core.RowCallbackHandler;
8   -import org.springframework.jdbc.core.RowMapper;
9   -
10   -import java.sql.*;
11   -import java.util.ArrayList;
12   -import java.util.List;
  3 +import java.sql.Connection;
  4 +import java.sql.DriverManager;
13 5  
14 6 /**
15 7 * JDBC 工具类
... ... @@ -34,52 +26,4 @@ public class JdbcUtils {
34 26 }
35 27 }
36 28  
37   - /**
38   - * 获得连接
39   - *
40   - * @param url 数据源连接
41   - * @param username 账号
42   - * @param password 密码
43   - * @return 是否正确
44   - */
45   - @SneakyThrows
46   - public static Connection getConnection(String url, String username, String password) {
47   - return DriverManager.getConnection(url, username, password);
48   - }
49   -
50   - /**
51   - * 执行指定 SQL,返回查询列表
52   - *
53   - * 参考 {@link JdbcTemplate#query(String, RowMapper)} 实现,主要考虑 JdbcTemplate 不支持使用指定 Connection 查询
54   - *
55   - * @param connection 数据库连接
56   - * @param sql SQL
57   - * @param handler 行处理器
58   - * @return 列表
59   - */
60   - @SneakyThrows
61   - public static <T> List<T> query(Connection connection, String sql, RowMapper<T> handler) {
62   - try (PreparedStatement ps = connection.prepareStatement(sql);
63   - ResultSet rs = ps.executeQuery()) {
64   - // 处理结果
65   - List<T> result = new ArrayList<>();
66   - int rowNum = 0;
67   - while (rs.next()) {
68   - result.add(handler.mapRow(rs, rowNum++));
69   - }
70   - return result;
71   - }
72   - }
73   -
74   - /**
75   - * 获得 URL 对应的 DB 类型
76   - *
77   - * @param url URL
78   - * @return DB 类型
79   - */
80   - public static DbType getDbType(String url) {
81   - String name = com.alibaba.druid.util.JdbcUtils.getDbType(url, null);
82   - return DbType.getDbType(name);
83   - }
84   -
85 29 }
... ...
yudao-module-infra/yudao-module-infra-biz/pom.xml
... ... @@ -47,6 +47,10 @@
47 47 <groupId>cn.iocoder.boot</groupId>
48 48 <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
49 49 </dependency>
  50 + <dependency>
  51 + <groupId>com.baomidou</groupId>
  52 + <artifactId>mybatis-plus-generator</artifactId> <!-- 代码生成器,使用它解析表结构 -->
  53 + </dependency>
50 54  
51 55 <dependency>
52 56 <groupId>cn.iocoder.boot</groupId>
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/CodegenController.java
... ... @@ -4,19 +4,18 @@ import cn.hutool.core.io.IoUtil;
4 4 import cn.hutool.core.util.ZipUtil;
5 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
  8 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
7 9 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO;
8 10 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenPreviewRespVO;
9 11 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
10 12 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
11 13 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableRespVO;
12   -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.SchemaTableRespVO;
  14 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
13 15 import cn.iocoder.yudao.module.infra.convert.codegen.CodegenConvert;
14 16 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
15 17 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
16   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
17 18 import cn.iocoder.yudao.module.infra.service.codegen.CodegenService;
18   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
19   -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
20 19 import io.swagger.annotations.Api;
21 20 import io.swagger.annotations.ApiImplicitParam;
22 21 import io.swagger.annotations.ApiImplicitParams;
... ... @@ -33,7 +32,6 @@ import java.io.ByteArrayOutputStream;
33 32 import java.io.IOException;
34 33 import java.util.List;
35 34 import java.util.Map;
36   -import java.util.Set;
37 35  
38 36 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
39 37 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
... ... @@ -51,20 +49,15 @@ public class CodegenController {
51 49 @ApiOperation(value = "获得数据库自带的表定义列表", notes = "会过滤掉已经导入 Codegen 的表")
52 50 @ApiImplicitParams({
53 51 @ApiImplicitParam(name = "dataSourceConfigId", value = "数据源配置的编号", required = true, example = "1", dataTypeClass = Long.class),
54   - @ApiImplicitParam(name = "tableName", value = "表名,模糊匹配", example = "yudao", dataTypeClass = String.class),
55   - @ApiImplicitParam(name = "tableComment", value = "描述,模糊匹配", example = "芋道", dataTypeClass = String.class)
  52 + @ApiImplicitParam(name = "name", value = "表名,模糊匹配", example = "yudao", dataTypeClass = String.class),
  53 + @ApiImplicitParam(name = "comment", value = "描述,模糊匹配", example = "芋道", dataTypeClass = String.class)
56 54 })
57 55 @PreAuthorize("@ss.hasPermission('infra:codegen:query')")
58   - public CommonResult<List<SchemaTableRespVO>> getSchemaTableList(
  56 + public CommonResult<List<DatabaseTableRespVO>> getDatabaseTableList(
59 57 @RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId,
60   - @RequestParam(value = "tableName", required = false) String tableName,
61   - @RequestParam(value = "tableComment", required = false) String tableComment) {
62   - // 获得数据库自带的表定义列表
63   - List<DatabaseTableDO> schemaTables = codegenService.getSchemaTableList(dataSourceConfigId, tableName, tableComment);
64   - // 移除在 Codegen 中,已经存在的
65   - Set<String> existsTables = CollectionUtils.convertSet(codegenService.getCodeGenTableList(), CodegenTableDO::getTableName);
66   - schemaTables.removeIf(table -> existsTables.contains(table.getTableName()));
67   - return success(CodegenConvert.INSTANCE.convertList04(schemaTables));
  58 + @RequestParam(value = "name", required = false) String name,
  59 + @RequestParam(value = "comment", required = false) String comment) {
  60 + return success(codegenService.getDatabaseTableList(dataSourceConfigId, name, comment));
68 61 }
69 62  
70 63 @GetMapping("/table/page")
... ... @@ -87,19 +80,10 @@ public class CodegenController {
87 80 }
88 81  
89 82 @ApiOperation("基于数据库的表结构,创建代码生成器的表和字段定义")
90   - @ApiImplicitParam(name = "tableNames", value = "表名数组", required = true, example = "sys_user", dataTypeClass = List.class)
91   - @PostMapping("/create-list-from-db")
92   - @PreAuthorize("@ss.hasPermission('infra:codegen:create')")
93   - public CommonResult<List<Long>> createCodegenListFromDB(@RequestParam("tableNames") List<String> tableNames) {
94   - return success(codegenService.createCodegenListFromDB(getLoginUserId(), tableNames));
95   - }
96   -
97   - @ApiOperation("基于 SQL 建表语句,创建代码生成器的表和字段定义")
98   - @ApiImplicitParam(name = "sql", value = "SQL 建表语句", required = true, example = "sql", dataTypeClass = String.class)
99   - @PostMapping("/create-list-from-sql")
  83 + @PostMapping("/create-list")
100 84 @PreAuthorize("@ss.hasPermission('infra:codegen:create')")
101   - public CommonResult<Long> createCodegenListFromSQL(@RequestParam("sql") String sql) {
102   - return success(codegenService.createCodegenListFromSQL(getLoginUserId(), sql));
  85 + public CommonResult<List<Long>> createCodegenList(@Valid @RequestBody CodegenCreateListReqVO reqVO) {
  86 + return success(codegenService.createCodegenList(getLoginUserId(), reqVO));
103 87 }
104 88  
105 89 @ApiOperation("更新数据库的表和字段定义")
... ... @@ -119,19 +103,6 @@ public class CodegenController {
119 103 return success(true);
120 104 }
121 105  
122   - @ApiOperation("基于 SQL 建表语句,同步数据库的表和字段定义")
123   - @PutMapping("/sync-from-sql")
124   - @ApiImplicitParams({
125   - @ApiImplicitParam(name = "tableId", value = "表编号", required = true, example = "1024", dataTypeClass = Long.class),
126   - @ApiImplicitParam(name = "sql", value = "SQL 建表语句", required = true, example = "sql", dataTypeClass = String.class)
127   - })
128   - @PreAuthorize("@ss.hasPermission('infra:codegen:update')")
129   - public CommonResult<Boolean> syncCodegenFromSQL(@RequestParam("tableId") Long tableId,
130   - @RequestParam("sql") String sql) {
131   - codegenService.syncCodegenFromSQL(tableId, sql);
132   - return success(true);
133   - }
134   -
135 106 @ApiOperation("删除数据库的表和字段定义")
136 107 @DeleteMapping("/delete")
137 108 @ApiImplicitParam(name = "tableId", value = "表编号", required = true, example = "1024", dataTypeClass = Long.class)
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenCreateListReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +import java.util.List;
  9 +
  10 +@ApiModel("管理后台 - 基于数据库的表结构,创建代码生成器的表和字段定义 Request VO")
  11 +@Data
  12 +public class CodegenCreateListReqVO {
  13 +
  14 + @ApiModelProperty(value = "数据源配置的编号", required = true, example = "1")
  15 + @NotNull(message = "数据源配置的编号不能为空")
  16 + private Long dataSourceConfigId;
  17 +
  18 + @ApiModelProperty(value = "表名数组", required = true, example = "[1, 2, 3]")
  19 + @NotNull(message = "表名数组不能为空")
  20 + private List<String> tableNames;
  21 +
  22 +}
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableBaseVO.java
... ... @@ -12,10 +12,6 @@ import javax.validation.constraints.NotNull;
12 12 @Data
13 13 public class CodegenTableBaseVO {
14 14  
15   - @ApiModelProperty(value = "导入类型", required = true, example = "1", notes = "参见 CodegenImportTypeEnum 枚举")
16   - @NotNull(message = "导入类型不能为空")
17   - private Integer importType;
18   -
19 15 @ApiModelProperty(value = "生成场景", required = true, example = "1", notes = "参见 CodegenSceneEnum 枚举")
20 16 @NotNull(message = "导入类型不能为空")
21 17 private Integer scene;
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableRespVO.java
... ... @@ -17,6 +17,9 @@ public class CodegenTableRespVO extends CodegenTableBaseVO {
17 17 @ApiModelProperty(value = "编号", required = true, example = "1")
18 18 private Long id;
19 19  
  20 + @ApiModelProperty(value = "主键编号", required = true, example = "1024")
  21 + private Integer dataSourceConfigId;
  22 +
20 23 @ApiModelProperty(value = "创建时间", required = true)
21 24 private Date createTime;
22 25  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/SchemaTableRespVO.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/DatabaseTableRespVO.java
... ... @@ -4,22 +4,14 @@ import io.swagger.annotations.ApiModel;
4 4 import io.swagger.annotations.ApiModelProperty;
5 5 import lombok.Data;
6 6  
7   -import java.util.Date;
8   -
9   -@ApiModel("管理后台 - 数据字典的表定义 Response VO")
  7 +@ApiModel("管理后台 - 数据库的表定义 Response VO")
10 8 @Data
11   -public class SchemaTableRespVO {
12   -
13   - @ApiModelProperty(value = "数据库", required = true, example = "yudao")
14   - private String tableSchema;
  9 +public class DatabaseTableRespVO {
15 10  
16 11 @ApiModelProperty(value = "表名称", required = true, example = "yuanma")
17   - private String tableName;
  12 + private String name;
18 13  
19 14 @ApiModelProperty(value = "表描述", required = true, example = "芋道源码")
20   - private String tableComment;
21   -
22   - @ApiModelProperty(value = "创建时间", required = true)
23   - private Date createTime;
  15 + private String comment;
24 16  
25 17 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java
... ... @@ -6,12 +6,14 @@ import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenPreviewR
6 6 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
7 7 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnRespVO;
8 8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableRespVO;
9   -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.SchemaTableRespVO;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
10 10 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
11 11 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
12   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseColumnDO;
13   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
  12 +import com.baomidou.mybatisplus.generator.config.po.TableField;
  13 +import com.baomidou.mybatisplus.generator.config.po.TableInfo;
14 14 import org.mapstruct.Mapper;
  15 +import org.mapstruct.Mapping;
  16 +import org.mapstruct.Mappings;
15 17 import org.mapstruct.factory.Mappers;
16 18  
17 19 import java.util.List;
... ... @@ -23,13 +25,27 @@ public interface CodegenConvert {
23 25  
24 26 CodegenConvert INSTANCE = Mappers.getMapper(CodegenConvert.class);
25 27  
26   - // ========== InformationSchemaTableDO 和 InformationSchemaColumnDO 相关 ==========
  28 + // ========== TableInfo 相关 ==========
27 29  
28   - CodegenTableDO convert(DatabaseTableDO bean);
  30 + @Mappings({
  31 + @Mapping(source = "name", target = "tableName"),
  32 + @Mapping(source = "comment", target = "tableComment"),
  33 + })
  34 + CodegenTableDO convert(TableInfo bean);
29 35  
30   - List<CodegenColumnDO> convertList(List<DatabaseColumnDO> list);
  36 + List<CodegenColumnDO> convertList(List<TableField> list);
31 37  
32   - CodegenTableRespVO convert(DatabaseColumnDO bean);
  38 + @Mappings({
  39 + @Mapping(source = "name", target = "columnName"),
  40 + @Mapping(source = "type", target = "dataType"),
  41 + @Mapping(source = "comment", target = "columnComment"),
  42 + @Mapping(source = "metaInfo.nullable", target = "nullable"),
  43 + @Mapping(source = "keyFlag", target = "primaryKey"),
  44 + @Mapping(source = "keyIdentityFlag", target = "autoIncrement"),
  45 + @Mapping(source = "columnType.type", target = "javaType"),
  46 + @Mapping(source = "propertyName", target = "javaField"),
  47 + })
  48 + CodegenColumnDO convert(TableField bean);
33 49  
34 50 // ========== CodegenTableDO 相关 ==========
35 51  
... ... @@ -47,7 +63,7 @@ public interface CodegenConvert {
47 63  
48 64 List<CodegenColumnDO> convertList03(List<CodegenUpdateReqVO.Column> columns);
49 65  
50   - List<SchemaTableRespVO> convertList04(List<DatabaseTableDO> list);
  66 + List<DatabaseTableRespVO> convertList04(List<TableInfo> list);
51 67  
52 68 // ========== 其它 ==========
53 69  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenTableDO.java
1 1 package cn.iocoder.yudao.module.infra.dal.dataobject.codegen;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO;
4 5 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
5 6 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
6 7 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -25,11 +26,11 @@ public class CodegenTableDO extends BaseDO {
25 26 private Long id;
26 27  
27 28 /**
28   - * 导入类型
  29 + * 数据源编号
29 30 *
30   - * 枚举 {@link CodegenTemplateTypeEnum}
  31 + * 关联 {@link DataSourceConfigDO#getId()}
31 32 */
32   - private Integer importType;
  33 + private Long dataSourceConfigId;
33 34 /**
34 35 * 生成场景
35 36 *
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DatabaseColumnDO.java deleted
1   -package cn.iocoder.yudao.module.infra.dal.dataobject.db;
2   -
3   -import com.baomidou.mybatisplus.annotation.TableField;
4   -import com.baomidou.mybatisplus.annotation.TableName;
5   -import lombok.Builder;
6   -import lombok.Data;
7   -
8   -/**
9   - * MySQL 数据库中的 column 字段定义
10   - *
11   - * @author 芋道源码
12   - */
13   -@Data
14   -@Builder
15   -public class DatabaseColumnDO {
16   -
17   - /**
18   - * 表名称
19   - */
20   - private String tableName;
21   - /**
22   - * 字段名
23   - */
24   - private String columnName;
25   - /**
26   - * 字段类型
27   - */
28   - private String dataType;
29   - /**
30   - * 字段描述
31   - */
32   - private String columnComment;
33   - /**
34   - * 是否允许为空
35   - */
36   - private Boolean nullable;
37   - /**
38   - * 是否主键
39   - */
40   - private Boolean primaryKey;
41   - /**
42   - * 是否自增
43   - */
44   - private Boolean autoIncrement;
45   - /**
46   - * 排序字段
47   - */
48   - private Integer ordinalPosition;
49   -
50   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DatabaseTableDO.java deleted
1   -package cn.iocoder.yudao.module.infra.dal.dataobject.db;
2   -
3   -import lombok.Builder;
4   -import lombok.Data;
5   -
6   -import java.util.Date;
7   -
8   -/**
9   - * MySQL 数据库中的 table 表定义
10   - *
11   - * @author 芋道源码
12   - */
13   -@Data
14   -@Builder
15   -public class DatabaseTableDO {
16   -
17   - /**
18   - * 表名称
19   - */
20   - private String tableName;
21   - /**
22   - * 表描述
23   - */
24   - private String tableComment;
25   - /**
26   - * 创建时间
27   - */
28   - private Date createTime;
29   -
30   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/CodegenTableMapper.java
... ... @@ -3,16 +3,18 @@ package cn.iocoder.yudao.module.infra.dal.mysql.codegen;
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
6   -import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
7 6 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
8   -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  7 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
9 8 import org.apache.ibatis.annotations.Mapper;
10 9  
  10 +import java.util.List;
  11 +
11 12 @Mapper
12 13 public interface CodegenTableMapper extends BaseMapperX<CodegenTableDO> {
13 14  
14   - default CodegenTableDO selectByTableName(String tableName) {
15   - return selectOne(new QueryWrapper<CodegenTableDO>().eq("table_name", tableName));
  15 + default CodegenTableDO selectByTableNameAndDataSourceConfigId(String tableName, Long dataSourceConfigId) {
  16 + return selectOne(CodegenTableDO::getTableName, tableName,
  17 + CodegenTableDO::getDataSourceConfigId, dataSourceConfigId);
16 18 }
17 19  
18 20 default PageResult<CodegenTableDO> selectPage(CodegenTablePageReqVO pageReqVO) {
... ... @@ -22,4 +24,8 @@ public interface CodegenTableMapper extends BaseMapperX&lt;CodegenTableDO&gt; {
22 24 .betweenIfPresent("create_time", pageReqVO.getBeginCreateTime(), pageReqVO.getEndCreateTime()));
23 25 }
24 26  
  27 + default List<CodegenTableDO> selectListByDataSourceConfigId(Long dataSourceConfigId) {
  28 + return selectList(CodegenTableDO::getDataSourceConfigId, dataSourceConfigId);
  29 + }
  30 +
25 31 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DatabaseTableDAO.java deleted
1   -package cn.iocoder.yudao.module.infra.dal.mysql.db;
2   -
3   -import cn.hutool.core.collection.CollUtil;
4   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseColumnDO;
5   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
6   -import com.baomidou.mybatisplus.annotation.DbType;
7   -
8   -import java.sql.Connection;
9   -import java.util.List;
10   -
11   -/**
12   - * 数据库 Table DAO 接口
13   - *
14   - * @author 芋道源码
15   - */
16   -public interface DatabaseTableDAO {
17   -
18   - /**
19   - * 获得表列表,基于表名称 + 表描述进行模糊匹配
20   - *
21   - * @param connection 数据库连接
22   - * @param tableNameLike 表名称,模糊匹配
23   - * @param tableCommentLike 表描述,模糊匹配
24   - * @return 表列表
25   - */
26   - List<DatabaseTableDO> selectTableList(Connection connection, String tableNameLike, String tableCommentLike);
27   -
28   - /**
29   - * 获得指定表名
30   - *
31   - * @param connection 数据库连接
32   - * @param tableName 表名称
33   - * @return 表
34   - */
35   - default DatabaseTableDO selectTable(Connection connection, String tableName) {
36   - // 考虑到对性能没有要求,直接查询列表,然后内存过滤到记录
37   - List<DatabaseTableDO> tables = selectTableList(connection, tableName, null);
38   - return CollUtil.findOne(tables, table -> table.getTableName().equalsIgnoreCase(tableName));
39   - }
40   -
41   - /**
42   - * 获得指定表的字段列表
43   - *
44   - * @param connection 数据库连接
45   - * @param tableName 表名称
46   - * @return 字段列表
47   - */
48   - List<DatabaseColumnDO> selectColumnList(Connection connection, String tableName);
49   -
50   - /**
51   - * 获得数据库的类型
52   - *
53   - * @return 数据库的类型
54   - */
55   - DbType getType();
56   -
57   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DatabaseTableMySQLDAOImpl.java deleted
1   -package cn.iocoder.yudao.module.infra.dal.mysql.db;
2   -
3   -import cn.hutool.core.util.StrUtil;
4   -import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils;
5   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseColumnDO;
6   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
7   -import com.baomidou.mybatisplus.annotation.DbType;
8   -import org.springframework.stereotype.Repository;
9   -
10   -import java.sql.Connection;
11   -import java.util.List;
12   -
13   -/**
14   - * {@link DatabaseTableDAO} 的 MySQL 实现类
15   - *
16   - * @author 芋道源码
17   - */
18   -@Repository
19   -public class DatabaseTableMySQLDAOImpl implements DatabaseTableDAO {
20   -
21   - @Override
22   - public List<DatabaseTableDO> selectTableList(Connection connection, String tableNameLike, String tableCommentLike) {
23   - // 拼接 SQL
24   - String sql = "SELECT table_name, table_comment, create_time" +
25   - " FROM information_schema.TABLES" +
26   - " WHERE table_schema = (SELECT DATABASE())";
27   - if (StrUtil.isNotEmpty(tableNameLike)) {
28   - sql += StrUtil.format(" AND table_name LIKE '%{}%'", tableNameLike);
29   - }
30   - if (StrUtil.isNotEmpty(tableCommentLike)) {
31   - sql += StrUtil.format(" AND table_comment LIKE '%{}%'", tableCommentLike);
32   - }
33   - // 执行并返回结果
34   - return JdbcUtils.query(connection, sql, (rs, rowNum) -> DatabaseTableDO.builder()
35   - .tableName(rs.getString("table_name"))
36   - .tableComment(rs.getString("table_comment"))
37   - .createTime(rs.getDate("create_time"))
38   - .build());
39   - }
40   -
41   - @Override
42   - public List<DatabaseColumnDO> selectColumnList(Connection connection, String tableName) {
43   - // 拼接 SQL
44   - String sql = "SELECT table_name, column_name, data_type, column_comment, ordinal_position," +
45   - " (CASE WHEN is_nullable = 'yes' THEN '1' ELSE '0' END) AS nullable," +
46   - " (CASE WHEN column_key = 'PRI' THEN '1' ELSE '0' END) AS primary_key," +
47   - " (CASE WHEN extra = 'auto_increment' THEN '1' ELSE '0' END) AS auto_increment" +
48   - " FROM information_schema.COLUMNS" +
49   - " WHERE table_schema = (SELECT DATABASE())" +
50   - String.format(" AND table_name = '%s'", tableName);
51   - // 执行并返回结果
52   - return JdbcUtils.query(connection, sql, (rs, rowNum) -> DatabaseColumnDO.builder()
53   - .tableName(rs.getString("table_name"))
54   - .columnName(rs.getString("column_name"))
55   - .dataType(rs.getString("data_type"))
56   - .columnComment(rs.getString("column_comment"))
57   - .nullable(rs.getBoolean("nullable"))
58   - .primaryKey(rs.getBoolean("primary_key"))
59   - .autoIncrement(rs.getBoolean("auto_increment"))
60   - .ordinalPosition(rs.getInt("ordinal_position"))
61   - .build());
62   - }
63   -
64   - @Override
65   - public DbType getType() {
66   - return DbType.MYSQL;
67   - }
68   -
69   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DatabaseTableOracleDAOImpl.java deleted
1   -package cn.iocoder.yudao.module.infra.dal.mysql.db;
2   -
3   -import cn.hutool.core.util.StrUtil;
4   -import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils;
5   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseColumnDO;
6   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
7   -import com.baomidou.mybatisplus.annotation.DbType;
8   -import org.springframework.stereotype.Repository;
9   -
10   -import java.sql.Connection;
11   -import java.util.List;
12   -
13   -/**
14   - * {@link DatabaseTableDAO} 的 Oracle 实现类
15   - *
16   - * @author 芋道源码
17   - */
18   -@Repository
19   -public class DatabaseTableOracleDAOImpl implements DatabaseTableDAO {
20   -
21   - @Override
22   - public List<DatabaseTableDO> selectTableList(Connection connection, String tableNameLike, String tableCommentLike) {
23   - // 拼接 SQL
24   - String sql = "SELECT tbl.table_name, col.comments, obj.created" +
25   - " FROM user_tables tbl, user_tab_comments col, user_objects obj" +
26   - " WHERE tbl.table_name = col.table_name" +
27   - " AND tbl.table_name = obj.object_name" +
28   - " AND obj.object_type = 'TABLE'";
29   - if (StrUtil.isNotEmpty(tableNameLike)) {
30   - sql += StrUtil.format(" AND tbl.table_name LIKE '%{}%'", tableNameLike);
31   - }
32   - if (StrUtil.isNotEmpty(tableCommentLike)) {
33   - sql += StrUtil.format(" AND col.comments LIKE '%{}%'", tableCommentLike);
34   - }
35   - // 执行并返回结果
36   - return JdbcUtils.query(connection, sql, (rs, rowNum) -> DatabaseTableDO.builder()
37   - .tableName(rs.getString("table_name"))
38   - .tableComment(rs.getString("comments"))
39   - .createTime(rs.getDate("created"))
40   - .build());
41   - }
42   -
43   - @Override
44   - public List<DatabaseColumnDO> selectColumnList(Connection connection, String tableName) {
45   - // 拼接 SQL
46   - String sql = String.format("SELECT table_name, column_name, data_type, comments, column_id," +
47   - " (CASE WHEN nullable = 'Y' THEN '1' ELSE '0' END) AS nullable," +
48   - " (CASE WHEN constraint_type = 'P' THEN '1' ELSE '0' END) AS primary_key" +
49   - " FROM" +
50   - " (" +
51   - " SELECT col.*, comments, constraint_type," +
52   - " row_number ( ) over ( partition BY col.column_name ORDER BY constraint_type DESC ) AS row_flag" +
53   - " FROM user_tab_columns col" +
54   - " LEFT JOIN user_col_comments ON user_col_comments.table_name = col.table_name" +
55   - " AND user_col_comments.column_name = col.column_name" +
56   - " LEFT JOIN user_cons_columns ON user_cons_columns.table_name = col.table_name" +
57   - " AND user_cons_columns.column_name = col.column_name" +
58   - " LEFT JOIN user_constraints ON user_constraints.constraint_name = user_cons_columns.constraint_name" +
59   - " WHERE col.table_name = '%s'" +
60   - " )" +
61   - "WHERE row_flag = 1", tableName);
62   - // 执行并返回结果
63   - return JdbcUtils.query(connection, sql, (rs, rowNum) -> DatabaseColumnDO.builder()
64   - .tableName(rs.getString("table_name"))
65   - .columnName(rs.getString("column_name"))
66   - .dataType(rs.getString("data_type"))
67   - .columnComment(rs.getString("comments"))
68   - .nullable(rs.getBoolean("nullable"))
69   - .primaryKey(rs.getBoolean("primary_key"))
70   - .autoIncrement(false) // TODO 芋艿:oracle???
71   - .ordinalPosition(rs.getInt("column_id"))
72   - .build());
73   - }
74   -
75   - @Override
76   - public DbType getType() {
77   - return DbType.ORACLE;
78   - }
79   -
80   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DatabaseTablePostgreSQLDAOImpl.java deleted
1   -package cn.iocoder.yudao.module.infra.dal.mysql.db;
2   -
3   -import cn.hutool.core.util.StrUtil;
4   -import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils;
5   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseColumnDO;
6   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
7   -import com.baomidou.mybatisplus.annotation.DbType;
8   -import org.springframework.stereotype.Repository;
9   -
10   -import java.sql.Connection;
11   -import java.util.List;
12   -
13   -/**
14   - * {@link DatabaseTableDAO} 的 PostgreSQL 实现类
15   - *
16   - * @author 芋道源码
17   - */
18   -@Repository
19   -public class DatabaseTablePostgreSQLDAOImpl implements DatabaseTableDAO {
20   -
21   - @Override
22   - public List<DatabaseTableDO> selectTableList(Connection connection, String tableNameLike, String tableCommentLike) {
23   - // 拼接 SQL
24   - String sql = "SELECT tbl.tablename, obj_description(c.oid)" +
25   - " FROM pg_tables tbl, pg_class c" +
26   - " WHERE tbl.schemaname = CURRENT_SCHEMA()" +
27   - " AND tbl.tablename = c.relname";
28   - if (StrUtil.isNotEmpty(tableNameLike)) {
29   - sql += StrUtil.format(" AND tbl.tablename LIKE '%{}%'", tableNameLike);
30   - }
31   - if (StrUtil.isNotEmpty(tableCommentLike)) {
32   - sql += StrUtil.format(" AND obj_description(c.oid) LIKE '%{}%'", tableCommentLike);
33   - }
34   - // 执行并返回结果
35   - return JdbcUtils.query(connection, sql, (rs, rowNum) -> DatabaseTableDO.builder()
36   - .tableName(rs.getString("tablename"))
37   - .tableComment(rs.getString("obj_description"))
38   - .build());
39   - }
40   -
41   - @Override
42   - public List<DatabaseColumnDO> selectColumnList(Connection connection, String tableName) {
43   - // 拼接 SQL
44   - String sql = "SELECT table_name, column_name, data_type, column_comment, ordinal_position," +
45   - " (CASE WHEN is_nullable = 'yes' THEN '1' ELSE '0' END) AS nullable," +
46   - " (CASE WHEN column_key = 'PRI' THEN '1' ELSE '0' END) AS primary_key," +
47   - " (CASE WHEN extra = 'auto_increment' THEN '1' ELSE '0' END) AS auto_increment" +
48   - " FROM information_schema.COLUMNS" +
49   - " WHERE table_schema = (SELECT DATABASE())" +
50   - String.format(" AND table_name = '%s'", tableName);
51   - // 执行并返回结果
52   - return JdbcUtils.query(connection, sql, (rs, rowNum) -> DatabaseColumnDO.builder()
53   - .tableName(rs.getString("table_name"))
54   - .columnName(rs.getString("column_name"))
55   - .dataType(rs.getString("data_type"))
56   - .columnComment(rs.getString("column_comment"))
57   - .nullable(rs.getBoolean("nullable"))
58   - .primaryKey(rs.getBoolean("primary_key"))
59   - .autoIncrement(rs.getBoolean("auto_increment"))
60   - .ordinalPosition(rs.getInt("ordinal_position"))
61   - .build());
62   - }
63   -
64   - @Override
65   - public DbType getType() {
66   - return DbType.MYSQL;
67   - }
68   -
69   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenImportTypeEnum.java deleted
1   -package cn.iocoder.yudao.module.infra.enums.codegen;
2   -
3   -import lombok.AllArgsConstructor;
4   -import lombok.Getter;
5   -
6   -/**
7   - * 代码生成的导入类型
8   - *
9   - * @author 芋道源码
10   - */
11   -@AllArgsConstructor
12   -@Getter
13   -public enum CodegenImportTypeEnum {
14   -
15   - DB(1), // 从 information_schema 的 table 和 columns 表导入
16   - SQL(2); // 基于建表 SQL 语句导入
17   -
18   - /**
19   - * 类型
20   - */
21   - private final Integer type;
22   -
23   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenService.java
1 1 package cn.iocoder.yudao.module.infra.service.codegen;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
4 5 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
5 6 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
  7 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
6 8 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
7 9 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
8   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
9 10  
10 11 import java.util.List;
11 12 import java.util.Map;
... ... @@ -18,31 +19,13 @@ import java.util.Map;
18 19 public interface CodegenService {
19 20  
20 21 /**
21   - * 基于 SQL 建表语句,创建代码生成器的表定义
22   - *
23   - * @param userId 用户编号
24   - * @param sql SQL 建表语句
25   - * @return 创建的表定义的编号
26   - */
27   - Long createCodegenListFromSQL(Long userId, String sql);
28   -
29   - /**
30 22 * 基于数据库的表结构,创建代码生成器的表定义
31 23 *
32 24 * @param userId 用户编号
33   - * @param tableName 表名称
34   - * @return 创建的表定义的编号
35   - */
36   - Long createCodegen(Long userId, String tableName);
37   -
38   - /**
39   - * 基于 {@link #createCodegen(Long, String)} 的批量创建
40   - *
41   - * @param userId 用户编号
42   - * @param tableNames 表名称数组
  25 + * @param reqVO 表信息
43 26 * @return 创建的表定义的编号数组
44 27 */
45   - List<Long> createCodegenListFromDB(Long userId, List<String> tableNames);
  28 + List<Long> createCodegenList(Long userId, CodegenCreateListReqVO reqVO);
46 29  
47 30 /**
48 31 * 更新数据库的表和字段定义
... ... @@ -59,14 +42,6 @@ public interface CodegenService {
59 42 void syncCodegenFromDB(Long tableId);
60 43  
61 44 /**
62   - * 基于 SQL 建表语句,同步数据库的表和字段定义
63   - *
64   - * @param tableId 表编号
65   - * @param sql SQL 建表语句
66   - */
67   - void syncCodegenFromSQL(Long tableId, String sql);
68   -
69   - /**
70 45 * 删除数据库的表和字段定义
71 46 *
72 47 * @param tableId 数据编号
... ... @@ -90,13 +65,6 @@ public interface CodegenService {
90 65 CodegenTableDO getCodegenTablePage(Long id);
91 66  
92 67 /**
93   - * 获得全部表定义
94   - *
95   - * @return 表定义数组
96   - */
97   - List<CodegenTableDO> getCodeGenTableList();
98   -
99   - /**
100 68 * 获得指定表的字段定义数组
101 69 *
102 70 * @param tableId 表编号
... ... @@ -116,11 +84,11 @@ public interface CodegenService {
116 84 * 获得数据库自带的表定义列表
117 85 *
118 86 *
119   - * @param dataSourceConfigId
120   - * @param tableName 表名称
121   - * @param tableComment 表描述
  87 + * @param dataSourceConfigId 数据源的配置编号
  88 + * @param name 表名称
  89 + * @param comment 表描述
122 90 * @return 表定义列表
123 91 */
124   - List<DatabaseTableDO> getSchemaTableList(Long dataSourceConfigId, String tableName, String tableComment);
  92 + List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment);
125 93  
126 94 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java
... ... @@ -3,22 +3,21 @@ package cn.iocoder.yudao.module.infra.service.codegen;
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  6 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
6 7 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
7 8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
8 10 import cn.iocoder.yudao.module.infra.convert.codegen.CodegenConvert;
9 11 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
10 12 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
11   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseColumnDO;
12   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
13 13 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
14 14 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper;
15   -import cn.iocoder.yudao.module.infra.enums.codegen.CodegenImportTypeEnum;
16 15 import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
17 16 import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
18   -import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenSQLParser;
19 17 import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
20 18 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
21   -import org.apache.commons.collections4.KeyValue;
  19 +import com.baomidou.mybatisplus.generator.config.po.TableField;
  20 +import com.baomidou.mybatisplus.generator.config.po.TableInfo;
22 21 import org.springframework.stereotype.Service;
23 22 import org.springframework.transaction.annotation.Transactional;
24 23  
... ... @@ -56,66 +55,48 @@ public class CodegenServiceImpl implements CodegenService {
56 55 @Resource
57 56 private CodegenEngine codegenEngine;
58 57  
59   - private Long createCodegen0(Long userId, CodegenImportTypeEnum importType,
60   - DatabaseTableDO schemaTable, List<DatabaseColumnDO> schemaColumns) {
  58 + @Override
  59 + @Transactional(rollbackFor = Exception.class)
  60 + public List<Long> createCodegenList(Long userId, CodegenCreateListReqVO reqVO) {
  61 + List<Long> ids = new ArrayList<>(reqVO.getTableNames().size());
  62 + // 遍历添加。虽然效率会低一点,但是没必要做成完全批量,因为不会这么大量
  63 + reqVO.getTableNames().forEach(tableName -> ids.add(createCodegen(userId, reqVO.getDataSourceConfigId(), tableName)));
  64 + return ids;
  65 + }
  66 +
  67 + public Long createCodegen(Long userId, Long dataSourceConfigId, String tableName) {
  68 + // 从数据库中,获得数据库表结构
  69 + TableInfo tableInfo = databaseTableService.getTable(dataSourceConfigId, tableName);
  70 + // 导入
  71 + return createCodegen0(userId, dataSourceConfigId, tableInfo);
  72 + }
  73 +
  74 + private Long createCodegen0(Long userId, Long dataSourceConfigId, TableInfo tableInfo) {
61 75 // 校验导入的表和字段非空
62   - if (schemaTable == null) {
  76 + if (tableInfo == null) {
63 77 throw exception(CODEGEN_IMPORT_TABLE_NULL);
64 78 }
65   - if (CollUtil.isEmpty(schemaColumns)) {
  79 + if (CollUtil.isEmpty(tableInfo.getFields())) {
66 80 throw exception(CODEGEN_IMPORT_COLUMNS_NULL);
67 81 }
68 82 // 校验是否已经存在
69   - if (codegenTableMapper.selectByTableName(schemaTable.getTableName()) != null) {
  83 + if (codegenTableMapper.selectByTableNameAndDataSourceConfigId(tableInfo.getName(),
  84 + dataSourceConfigId) != null) {
70 85 throw exception(CODEGEN_TABLE_EXISTS);
71 86 }
72 87  
73 88 // 构建 CodegenTableDO 对象,插入到 DB 中
74   - CodegenTableDO table = codegenBuilder.buildTable(schemaTable);
75   - table.setImportType(importType.getType());
  89 + CodegenTableDO table = codegenBuilder.buildTable(tableInfo);
  90 + table.setDataSourceConfigId(dataSourceConfigId);
76 91 table.setAuthor(userApi.getUser(userId).getNickname());
77 92 codegenTableMapper.insert(table);
78 93 // 构建 CodegenColumnDO 数组,插入到 DB 中
79   - List<CodegenColumnDO> columns = codegenBuilder.buildColumns(table.getId(), schemaColumns);
  94 + List<CodegenColumnDO> columns = codegenBuilder.buildColumns(table.getId(), tableInfo.getFields());
80 95 codegenColumnMapper.insertBatch(columns);
81 96 return table.getId();
82 97 }
83 98  
84 99 @Override
85   - public Long createCodegenListFromSQL(Long userId, String sql) {
86   - // 从 SQL 中,获得数据库表结构
87   - DatabaseTableDO schemaTable;
88   - List<DatabaseColumnDO> schemaColumns;
89   - try {
90   - KeyValue<DatabaseTableDO, List<DatabaseColumnDO>> result = CodegenSQLParser.parse(sql);
91   - schemaTable = result.getKey();
92   - schemaColumns = result.getValue();
93   - } catch (Exception ex) {
94   - throw exception(CODEGEN_PARSE_SQL_ERROR);
95   - }
96   - // 导入
97   - return this.createCodegen0(userId, CodegenImportTypeEnum.SQL, schemaTable, schemaColumns);
98   - }
99   -
100   - @Override
101   - public Long createCodegen(Long userId, String tableName) {
102   - // 从数据库中,获得数据库表结构
103   - DatabaseTableDO schemaTable = databaseTableService.getTable(9L, tableName);
104   - List<DatabaseColumnDO> schemaColumns = databaseTableService.getColumnList(9L, tableName);
105   - // 导入
106   - return this.createCodegen0(userId, CodegenImportTypeEnum.DB, schemaTable, schemaColumns);
107   - }
108   -
109   - @Override
110   - @Transactional(rollbackFor = Exception.class)
111   - public List<Long> createCodegenListFromDB(Long userId, List<String> tableNames) {
112   - List<Long> ids = new ArrayList<>(tableNames.size());
113   - // 遍历添加。虽然效率会低一点,但是没必要做成完全批量,因为不会这么大量
114   - tableNames.forEach(tableName -> ids.add(createCodegen(userId, tableName)));
115   - return ids;
116   - }
117   -
118   - @Override
119 100 @Transactional(rollbackFor = Exception.class)
120 101 public void updateCodegen(CodegenUpdateReqVO updateReqVO) {
121 102 // 校验是否已经存在
... ... @@ -140,54 +121,33 @@ public class CodegenServiceImpl implements CodegenService {
140 121 throw exception(CODEGEN_TABLE_NOT_EXISTS);
141 122 }
142 123 // 从数据库中,获得数据库表结构
143   - List<DatabaseColumnDO> schemaColumns = databaseTableService.getColumnList(0L, table.getTableName());
144   -
  124 + TableInfo tableInfo = databaseTableService.getTable(table.getDataSourceConfigId(), table.getTableName());
145 125 // 执行同步
146   - this.syncCodegen0(tableId, schemaColumns);
  126 + syncCodegen0(tableId, tableInfo);
147 127 }
148 128  
149   - @Override
150   - @Transactional(rollbackFor = Exception.class)
151   - public void syncCodegenFromSQL(Long tableId, String sql) {
152   - // 校验是否已经存在
153   - CodegenTableDO table = codegenTableMapper.selectById(tableId);
154   - if (table == null) {
155   - throw exception(CODEGEN_TABLE_NOT_EXISTS);
156   - }
157   - // 从 SQL 中,获得数据库表结构
158   - List<DatabaseColumnDO> schemaColumns;
159   - try {
160   - KeyValue<DatabaseTableDO, List<DatabaseColumnDO>> result = CodegenSQLParser.parse(sql);
161   - schemaColumns = result.getValue();
162   - } catch (Exception ex) {
163   - throw exception(CODEGEN_PARSE_SQL_ERROR);
164   - }
165   -
166   - // 执行同步
167   - this.syncCodegen0(tableId, schemaColumns);
168   - }
169   -
170   - private void syncCodegen0(Long tableId, List<DatabaseColumnDO> schemaColumns) {
  129 + private void syncCodegen0(Long tableId, TableInfo tableInfo) {
171 130 // 校验导入的字段不为空
172   - if (CollUtil.isEmpty(schemaColumns)) {
  131 + List<TableField> tableFields = tableInfo.getFields();
  132 + if (CollUtil.isEmpty(tableFields)) {
173 133 throw exception(CODEGEN_SYNC_COLUMNS_NULL);
174 134 }
175   - Set<String> schemaColumnNames = CollectionUtils.convertSet(schemaColumns, DatabaseColumnDO::getColumnName);
  135 + Set<String> tableFieldNames = CollectionUtils.convertSet(tableFields, TableField::getName);
176 136  
177 137 // 构建 CodegenColumnDO 数组,只同步新增的字段
178 138 List<CodegenColumnDO> codegenColumns = codegenColumnMapper.selectListByTableId(tableId);
179 139 Set<String> codegenColumnNames = CollectionUtils.convertSet(codegenColumns, CodegenColumnDO::getColumnName);
180 140 // 移除已经存在的字段
181   - schemaColumns.removeIf(column -> codegenColumnNames.contains(column.getColumnName()));
  141 + tableFields.removeIf(column -> codegenColumnNames.contains(column.getColumnName()));
182 142 // 计算需要删除的字段
183   - Set<Long> deleteColumnIds = codegenColumns.stream().filter(column -> !schemaColumnNames.contains(column.getColumnName()))
  143 + Set<Long> deleteColumnIds = codegenColumns.stream().filter(column -> !tableFieldNames.contains(column.getColumnName()))
184 144 .map(CodegenColumnDO::getId).collect(Collectors.toSet());
185   - if (CollUtil.isEmpty(schemaColumns) && CollUtil.isEmpty(deleteColumnIds)) {
  145 + if (CollUtil.isEmpty(tableFields) && CollUtil.isEmpty(deleteColumnIds)) {
186 146 throw exception(CODEGEN_SYNC_NONE_CHANGE);
187 147 }
188 148  
189 149 // 插入新增的字段
190   - List<CodegenColumnDO> columns = codegenBuilder.buildColumns(tableId, schemaColumns);
  150 + List<CodegenColumnDO> columns = codegenBuilder.buildColumns(tableId, tableFields);
191 151 codegenColumnMapper.insertBatch(columns);
192 152 // 删除不存在的字段
193 153 if (CollUtil.isNotEmpty(deleteColumnIds)) {
... ... @@ -220,11 +180,6 @@ public class CodegenServiceImpl implements CodegenService {
220 180 }
221 181  
222 182 @Override
223   - public List<CodegenTableDO> getCodeGenTableList() {
224   - return codegenTableMapper.selectList();
225   - }
226   -
227   - @Override
228 183 public List<CodegenColumnDO> getCodegenColumnListByTableId(Long tableId) {
229 184 return codegenColumnMapper.selectListByTableId(tableId);
230 185 }
... ... @@ -246,13 +201,18 @@ public class CodegenServiceImpl implements CodegenService {
246 201 }
247 202  
248 203 @Override
249   - public List<DatabaseTableDO> getSchemaTableList(Long dataSourceConfigId, String tableName, String tableComment) {
250   - List<DatabaseTableDO> tables = databaseTableService.getTableList(dataSourceConfigId, tableName, tableComment);
251   - // TODO 强制移除 Quartz 的表,未来做成可配置
252   - tables.removeIf(table -> table.getTableName().startsWith("QRTZ_"));
253   - tables.removeIf(table -> table.getTableName().startsWith("ACT_"));
254   - tables.removeIf(table -> table.getTableName().startsWith("FLW_"));
255   - return tables;
  204 + public List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment) {
  205 + List<TableInfo> tables = databaseTableService.getTableList(dataSourceConfigId, name, comment);
  206 + // 移除置顶前缀的表名 // TODO 未来做成可配置
  207 + tables.removeIf(table -> table.getName().startsWith("QRTZ_"));
  208 + tables.removeIf(table -> table.getName().startsWith("ACT_"));
  209 + tables.removeIf(table -> table.getName().startsWith("FLW_"));
  210 + // 移除已经生成的表
  211 + // 移除在 Codegen 中,已经存在的
  212 + Set<String> existsTables = CollectionUtils.convertSet(
  213 + codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId), CodegenTableDO::getTableName);
  214 + tables.removeIf(table -> existsTables.contains(table.getName()));
  215 + return CodegenConvert.INSTANCE.convertList04(tables);
256 216 }
257 217  
258 218 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilder.java
... ... @@ -7,23 +7,22 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
7 7 import cn.iocoder.yudao.module.infra.convert.codegen.CodegenConvert;
8 8 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
9 9 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
10   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseColumnDO;
11   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
12 10 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnHtmlTypeEnum;
13 11 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnListConditionEnum;
14 12 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
  13 +import com.baomidou.mybatisplus.generator.config.po.TableField;
  14 +import com.baomidou.mybatisplus.generator.config.po.TableInfo;
15 15 import com.google.common.collect.Sets;
16 16 import org.springframework.stereotype.Component;
17 17  
18   -import java.math.BigDecimal;
19 18 import java.util.*;
20 19  
21 20 import static cn.hutool.core.text.CharSequenceUtil.*;
22 21  
23 22 /**
24 23 * 代码生成器的 Builder,负责:
25   - * 1. 将数据库的表 {@link DatabaseTableDO} 定义,构建成 {@link CodegenTableDO}
26   - * 2. 将数据库的列 {@link DatabaseColumnDO} 构定义,建成 {@link CodegenColumnDO}
  24 + * 1. 将数据库的表 {@link TableInfo} 定义,构建成 {@link CodegenTableDO}
  25 + * 2. 将数据库的列 {@link TableField} 构定义,建成 {@link CodegenColumnDO}
27 26 */
28 27 @Component
29 28 public class CodegenBuilder {
... ... @@ -82,24 +81,6 @@ public class CodegenBuilder {
82 81 */
83 82 private static final Set<String> LIST_OPERATION_RESULT_EXCLUDE_COLUMN = Sets.newHashSet();
84 83  
85   - /**
86   - * Java 类型与 MySQL 类型的映射关系
87   - */
88   - private static final Map<String, Set<String>> javaTypeMappings = MapUtil.<String, Set<String>>builder()
89   - .put(Boolean.class.getSimpleName(), Sets.newHashSet("bit"))
90   - .put(Integer.class.getSimpleName(), Sets.newHashSet(
91   - "tinyint", "smallint", "mediumint", "int", "integer"))
92   - .put(Long.class.getSimpleName(), Sets.newHashSet("bigint", "number"))
93   - .put(Double.class.getSimpleName(), Sets.newHashSet("float", "double"))
94   - .put(BigDecimal.class.getSimpleName(), Sets.newHashSet("decimal", "numeric"))
95   - .put(String.class.getSimpleName(), Sets.newHashSet(
96   - "tinytext", "text", "mediumtext", "longtext", "nclob", // 长文本
97   - "char", "varchar", "nvarchar", "varchar2", "nvarchar2", // 短文本
98   - "json")) // 特殊文本
99   - .put(Date.class.getSimpleName(), Sets.newHashSet("datetime", "time", "date", "timestamp"))
100   - .put("byte[]", Sets.newHashSet("blob"))
101   - .build();
102   -
103 84 static {
104 85 Arrays.stream(ReflectUtil.getFields(BaseDO.class)).forEach(field -> BASE_DO_FIELDS.add(field.getName()));
105 86 BASE_DO_FIELDS.add(TENANT_ID_FIELD);
... ... @@ -112,8 +93,8 @@ public class CodegenBuilder {
112 93 LIST_OPERATION_RESULT_EXCLUDE_COLUMN.remove("createTime"); // 创建时间,还是需要返回的
113 94 }
114 95  
115   - public CodegenTableDO buildTable(DatabaseTableDO schemaTable) {
116   - CodegenTableDO table = CodegenConvert.INSTANCE.convert(schemaTable);
  96 + public CodegenTableDO buildTable(TableInfo tableInfo) {
  97 + CodegenTableDO table = CodegenConvert.INSTANCE.convert(tableInfo);
117 98 initTableDefault(table);
118 99 return table;
119 100 }
... ... @@ -136,43 +117,19 @@ public class CodegenBuilder {
136 117 table.setTemplateType(CodegenTemplateTypeEnum.CRUD.getType());
137 118 }
138 119  
139   - public List<CodegenColumnDO> buildColumns(Long tableId, List<DatabaseColumnDO> schemaColumns) {
140   - List<CodegenColumnDO> columns = CodegenConvert.INSTANCE.convertList(schemaColumns);
  120 + public List<CodegenColumnDO> buildColumns(Long tableId, List<TableField> tableFields) {
  121 + List<CodegenColumnDO> columns = CodegenConvert.INSTANCE.convertList(tableFields);
  122 + int index = 1;
141 123 for (CodegenColumnDO column : columns) {
142 124 column.setTableId(tableId);
143   - initColumnDefault(column);
  125 + column.setOrdinalPosition(index++);
  126 + // 初始化 Column 列的默认字段
  127 + processColumnOperation(column); // 处理 CRUD 相关的字段的默认值
  128 + processColumnUI(column); // 处理 UI 相关的字段的默认值
144 129 }
145 130 return columns;
146 131 }
147 132  
148   - /**
149   - * 初始化 Column 列的默认字段
150   - *
151   - * @param column 列定义
152   - */
153   - private void initColumnDefault(CodegenColumnDO column) {
154   - // 处理 Java 相关的字段的默认值
155   - processColumnJava(column);
156   - // 处理 CRUD 相关的字段的默认值
157   - processColumnOperation(column);
158   - // 处理 UI 相关的字段的默认值
159   - processColumnUI(column);
160   - }
161   -
162   - private void processColumnJava(CodegenColumnDO column) {
163   - // 处理 javaField 字段
164   - column.setJavaField(toCamelCase(column.getColumnName()));
165   - // 处理 dataType 字段
166   - String dataType = column.getDataType().toLowerCase();
167   - javaTypeMappings.entrySet().stream()
168   - .filter(entry -> entry.getValue().contains(dataType))
169   - .findFirst().ifPresent(entry -> column.setJavaType(entry.getKey()));
170   - if (column.getJavaType() == null) {
171   - throw new IllegalStateException(String.format("column(%s) 的数据库类型(%s) 找不到匹配的 Java 类型",
172   - column.getColumnName(), column.getJavaType()));
173   - }
174   - }
175   -
176 133 private void processColumnOperation(CodegenColumnDO column) {
177 134 // 处理 createOperation 字段
178 135 column.setCreateOperation(!CREATE_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField())
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenSQLParser.java deleted
1   -package cn.iocoder.yudao.module.infra.service.codegen.inner;
2   -
3   -import cn.hutool.core.collection.CollUtil;
4   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseColumnDO;
5   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
6   -import com.alibaba.druid.DbType;
7   -import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
8   -import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
9   -import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
10   -import com.alibaba.druid.sql.ast.statement.SQLPrimaryKey;
11   -import com.alibaba.druid.sql.ast.statement.SQLTableElement;
12   -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
13   -import com.alibaba.druid.sql.repository.SchemaRepository;
14   -import org.apache.commons.collections4.KeyValue;
15   -import org.apache.commons.collections4.keyvalue.DefaultKeyValue;
16   -
17   -import java.util.ArrayList;
18   -import java.util.List;
19   -import java.util.Objects;
20   -
21   -import static com.alibaba.druid.sql.SQLUtils.normalize;
22   -
23   -/**
24   - * SQL 解析器,将创建表的 SQL,解析成 {@link DatabaseTableDO} 和 {@link DatabaseColumnDO} 对象,
25   - * 后续可以基于它们,生成代码~
26   - *
27   - * @author 芋道源码
28   - */
29   -public class CodegenSQLParser {
30   -
31   - /**
32   - * 解析建表 SQL 语句,返回 {@link DatabaseTableDO} 和 {@link DatabaseColumnDO} 对象
33   - *
34   - * @param sql 建表 SQL 语句
35   - * @return 解析结果
36   - */
37   - public static KeyValue<DatabaseTableDO, List<DatabaseColumnDO>> parse(String sql) {
38   - // 解析 SQL 成 Statement
39   - SQLCreateTableStatement statement = parseCreateSQL(sql);
40   - // 解析 Table 表
41   - DatabaseTableDO table = parseTable(statement);
42   - // 解析 Column 字段
43   - List<DatabaseColumnDO> columns = parseColumns(statement);
44   - columns.forEach(column -> column.setTableName(table.getTableName()));
45   - // 返回
46   - return new DefaultKeyValue<>(table, columns);
47   - }
48   -
49   - /**
50   - * 使用 Druid 工具,建表 SQL 语句
51   - *
52   - * @param sql 建表 SQL 语句
53   - * @return 创建 Statement
54   - */
55   - private static SQLCreateTableStatement parseCreateSQL(String sql) {
56   - // 解析 SQL
57   - SchemaRepository repository = new SchemaRepository(DbType.mysql);
58   - repository.console(sql);
59   - // 获得该表对应的 MySqlCreateTableStatement 对象
60   - String tableName = CollUtil.getFirst(repository.getDefaultSchema().getObjects()).getName();
61   - return (MySqlCreateTableStatement) repository.findTable(tableName).getStatement();
62   - }
63   -
64   - private static DatabaseTableDO parseTable(SQLCreateTableStatement statement) {
65   - return DatabaseTableDO.builder()
66   - .tableName(statement.getTableSource().getTableName(true))
67   - .tableComment(getCommentText(statement))
68   - .build();
69   - }
70   -
71   - private static String getCommentText(SQLCreateTableStatement statement) {
72   - if (statement == null || statement.getComment() == null) {
73   - return "";
74   - }
75   - return ((SQLCharExpr) statement.getComment()).getText();
76   - }
77   -
78   - private static List<DatabaseColumnDO> parseColumns(SQLCreateTableStatement statement) {
79   - List<DatabaseColumnDO> columns = new ArrayList<>();
80   - statement.getTableElementList().forEach(element -> parseColumn(columns, element));
81   - return columns;
82   - }
83   -
84   - private static void parseColumn(List<DatabaseColumnDO> columns, SQLTableElement element) {
85   - // 处理主键
86   - if (element instanceof SQLPrimaryKey) {
87   - parsePrimaryKey(columns, (SQLPrimaryKey) element);
88   - return;
89   - }
90   - // 处理字段定义
91   - if (element instanceof SQLColumnDefinition) {
92   - parseColumnDefinition(columns, (SQLColumnDefinition) element);
93   - }
94   - }
95   -
96   - private static void parsePrimaryKey(List<DatabaseColumnDO> columns, SQLPrimaryKey primaryKey) {
97   - String columnName = normalize(primaryKey.getColumns().get(0).toString()); // 暂时不考虑联合主键
98   - // 匹配 columns 主键字段,设置为 primary
99   - columns.stream().filter(column -> column.getColumnName().equals(columnName))
100   - .forEach(column -> column.setPrimaryKey(true));
101   - }
102   -
103   - private static void parseColumnDefinition(List<DatabaseColumnDO> columns, SQLColumnDefinition definition) {
104   - String text = definition.toString().toUpperCase();
105   - columns.add(DatabaseColumnDO.builder()
106   - .columnName(normalize(definition.getColumnName()))
107   - .dataType(definition.getDataType().toString())
108   - .columnComment(Objects.isNull(definition.getComment()) ? ""
109   - : normalize(definition.getComment().toString()))
110   - .nullable(!text.contains(" NOT NULL"))
111   - .primaryKey(false)
112   - .autoIncrement(text.contains("AUTO_INCREMENT"))
113   - .ordinalPosition(columns.size() + 1)
114   - .build());
115   - }
116   -
117   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigService.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.infra.service.db;
3 3 import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigCreateReqVO;
4 4 import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigUpdateReqVO;
5 5 import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO;
6   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
7 6  
8 7 import javax.validation.Valid;
9 8 import java.util.List;
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableService.java
1 1 package cn.iocoder.yudao.module.infra.service.db;
2 2  
3   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseColumnDO;
4   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
5 3 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
6 4  
7 5 import java.util.List;
... ... @@ -17,11 +15,11 @@ public interface DatabaseTableService {
17 15 * 获得表列表,基于表名称 + 表描述进行模糊匹配
18 16 *
19 17 * @param dataSourceConfigId 数据源配置的编号
20   - * @param tableNameLike 表名称,模糊匹配
21   - * @param tableCommentLike 表描述,模糊匹配
  18 + * @param nameLike 表名称,模糊匹配
  19 + * @param commentLike 表描述,模糊匹配
22 20 * @return 表列表
23 21 */
24   - List<DatabaseTableDO> getTableList(Long dataSourceConfigId, String tableNameLike, String tableCommentLike);
  22 + List<TableInfo> getTableList(Long dataSourceConfigId, String nameLike, String commentLike);
25 23  
26 24 /**
27 25 * 获得指定表名
... ... @@ -30,35 +28,6 @@ public interface DatabaseTableService {
30 28 * @param tableName 表名称
31 29 * @return 表
32 30 */
33   - DatabaseTableDO getTable(Long dataSourceConfigId, String tableName);
34   -
35   - /**
36   - * 获得指定表的字段列表
37   - *
38   - * @param dataSourceConfigId 数据源配置的编号
39   - * @param tableName 表名称
40   - * @return 字段列表
41   - */
42   - List<DatabaseColumnDO> getColumnList(Long dataSourceConfigId, String tableName);
43   -
44   -
45   - /**
46   - * 获得表列表,基于表名称 + 表描述进行模糊匹配
47   - *
48   - * @param dataSourceConfigId 数据源配置的编号
49   - * @param tableNameLike 表名称,模糊匹配
50   - * @param tableCommentLike 表描述,模糊匹配
51   - * @return 表列表
52   - */
53   - List<TableInfo> getTableList2(Long dataSourceConfigId, String tableNameLike, String tableCommentLike);
54   -
55   - /**
56   - * 获得指定表名
57   - *
58   - * @param dataSourceConfigId 数据源配置的编号
59   - * @param tableName 表名称
60   - * @return 表
61   - */
62   - TableInfo getTable2(Long dataSourceConfigId, String tableName);
  31 + TableInfo getTable(Long dataSourceConfigId, String tableName);
63 32  
64 33 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java
... ... @@ -2,20 +2,20 @@ package cn.iocoder.yudao.module.infra.service.db;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.lang.Assert;
5   -import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils;
  5 +import cn.hutool.core.util.StrUtil;
6 6 import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO;
7   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseColumnDO;
8   -import cn.iocoder.yudao.module.infra.dal.dataobject.db.DatabaseTableDO;
9   -import cn.iocoder.yudao.module.infra.dal.mysql.db.DatabaseTableDAO;
10   -import com.baomidou.mybatisplus.annotation.DbType;
  7 +import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
  8 +import com.baomidou.mybatisplus.generator.config.GlobalConfig;
  9 +import com.baomidou.mybatisplus.generator.config.StrategyConfig;
  10 +import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
11 11 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
12   -import lombok.SneakyThrows;
  12 +import com.baomidou.mybatisplus.generator.config.rules.DateType;
13 13 import org.springframework.stereotype.Service;
14 14  
15 15 import javax.annotation.Resource;
16   -import java.sql.Connection;
17 16 import java.util.Comparator;
18 17 import java.util.List;
  18 +import java.util.stream.Collectors;
19 19  
20 20 /**
21 21 * 数据库表 Service 实现类
... ... @@ -28,61 +28,38 @@ public class DatabaseTableServiceImpl implements DatabaseTableService {
28 28 @Resource
29 29 private DataSourceConfigService dataSourceConfigService;
30 30  
31   - @Resource
32   - private List<DatabaseTableDAO> databaseTableDAOs;
33   -
34   - @Override
35   - @SneakyThrows
36   - public List<DatabaseTableDO> getTableList(Long dataSourceConfigId, String tableNameLike, String tableCommentLike) {
37   - try (Connection connection = getConnection(dataSourceConfigId)) {
38   - return getDatabaseTableDAO(dataSourceConfigId).selectTableList(connection, tableNameLike, tableCommentLike);
39   - }
40   - }
41   -
42   - @Override
43   - @SneakyThrows
44   - public DatabaseTableDO getTable(Long dataSourceConfigId, String tableName) {
45   - try (Connection connection = getConnection(dataSourceConfigId)) {
46   - return getDatabaseTableDAO(dataSourceConfigId).selectTable(connection, tableName);
47   - }
48   - }
49   -
50   - @Override
51   - @SneakyThrows
52   - public List<DatabaseColumnDO> getColumnList(Long dataSourceConfigId, String tableName) {
53   - try (Connection connection = getConnection(dataSourceConfigId)) {
54   - List<DatabaseColumnDO> columns = getDatabaseTableDAO(dataSourceConfigId).selectColumnList(connection, tableName);
55   - columns.sort(Comparator.comparing(DatabaseColumnDO::getOrdinalPosition));
56   - return columns;
57   - }
58   - }
59   -
60 31 @Override
61   - public List<TableInfo> getTableList2(Long dataSourceConfigId, String tableNameLike, String tableCommentLike) {
62   - return null;
  32 + public List<TableInfo> getTableList(Long dataSourceConfigId, String nameLike, String commentLike) {
  33 + List<TableInfo> tables = getTableList0(dataSourceConfigId, null);
  34 + return tables.stream().filter(tableInfo -> (StrUtil.isEmpty(nameLike) || tableInfo.getName().contains(nameLike))
  35 + && (StrUtil.isEmpty(commentLike) || tableInfo.getComment().contains(commentLike)))
  36 + .collect(Collectors.toList());
63 37 }
64 38  
65 39 @Override
66   - public TableInfo getTable2(Long dataSourceConfigId, String tableName) {
67   - return null;
  40 + public TableInfo getTable(Long dataSourceConfigId, String name) {
  41 + return CollUtil.getFirst(getTableList0(dataSourceConfigId, name));
68 42 }
69 43  
70   - private Connection getConnection(Long dataSourceConfigId) {
  44 + public List<TableInfo> getTableList0(Long dataSourceConfigId, String name) {
  45 + // 获得数据源配置
71 46 DataSourceConfigDO config = dataSourceConfigService.getDataSourceConfig(dataSourceConfigId);
72 47 Assert.notNull(config, "数据源({}) 不存在!", dataSourceConfigId);
73   - return JdbcUtils.getConnection(config.getUrl(), config.getUsername(), config.getPassword());
74   - }
75 48  
76   - private DatabaseTableDAO getDatabaseTableDAO(Long dataSourceConfigId) {
77   - DataSourceConfigDO config = dataSourceConfigService.getDataSourceConfig(dataSourceConfigId);
78   - Assert.notNull(config, "数据源({}) 不存在!", dataSourceConfigId);
79   - // 获得 dbType
80   - DbType dbType = JdbcUtils.getDbType(config.getUrl());
81   - Assert.notNull(config, "数据源类型({}) 不存在!", config.getUrl());
82   - // 获得 DatabaseTableDAO
83   - DatabaseTableDAO dao = CollUtil.findOne(databaseTableDAOs, databaseTableDAO -> databaseTableDAO.getType().equals(dbType));
84   - Assert.notNull(dao, "DAO({}) 查找不到实现!", dbType);
85   - return dao;
  49 + // 使用 MyBatis Plus Generator 解析表结构
  50 + DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(config.getUrl(), config.getUsername(),
  51 + config.getPassword()).build();
  52 + StrategyConfig.Builder strategyConfig = new StrategyConfig.Builder();
  53 + if (StrUtil.isNotEmpty(name)) {
  54 + strategyConfig.addInclude(name);
  55 + }
  56 + GlobalConfig globalConfig = new GlobalConfig.Builder().dateType(DateType.ONLY_DATE).build(); // 只使用 Date 类型,不使用 LocalDate
  57 + ConfigBuilder builder = new ConfigBuilder(null, dataSourceConfig, strategyConfig.build(),
  58 + null, globalConfig, null);
  59 + // 按照名字排序
  60 + List<TableInfo> tables = builder.getTableInfoList();
  61 + tables.sort(Comparator.comparing(TableInfo::getName));
  62 + return tables;
86 63 }
87 64  
88 65 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service;
  2 +
  3 +import com.baomidou.mybatisplus.generator.IDatabaseQuery.DefaultDatabaseQuery;
  4 +import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
  5 +import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
  6 +import com.baomidou.mybatisplus.generator.config.po.TableInfo;
  7 +
  8 +import java.util.List;
  9 +
  10 +public class DefaultDatabaseQueryTest {
  11 +
  12 + public static void main(String[] args) {
  13 + DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder("jdbc:oracle:thin:@127.0.0.1:1521:xe",
  14 + "root", "123456").build();
  15 +// StrategyConfig strategyConfig = new StrategyConfig.Builder().build();
  16 +
  17 + ConfigBuilder builder = new ConfigBuilder(null, dataSourceConfig, null, null, null, null);
  18 +
  19 + DefaultDatabaseQuery query = new DefaultDatabaseQuery(builder);
  20 +
  21 + long time = System.currentTimeMillis();
  22 + List<TableInfo> tableInfos = query.queryTables();
  23 + System.out.println(tableInfos.size());
  24 + System.out.println(System.currentTimeMillis() - time);
  25 + }
  26 +
  27 +}
... ...
yudao-ui-admin/src/api/infra/codegen.js
... ... @@ -73,26 +73,11 @@ export function getSchemaTableList(query) {
73 73 }
74 74  
75 75 // 基于数据库的表结构,创建代码生成器的表定义
76   -export function createCodegenListFromDB(tableNames) {
  76 +export function createCodegenList(data) {
77 77 return request({
78   - url: '/infra/codegen/create-list-from-db',
  78 + url: '/infra/codegen/create-list',
79 79 method: 'post',
80   - headers:{
81   - 'Content-type': 'application/x-www-form-urlencoded'
82   - },
83   - data: 'tableNames=' + tableNames
84   - })
85   -}
86   -
87   -// 基于 SQL 建表语句,创建代码生成器的表定义
88   -export function createCodegenListFromSQL(data) {
89   - return request({
90   - url: '/infra/codegen/create-list-from-sql',
91   - method: 'post',
92   - headers:{
93   - 'Content-type': 'application/x-www-form-urlencoded'
94   - },
95   - data: 'sql=' + data.sql,
  80 + data: data
96 81 })
97 82 }
98 83  
... ...
yudao-ui-admin/src/views/infra/codegen/editTable.vue
... ... @@ -19,7 +19,7 @@
19 19 </el-table-column>
20 20 <el-table-column
21 21 label="物理类型"
22   - prop="dateType"
  22 + prop="dataType"
23 23 min-width="10%"
24 24 :show-overflow-tooltip="true"
25 25 />
... ...
yudao-ui-admin/src/views/infra/codegen/importTable.vue
... ... @@ -8,11 +8,11 @@
8 8 :key="config.id" :label="config.name" :value="config.id"/>
9 9 </el-select>
10 10 </el-form-item>
11   - <el-form-item label="表名称" prop="tableName">
12   - <el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable @keyup.enter.native="handleQuery" />
  11 + <el-form-item label="表名称" prop="name">
  12 + <el-input v-model="queryParams.name" placeholder="请输入表名称" clearable @keyup.enter.native="handleQuery" />
13 13 </el-form-item>
14   - <el-form-item label="表描述" prop="tableComment">
15   - <el-input v-model="queryParams.tableComment" placeholder="请输入表描述" clearable @keyup.enter.native="handleQuery"/>
  14 + <el-form-item label="表描述" prop="comment">
  15 + <el-input v-model="queryParams.comment" placeholder="请输入表描述" clearable @keyup.enter.native="handleQuery"/>
16 16 </el-form-item>
17 17 <el-form-item>
18 18 <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
... ... @@ -20,15 +20,11 @@
20 20 </el-form-item>
21 21 </el-form>
22 22 <el-row>
23   - <el-table @row-click="clickRow" ref="table" :data="dbTableList" @selection-change="handleSelectionChange" height="260px">
  23 + <el-table v-loading="loading" @row-click="clickRow" ref="table" :data="dbTableList"
  24 + @selection-change="handleSelectionChange" height="260px">
24 25 <el-table-column type="selection" width="55" />
25   - <el-table-column prop="tableName" label="表名称" :show-overflow-tooltip="true" />
26   - <el-table-column prop="tableComment" label="表描述" :show-overflow-tooltip="true" />
27   - <el-table-column prop="createTime" label="创建时间">
28   - <template slot-scope="scope">
29   - <span>{{ parseTime(scope.row.createTime) }}</span>
30   - </template>
31   - </el-table-column>
  26 + <el-table-column prop="name" label="表名称" :show-overflow-tooltip="true" />
  27 + <el-table-column prop="comment" label="表描述" :show-overflow-tooltip="true" />
32 28 </el-table>
33 29 </el-row>
34 30 <div slot="footer" class="dialog-footer">
... ... @@ -39,12 +35,14 @@
39 35 </template>
40 36  
41 37 <script>
42   -import { getSchemaTableList, createCodegenListFromDB } from "@/api/infra/codegen";
  38 +import { getSchemaTableList, createCodegenList } from "@/api/infra/codegen";
43 39 import {getDataSourceConfigList} from "@/api/infra/dataSourceConfig";
44 40 export default {
45 41 data() {
46 42 return {
47 43 // 遮罩层
  44 + loading: false,
  45 + // 遮罩层
48 46 visible: false,
49 47 // 选中数组值
50 48 tables: [],
... ... @@ -55,8 +53,8 @@ export default {
55 53 // 查询参数
56 54 queryParams: {
57 55 dataSourceConfigId: undefined,
58   - tableName: undefined,
59   - tableComment: undefined,
  56 + name: undefined,
  57 + comment: undefined,
60 58 },
61 59 // 数据源列表
62 60 dataSourceConfigs: [],
... ... @@ -79,12 +77,15 @@ export default {
79 77 },
80 78 // 多选框选中数据
81 79 handleSelectionChange(selection) {
82   - this.tables = selection.map(item => item.tableName);
  80 + this.tables = selection.map(item => item.name);
83 81 },
84 82 // 查询表数据
85 83 getList() {
  84 + this.loading = true;
86 85 getSchemaTableList(this.queryParams).then(res => {
87 86 this.dbTableList = res.data;
  87 + }).finally(() => {
  88 + this.loading = false;
88 89 });
89 90 },
90 91 /** 搜索按钮操作 */
... ... @@ -99,7 +100,10 @@ export default {
99 100 },
100 101 /** 导入按钮操作 */
101 102 handleImportTable() {
102   - createCodegenListFromDB(this.tables.join(",")).then(res => {
  103 + createCodegenList({
  104 + dataSourceConfigId: this.queryParams.dataSourceConfigId,
  105 + tableNames: this.tables
  106 + }).then(res => {
103 107 this.$modal.msgSuccess("导入成功");
104 108 this.visible = false;
105 109 this.$emit("ok");
... ...
yudao-ui-admin/src/views/infra/codegen/index.vue
... ... @@ -26,29 +26,28 @@
26 26 <el-row :gutter="10" class="mb8">
27 27 <el-col :span="1.5">
28 28 <el-button type="info" plain icon="el-icon-upload" size="mini" @click="openImportTable"
29   - v-hasPermi="['infra:codegen:create']">基于 DB 导入</el-button>
30   - <el-button type="info" plain icon="el-icon-upload" size="mini" @click="openImportSQL"
31   - v-hasPermi="['infra:codegen:create']">基于 SQL 导入</el-button>
  29 + v-hasPermi="['infra:codegen:create']">导入</el-button>
32 30 </el-col>
33 31 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
34 32 </el-row>
35 33  
36 34 <!-- 列表 -->
37 35 <el-table v-loading="loading" :data="tableList">
38   - <el-table-column label="表名称" align="center" prop="tableName" :show-overflow-tooltip="true" width="200"/>
  36 + <el-table-column label="数据源" align="center" :formatter="dataSourceConfigNameFormat"/>
  37 + <el-table-column label="表名称" align="center" prop="tableName" width="200"/>
39 38 <el-table-column label="表描述" align="center" prop="tableComment" :show-overflow-tooltip="true" width="120"/>
40   - <el-table-column label="实体" align="center" prop="className" :show-overflow-tooltip="true" width="200"/>
41   - <el-table-column label="创建时间" align="center" prop="createTime" width="160">
  39 + <el-table-column label="实体" align="center" prop="className" width="200"/>
  40 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
42 41 <template slot-scope="scope">
43 42 <span>{{ parseTime(scope.row.createTime) }}</span>
44 43 </template>
45 44 </el-table-column>
46   - <el-table-column label="更新时间" align="center" prop="createTime" width="160">
  45 + <el-table-column label="更新时间" align="center" prop="createTime" width="180">
47 46 <template slot-scope="scope">
48 47 <span>{{ parseTime(scope.row.updateTime) }}</span>
49 48 </template>
50 49 </el-table-column>
51   - <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  50 + <el-table-column label="操作" align="center" width="300px" class-name="small-padding fixed-width">
52 51 <template slot-scope="scope">
53 52 <el-button type="text" size="small" icon="el-icon-view" @click="handlePreview(scope.row)" v-hasPermi="['infra:codegen:preview']">预览</el-button>
54 53 <el-button type="text" size="small" icon="el-icon-edit" @click="handleEditTable(scope.row)" v-hasPermi="['infra:codegen:update']">编辑</el-button>
... ... @@ -81,23 +80,6 @@
81 80  
82 81 <!-- 基于 DB 导入 -->
83 82 <import-table ref="import" @ok="handleQuery" />
84   -
85   - <!-- 基于 SQL 导入 -->
86   - <el-dialog :title="importSQL.title" :visible.sync="importSQL.open" width="800px" append-to-body>
87   - <el-form ref="importSQLForm" :model="importSQL.form" :rules="importSQL.rules" label-width="120px">
88   - <el-row>
89   - <el-col :span="12">
90   - <el-form-item label="建表 SQL 语句" prop="sql">
91   - <el-input v-model="importSQL.form.sql" type="textarea" rows="30" style="width: 650px;" placeholder="请输入建 SQL 语句" />
92   - </el-form-item>
93   - </el-col>
94   - </el-row>
95   - </el-form>
96   - <div slot="footer" class="dialog-footer">
97   - <el-button type="primary" @click="submitImportSQLForm">确 定</el-button>
98   - <el-button @click="cancel">取 消</el-button>
99   - </div>
100   - </el-dialog>
101 83 </div>
102 84 </template>
103 85  
... ... @@ -109,6 +91,7 @@ import importTable from &quot;./importTable&quot;;
109 91 // 代码高亮插件
110 92 import hljs from "highlight.js/lib/highlight";
111 93 import "highlight.js/styles/github-gist.css";
  94 +import {getDataSourceConfigList} from "@/api/infra/dataSourceConfig";
112 95 hljs.registerLanguage("java", require("highlight.js/lib/languages/java"));
113 96 hljs.registerLanguage("xml", require("highlight.js/lib/languages/xml"));
114 97 hljs.registerLanguage("html", require("highlight.js/lib/languages/xml"));
... ... @@ -150,21 +133,16 @@ export default {
150 133 data: {},
151 134 activeName: "",
152 135 },
153   - // 基于 SQL 导入
154   - importSQL: {
155   - open: false,
156   - title: "",
157   - form: {
158   -
159   - },
160   - rules: {
161   - sql: [{ required: true, message: "SQL 不能为空", trigger: "blur" }]
162   - }
163   - }
  136 + // 数据源列表
  137 + dataSourceConfigs: [],
164 138 };
165 139 },
166 140 created() {
167 141 this.getList();
  142 + // 加载数据源
  143 + getDataSourceConfigList().then(response => {
  144 + this.dataSourceConfigs = response.data;
  145 + });
168 146 },
169 147 activated() {
170 148 const time = this.$route.query.t;
... ... @@ -200,12 +178,6 @@ export default {
200 178 },
201 179 /** 同步数据库操作 */
202 180 handleSynchDb(row) {
203   - // 基于 SQL 同步
204   - if (row.importType === 2) {
205   - this.importSQL.open = true;
206   - this.importSQL.form.tableId = row.id;
207   - return;
208   - }
209 181 // 基于 DB 同步
210 182 const tableName = row.tableName;
211 183 this.$modal.confirm('确认要强制同步"' + tableName + '"表结构吗?').then(function() {
... ... @@ -218,10 +190,6 @@ export default {
218 190 openImportTable() {
219 191 this.$refs.import.show();
220 192 },
221   - /** 打开 SQL 导入的弹窗 **/
222   - openImportSQL() {
223   - this.importSQL.open = true;
224   - },
225 193 /** 重置按钮操作 */
226 194 resetQuery() {
227 195 this.dateRange = [];
... ... @@ -336,43 +304,15 @@ export default {
336 304 this.$modal.msgSuccess("删除成功");
337 305 }).catch(() => {});
338 306 },
339   - // 取消按钮
340   - cancel() {
341   - this.importSQL.open = false;
342   - this.reset();
343   - },
344   - // 表单重置
345   - reset() {
346   - this.importSQL.form = {
347   - tableId: undefined,
348   - sql: undefined,
349   - };
350   - this.resetForm("importSQLForm");
351   - },
352   - // 提交 import SQL 表单
353   - submitImportSQLForm() {
354   - this.$refs["importSQLForm"].validate(valid => {
355   - if (!valid) {
356   - return;
357   - }
358   - // 修改的提交
359   - let form = this.importSQL.form;
360   - if (form.tableId != null) {
361   - syncCodegenFromSQL(form.tableId, form.sql).then(response => {
362   - this.$modal.msgSuccess("同步成功");
363   - this.importSQL.open = false;
364   - this.getList();
365   - });
366   - return;
  307 + // 数据源配置的名字
  308 + dataSourceConfigNameFormat(row, column) {
  309 + for (const config of this.dataSourceConfigs) {
  310 + if (row.dataSourceConfigId === config.id) {
  311 + return config.name;
367 312 }
368   - // 添加的提交
369   - createCodegenListFromSQL(form).then(response => {
370   - this.$modal.msgSuccess("导入成功");
371   - this.importSQL.open = false;
372   - this.getList();
373   - });
374   - });
375   - }
  313 + }
  314 + return '未知【' + row.leaderUserId + '】';
  315 + },
376 316 }
377 317 };
378 318 </script>
... ...