Эх сурвалжийг харах

增加基于 SQL 导入表结构

YunaiV 4 жил өмнө
parent
commit
95757db6be

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 43 - 7
sql/ruoyi-vue-pro.sql


+ 41 - 17
src/main/java/cn/iocoder/dashboard/modules/tool/controller/codegen/ToolCodegenController.java

@@ -21,6 +21,7 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -45,12 +46,13 @@ public class ToolCodegenController {
     @Resource
     private ToolCodegenService codegenService;
 
-    @ApiOperation(value = "获得数据库自带的表定义列表", notes = "会过滤掉已经导入 Codegen 的表")
     @GetMapping("/db/table/list")
+    @ApiOperation(value = "获得数据库自带的表定义列表", notes = "会过滤掉已经导入 Codegen 的表")
     @ApiImplicitParams({
             @ApiImplicitParam(name = "tableName", required = true, example = "yudao", dataTypeClass = String.class),
             @ApiImplicitParam(name = "tableComment", required = true, example = "芋道", dataTypeClass = String.class)
     })
+    @PreAuthorize("@ss.hasPermission('tool:codegen:query')")
     public CommonResult<List<ToolSchemaTableRespVO>> getSchemaTableList(
             @RequestParam(value = "tableName", required = false) String tableName,
             @RequestParam(value = "tableComment", required = false) String tableComment) {
@@ -62,18 +64,18 @@ public class ToolCodegenController {
         return success(ToolCodegenConvert.INSTANCE.convertList04(schemaTables));
     }
 
-    @ApiOperation("获得表定义分页")
     @GetMapping("/table/page")
-    // TODO 权限 @PreAuthorize("@ss.hasPermi('tool:gen:list')")
+    @ApiOperation("获得表定义分页")
+    @PreAuthorize("@ss.hasPermission('tool:codegen:query')")
     public CommonResult<PageResult<ToolCodegenTableRespVO>> getCodeGenTablePage(@Valid ToolCodegenTablePageReqVO pageReqVO) {
         PageResult<ToolCodegenTableDO> pageResult = codegenService.getCodegenTablePage(pageReqVO);
         return success(ToolCodegenConvert.INSTANCE.convertPage(pageResult));
     }
 
-    @ApiOperation("获得表和字段的明细")
     @GetMapping("/detail")
+    @ApiOperation("获得表和字段的明细")
     @ApiImplicitParam(name = "tableId", required = true, example = "表编号", dataTypeClass = Long.class)
-//   todo @PreAuthorize("@ss.hasPermi('tool:gen:query')")
+    @PreAuthorize("@ss.hasPermission('tool:codegen:query')")
     public CommonResult<ToolCodegenDetailRespVO> getCodegenDetail(@RequestParam("tableId") Long tableId) {
         ToolCodegenTableDO table = codegenService.getCodegenTablePage(tableId);
         List<ToolCodegenColumnDO> columns = codegenService.getCodegenColumnListByTableId(tableId);
@@ -82,33 +84,55 @@ public class ToolCodegenController {
     }
 
     @ApiOperation("基于数据库的表结构,创建代码生成器的表和字段定义")
-    @PostMapping("/create-list")
-    // TODO 权限
-    public CommonResult<List<Long>> createCodegenList(@RequestParam("tableNames") List<String> tableNames) {
-        return success(codegenService.createCodeGenList(tableNames));
+    @ApiImplicitParam(name = "tableNames", required = true, example = "sys_user", dataTypeClass = List.class)
+    @PostMapping("/create-list-from-db")
+    @PreAuthorize("@ss.hasPermission('tool:codegen:create')")
+    public CommonResult<List<Long>> createCodegenListFromDB(@RequestParam("tableNames") List<String> tableNames) {
+        return success(codegenService.createCodegenListFromDB(tableNames));
+    }
+
+    @ApiOperation("基于 SQL 建表语句,创建代码生成器的表和字段定义")
+    @ApiImplicitParam(name = "SQL 建表语句", required = true, example = "sql", dataTypeClass = String.class)
+    @PostMapping("/create-list-from-sql")
+    @PreAuthorize("@ss.hasPermission('tool:codegen:create')")
+    public CommonResult<Long> createCodegenListFromSQL(@RequestParam("sql") String sql) {
+        return success(codegenService.createCodegenListFromSQL(sql));
     }
 
     @ApiOperation("更新数据库的表和字段定义")
     @PutMapping("/update")
-//    @PreAuthorize("@ss.hasPermi('tool:gen:edit')") TODO 权限
+    @PreAuthorize("@ss.hasPermission('tool:codegen:update')")
     public CommonResult<Boolean> updateCodegen(@Valid @RequestBody ToolCodegenUpdateReqVO updateReqVO) {
         codegenService.updateCodegen(updateReqVO);
         return success(true);
     }
 
     @ApiOperation("基于数据库的表结构,同步数据库的表和字段定义")
-    @PutMapping("/sync")
+    @PutMapping("/sync-from-db")
     @ApiImplicitParam(name = "tableId", required = true, example = "表编号", dataTypeClass = Long.class)
-//    @PreAuthorize("@ss.hasPermi('tool:gen:edit')") TODO 权限
-    public CommonResult<Boolean> syncCodegen(@RequestParam("tableId") Long tableId) {
-        codegenService.syncCodegen(tableId);
+    @PreAuthorize("@ss.hasPermission('tool:codegen:update')")
+    public CommonResult<Boolean> syncCodegenFromDB(@RequestParam("tableId") Long tableId) {
+        codegenService.syncCodegenFromDB(tableId);
+        return success(true);
+    }
+
+    @ApiOperation("基于 SQL 建表语句,同步数据库的表和字段定义")
+    @PutMapping("/sync-from-sql")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "tableId", required = true, example = "表编号", dataTypeClass = Long.class),
+            @ApiImplicitParam(name = "SQL 建表语句", required = true, example = "sql", dataTypeClass = String.class)
+    })
+    @PreAuthorize("@ss.hasPermission('tool:codegen:update')")
+    public CommonResult<Boolean> syncCodegenFromSQL(@RequestParam("tableId") Long tableId,
+                                                    @RequestParam("sql") String sql) {
+        codegenService.syncCodegenFromSQL(tableId, sql);
         return success(true);
     }
 
     @ApiOperation("删除数据库的表和字段定义")
     @DeleteMapping("/delete")
     @ApiImplicitParam(name = "tableId", required = true, example = "表编号", dataTypeClass = Long.class)
-//    @PreAuthorize("@ss.hasPermi('tool:gen:remove')") TODO 权限
+    @PreAuthorize("@ss.hasPermission('tool:codegen:delete')")
     public CommonResult<Boolean> deleteCodegen(@RequestParam("tableId") Long tableId) {
         codegenService.deleteCodegen(tableId);
         return success(true);
@@ -117,7 +141,7 @@ public class ToolCodegenController {
     @ApiOperation("预览生成代码")
     @GetMapping("/preview")
     @ApiImplicitParam(name = "tableId", required = true, example = "表编号", dataTypeClass = Long.class)
-//    @PreAuthorize("@ss.hasPermi('tool:gen:preview')") TODO 权限
+    @PreAuthorize("@ss.hasPermission('tool:codegen:preview')")
     public CommonResult<List<ToolCodegenPreviewRespVO>> previewCodegen(@RequestParam("tableId") Long tableId) {
         Map<String, String> codes = codegenService.generationCodes(tableId);
         return success(ToolCodegenConvert.INSTANCE.convert(codes));
@@ -126,7 +150,7 @@ public class ToolCodegenController {
     @ApiOperation("下载生成代码")
     @GetMapping("/download")
     @ApiImplicitParam(name = "tableId", required = true, example = "表编号", dataTypeClass = Long.class)
-    // @PreAuthorize("@ss.hasPermi('tool:gen:code')") todo 权限
+    @PreAuthorize("@ss.hasPermission('tool:codegen:download')")
     public void downloadCodegen(@RequestParam("tableId") Long tableId,
                                 HttpServletResponse response) throws IOException {
         // 生成代码

+ 4 - 0
src/main/java/cn/iocoder/dashboard/modules/tool/controller/codegen/vo/table/ToolCodegenTableBaseVO.java

@@ -12,6 +12,10 @@ import javax.validation.constraints.NotNull;
 @Data
 public class ToolCodegenTableBaseVO {
 
+    @ApiModelProperty(value = "导入类型", required = true, example = "1", notes = "参见 ToolCodegenImportTypeEnum 枚举")
+    @NotNull(message = "导入类型不能为空")
+    private Integer importType;
+
     @ApiModelProperty(value = "表名称", required = true, example = "yudao")
     @NotNull(message = "表名称不能为空")
     private String tableName;

+ 7 - 0
src/main/java/cn/iocoder/dashboard/modules/tool/dal/dataobject/codegen/ToolCodegenTableDO.java

@@ -24,6 +24,13 @@ public class ToolCodegenTableDO extends BaseDO {
      */
     private Long id;
 
+    /**
+     * 导入类型
+     *
+     * 枚举 {@link ToolCodegenTemplateTypeEnum}
+     */
+    private Integer importType;
+
     // ========== 表相关字段 ==========
 
     /**

+ 10 - 0
src/main/java/cn/iocoder/dashboard/modules/tool/enums/ToolErrorCodeConstants.java

@@ -12,4 +12,14 @@ public interface ToolErrorCodeConstants {
     // ========== 字典类型(测试) 1003000000 ==========
     ErrorCode TEST_DEMO_NOT_EXISTS = new ErrorCode(1003000000, "测试示例不存在");
 
+    // ========== 代码生成器 1003001000 ==========
+    ErrorCode CODEGEN_TABLE_EXISTS = new ErrorCode(1003001000, "表定义已经存在");
+    ErrorCode CODEGEN_IMPORT_TABLE_NULL = new ErrorCode(1003001001, "导入的表不存在");
+    ErrorCode CODEGEN_IMPORT_COLUMNS_NULL = new ErrorCode(1003001002, "导入的字段不存在");
+    ErrorCode CODEGEN_PARSE_SQL_ERROR = new ErrorCode(1003001003, "解析 SQL 失败,请检查");
+    ErrorCode CODEGEN_TABLE_NOT_EXISTS = new ErrorCode(1003001004, "表定义不存在");
+    ErrorCode CODEGEN_COLUMN_NOT_EXISTS = new ErrorCode(1003001005, "字段义不存在");
+    ErrorCode CODEGEN_SYNC_COLUMNS_NULL = new ErrorCode(1003001006, "同步的字段不存在");
+    ErrorCode CODEGEN_SYNC_NONE_CHANGE = new ErrorCode(1003001007, "同步失败,不存在改变");
+
 }

+ 23 - 0
src/main/java/cn/iocoder/dashboard/modules/tool/enums/codegen/ToolCodegenImportTypeEnum.java

@@ -0,0 +1,23 @@
+package cn.iocoder.dashboard.modules.tool.enums.codegen;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 代码生成的导入类型
+ *
+ * @author 芋道源码
+ */
+@AllArgsConstructor
+@Getter
+public enum ToolCodegenImportTypeEnum {
+
+    DB(1), // 从 information_schema 的 table 和 columns 表导入
+    SQL(2); // 基于建表 SQL 语句导入
+
+    /**
+     * 类型
+     */
+    private final Integer type;
+
+}

+ 0 - 2
src/main/java/cn/iocoder/dashboard/modules/tool/enums/codegen/ToolCodegenTemplateTypeEnum.java

@@ -14,8 +14,6 @@ public enum ToolCodegenTemplateTypeEnum {
 
     CRUD(1), // 单表(增删改查)
     TREE(2), // 树表(增删改查)
-    // TODO 主子表,暂时不考虑支持。原因是较为灵活,形态较多,很难评估。
-    SUB(3) // 主子表(增删改查)
     ;
 
     /**

+ 18 - 2
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/ToolCodegenService.java

@@ -17,6 +17,14 @@ import java.util.Map;
  */
 public interface ToolCodegenService {
 
+    /**
+     * 基于 SQL 建表语句,创建代码生成器的表定义
+     *
+     * @param sql SQL 建表语句
+     * @return 创建的表定义的编号
+     */
+    Long createCodegenListFromSQL(String sql);
+
     /**
      * 基于数据库的表结构,创建代码生成器的表定义
      *
@@ -31,7 +39,7 @@ public interface ToolCodegenService {
      * @param tableNames 表名称数组
      * @return 创建的表定义的编号数组
      */
-    List<Long> createCodeGenList(List<String> tableNames);
+    List<Long> createCodegenListFromDB(List<String> tableNames);
 
     /**
      * 更新数据库的表和字段定义
@@ -45,7 +53,15 @@ public interface ToolCodegenService {
      *
      * @param tableId 表编号
      */
-    void syncCodegen(Long tableId);
+    void syncCodegenFromDB(Long tableId);
+
+    /**
+     * 基于 SQL 建表语句,同步数据库的表和字段定义
+     *
+     * @param tableId 表编号
+     * @param sql SQL 建表语句
+     */
+    void syncCodegenFromSQL(Long tableId, String sql);
 
     /**
      * 删除数据库的表和字段定义

+ 78 - 20
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImpl.java

@@ -14,8 +14,10 @@ import cn.iocoder.dashboard.modules.tool.dal.mysql.coegen.ToolCodegenColumnMappe
 import cn.iocoder.dashboard.modules.tool.dal.mysql.coegen.ToolCodegenTableMapper;
 import cn.iocoder.dashboard.modules.tool.dal.mysql.coegen.ToolSchemaColumnMapper;
 import cn.iocoder.dashboard.modules.tool.dal.mysql.coegen.ToolSchemaTableMapper;
+import cn.iocoder.dashboard.modules.tool.enums.codegen.ToolCodegenImportTypeEnum;
 import cn.iocoder.dashboard.modules.tool.service.codegen.ToolCodegenService;
 import cn.iocoder.dashboard.util.collection.CollectionUtils;
+import org.apache.commons.collections4.KeyValue;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -26,6 +28,9 @@ import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.dashboard.modules.tool.enums.ToolErrorCodeConstants.*;
+
 /**
  * 代码生成 Service 实现类
  *
@@ -51,25 +56,26 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
     @Resource
     private CodegenProperties codegenProperties;
 
-    @Override
-    @Transactional
-    public Long createCodegen(String tableName) {
-        // 从数据库中,获得数据库表结构
-        ToolSchemaTableDO schemaTable = schemaTableMapper.selectByTableName(tableName);
+    @Resource
+    private ToolCodegenServiceImpl self;
+
+    private Long createCodegen0(ToolCodegenImportTypeEnum importType,
+                                ToolSchemaTableDO schemaTable, List<ToolSchemaColumnDO> schemaColumns) {
+        // 校验导入的表和字段非空
         if (schemaTable == null) {
-            throw new RuntimeException(""); // TODO
+            throw exception(CODEGEN_IMPORT_TABLE_NULL);
         }
-        List<ToolSchemaColumnDO> schemaColumns = schemaColumnMapper.selectListByTableName(tableName);
         if (CollUtil.isEmpty(schemaColumns)) {
-            throw new RuntimeException(""); // TODO
+            throw exception(CODEGEN_IMPORT_COLUMNS_NULL);
         }
         // 校验是否已经存在
-        if (codegenTableMapper.selectByTableName(tableName) != null) {
-            throw new RuntimeException(""); // TODO
+        if (codegenTableMapper.selectByTableName(schemaTable.getTableName()) != null) {
+            throw exception(CODEGEN_TABLE_EXISTS);
         }
 
         // 构建 ToolCodegenTableDO 对象,插入到 DB 中
         ToolCodegenTableDO table = codegenBuilder.buildTable(schemaTable);
+        table.setImportType(importType.getType());
         codegenTableMapper.insert(table);
         // 构建 ToolCodegenColumnDO 数组,插入到 DB 中
         List<ToolCodegenColumnDO> columns = codegenBuilder.buildColumns(schemaColumns);
@@ -80,9 +86,34 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
         return table.getId();
     }
 
+    @Override
+    public Long createCodegenListFromSQL(String sql) {
+        // 从 SQL 中,获得数据库表结构
+        ToolSchemaTableDO schemaTable;
+        List<ToolSchemaColumnDO> schemaColumns;
+        try {
+            KeyValue<ToolSchemaTableDO, List<ToolSchemaColumnDO>> result = ToolCodegenSQLParser.parse(sql);
+            schemaTable = result.getKey();
+            schemaColumns = result.getValue();
+        } catch (Exception ex) {
+            throw exception(CODEGEN_PARSE_SQL_ERROR);
+        }
+        // 导入
+        return self.createCodegen0(ToolCodegenImportTypeEnum.SQL, schemaTable, schemaColumns);
+    }
+
+    @Override
+    public Long createCodegen(String tableName) {
+        // 从数据库中,获得数据库表结构
+        ToolSchemaTableDO schemaTable = schemaTableMapper.selectByTableName(tableName);
+        List<ToolSchemaColumnDO> schemaColumns = schemaColumnMapper.selectListByTableName(tableName);
+        // 导入
+        return self.createCodegen0(ToolCodegenImportTypeEnum.DB, schemaTable, schemaColumns);
+    }
+
     @Override
     @Transactional
-    public List<Long> createCodeGenList(List<String> tableNames) {
+    public List<Long> createCodegenListFromDB(List<String> tableNames) {
         List<Long> ids = new ArrayList<>(tableNames.size());
         // 遍历添加。虽然效率会低一点,但是没必要做成完全批量,因为不会这么大量
         tableNames.forEach(tableName -> ids.add(createCodegen(tableName)));
@@ -94,7 +125,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
     public void updateCodegen(ToolCodegenUpdateReqVO updateReqVO) {
         // 校验是否已经存在
         if (codegenTableMapper.selectById(updateReqVO.getTable().getId()) == null) {
-            throw new RuntimeException(""); // TODO
+            throw exception(CODEGEN_TABLE_NOT_EXISTS);
         }
 
         // 更新 table 表定义
@@ -106,16 +137,43 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
     }
 
     @Override
-    public void syncCodegen(Long tableId) {
+    public void syncCodegenFromDB(Long tableId) {
         // 校验是否已经存在
         ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
         if (table == null) {
-            throw new RuntimeException(""); // TODO
+            throw exception(CODEGEN_TABLE_NOT_EXISTS);
         }
         // 从数据库中,获得数据库表结构
         List<ToolSchemaColumnDO> schemaColumns = schemaColumnMapper.selectListByTableName(table.getTableName());
+
+        // 执行同步
+        self.syncCodegen0(tableId, schemaColumns);
+    }
+
+    @Override
+    public void syncCodegenFromSQL(Long tableId, String sql) {
+        // 校验是否已经存在
+        ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
+        if (table == null) {
+            throw exception(CODEGEN_TABLE_NOT_EXISTS);
+        }
+        // 从 SQL 中,获得数据库表结构
+        List<ToolSchemaColumnDO> schemaColumns;
+        try {
+            KeyValue<ToolSchemaTableDO, List<ToolSchemaColumnDO>> result = ToolCodegenSQLParser.parse(sql);
+            schemaColumns = result.getValue();
+        } catch (Exception ex) {
+            throw exception(CODEGEN_PARSE_SQL_ERROR);
+        }
+
+        // 执行同步
+        self.syncCodegen0(tableId, schemaColumns);
+    }
+
+    private void syncCodegen0(Long tableId, List<ToolSchemaColumnDO> schemaColumns) {
+        // 校验导入的字段不为空
         if (CollUtil.isEmpty(schemaColumns)) {
-            throw new RuntimeException(""); // TODO
+            throw exception(CODEGEN_SYNC_COLUMNS_NULL);
         }
         Set<String> schemaColumnNames = CollectionUtils.convertSet(schemaColumns, ToolSchemaColumnDO::getColumnName);
 
@@ -128,13 +186,13 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
         Set<Long> deleteColumnIds = codegenColumns.stream().filter(column -> !schemaColumnNames.contains(column.getColumnName()))
                 .map(ToolCodegenColumnDO::getId).collect(Collectors.toSet());
         if (CollUtil.isEmpty(schemaColumns) && CollUtil.isEmpty(deleteColumnIds)) {
-            throw new RuntimeException(""); // TODO
+            throw exception(CODEGEN_SYNC_NONE_CHANGE);
         }
 
         // 插入新增的字段
         List<ToolCodegenColumnDO> columns = codegenBuilder.buildColumns(schemaColumns);
         columns.forEach(column -> {
-            column.setTableId(table.getId());
+            column.setTableId(tableId);
             codegenColumnMapper.insert(column); // TODO 批量插入
         });
         // 删除不存在的字段
@@ -146,7 +204,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
     public void deleteCodegen(Long tableId) {
         // 校验是否已经存在
         if (codegenTableMapper.selectById(tableId) == null) {
-            throw new RuntimeException(""); // TODO
+            throw exception(CODEGEN_TABLE_NOT_EXISTS);
         }
 
         // 删除 table 表定义
@@ -180,11 +238,11 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
         // 校验是否已经存在
         ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
         if (codegenTableMapper.selectById(tableId) == null) {
-            throw new RuntimeException(""); // TODO
+            throw exception(CODEGEN_TABLE_NOT_EXISTS);
         }
         List<ToolCodegenColumnDO> columns = codegenColumnMapper.selectListByTableId(tableId);
         if (CollUtil.isEmpty(columns)) {
-            throw new RuntimeException(""); // TODO
+            throw exception(CODEGEN_COLUMN_NOT_EXISTS);
         }
 
         // 执行生成

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно