Przeglądaj źródła

增加 druid 解析 sql,用于后续生成代码

YunaiV 4 lat temu
rodzic
commit
8d6b14bc9c

+ 5 - 0
ruoyi-ui/src/views/tool/gen/genInfoForm.vue

@@ -294,6 +294,11 @@ export default {
     },
     /** 选择生成模板触发 */
     tplSelectChange(value) {
+      if (value !== 1) {
+        // TODO 芋艿:暂时不考虑支持树形结构
+        this.msgError('暂时不考虑支持【树形】和【主子表】的代码生成。原因是:导致 vm 模板过于复杂,不利于胖友二次开发');
+        return false;
+      }
       if(value !== 'sub') {
         this.info.subTableName = '';
         this.info.subTableFkName = '';

+ 108 - 0
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenSQLParser.java

@@ -0,0 +1,108 @@
+package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolSchemaColumnDO;
+import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolSchemaTableDO;
+import com.alibaba.druid.DbType;
+import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
+import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
+import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
+import com.alibaba.druid.sql.ast.statement.SQLPrimaryKey;
+import com.alibaba.druid.sql.ast.statement.SQLTableElement;
+import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
+import com.alibaba.druid.sql.repository.SchemaRepository;
+import org.apache.commons.collections4.KeyValue;
+import org.apache.commons.collections4.keyvalue.DefaultKeyValue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.alibaba.druid.sql.SQLUtils.normalize;
+
+/**
+ * SQL 解析器,将创建表的 SQL,解析成 {@link ToolSchemaTableDO} 和 {@link ToolSchemaColumnDO} 对象,
+ * 后续可以基于它们,生成代码~
+ *
+ * @author 芋道源码
+ */
+public class ToolCodegenSQLParser {
+
+    /**
+     * 解析建表 SQL 语句,返回 {@link ToolSchemaTableDO} 和 {@link ToolSchemaColumnDO} 对象
+     *
+     * @param sql 建表 SQL 语句
+     * @return 解析结果
+     */
+    public static KeyValue<ToolSchemaTableDO, List<ToolSchemaColumnDO>> parse(String sql) {
+        // 解析 SQL 成 Statement
+        SQLCreateTableStatement statement = parseCreateSQL(sql);
+        // 解析 Table 表
+        ToolSchemaTableDO table = parseTable(statement);
+        // 解析 Column 字段
+        List<ToolSchemaColumnDO> columns = parseColumns(statement);
+        columns.forEach(column -> column.setTableName(table.getTableName()));
+        // 返回
+        return new DefaultKeyValue<>(table, columns);
+    }
+
+    /**
+     * 使用 Druid 工具,建表 SQL 语句
+     *
+     * @param sql 建表 SQL 语句
+     * @return 创建 Statement
+     */
+    private static SQLCreateTableStatement parseCreateSQL(String sql) {
+        // 解析 SQL
+        SchemaRepository repository = new SchemaRepository(DbType.mysql);
+        repository.console(sql);
+        // 获得该表对应的 MySqlCreateTableStatement 对象
+        String tableName = CollUtil.getFirst(repository.getDefaultSchema().getObjects()).getName();
+        return (MySqlCreateTableStatement) repository.findTable(tableName).getStatement();
+    }
+
+    private static ToolSchemaTableDO parseTable(SQLCreateTableStatement statement) {
+        return ToolSchemaTableDO.builder()
+                .tableName(statement.getTableSource().getTableName(true))
+                .tableComment(((SQLCharExpr) statement.getComment()).getText())
+                .build();
+    }
+
+    private static List<ToolSchemaColumnDO> parseColumns(SQLCreateTableStatement statement) {
+        List<ToolSchemaColumnDO> columns = new ArrayList<>();
+        statement.getTableElementList().forEach(element -> parseColumn(columns, element));
+        return columns;
+    }
+
+    private static void parseColumn(List<ToolSchemaColumnDO> columns, SQLTableElement element) {
+        // 处理主键
+        if (element instanceof SQLPrimaryKey) {
+            parsePrimaryKey(columns, (SQLPrimaryKey) element);
+            return;
+        }
+        // 处理字段定义
+        if (element instanceof SQLColumnDefinition) {
+            parseColumnDefinition(columns, (SQLColumnDefinition) element);
+        }
+    }
+
+    private static void parsePrimaryKey(List<ToolSchemaColumnDO> columns, SQLPrimaryKey primaryKey) {
+        String columnName = normalize(primaryKey.getColumns().get(0).toString()); // 暂时不考虑联合主键
+        // 匹配 columns 主键字段,设置为 primary
+        columns.stream().filter(column -> column.getColumnName().equals(columnName))
+            .forEach(column -> column.setPrimaryKey(true));
+    }
+
+    private static void parseColumnDefinition(List<ToolSchemaColumnDO> columns, SQLColumnDefinition definition) {
+        String text = definition.toString().toUpperCase();
+        columns.add(ToolSchemaColumnDO.builder()
+                .columnName(normalize(definition.getColumnName()))
+                .columnType(definition.getDataType().toString())
+                .columnComment(normalize(definition.getComment().toString()))
+                .nullable(!text.contains(" NOT NULL"))
+                .primaryKey(false)
+                .autoIncrement(text.contains("AUTO_INCREMENT"))
+                .ordinalPosition(columns.size() + 1)
+                .build());
+    }
+
+}

+ 29 - 0
src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenSQLParserTest.java

@@ -0,0 +1,29 @@
+package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ToolCodegenSQLParserTest {
+
+    @Test
+    public void testParse() {
+        String sql = "CREATE TABLE `tool_test_demo` (\n" +
+                "  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',\n" +
+                "  `name` varchar(100) NOT NULL DEFAULT '' COMMENT '名字',\n" +
+                "  `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态',\n" +
+                "  `type` tinyint(4) NOT NULL COMMENT '类型',\n" +
+                "  `category` tinyint(4) NOT NULL COMMENT '分类',\n" +
+                "  `remark` varchar(500) DEFAULT NULL COMMENT '备注',\n" +
+                "  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',\n" +
+                "  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n" +
+                "  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',\n" +
+                "  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',\n" +
+                "  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',\n" +
+                "  PRIMARY KEY (`id`) USING BTREE\n" +
+                ") ENGINE=InnoDB AUTO_INCREMENT=108 DEFAULT CHARSET=utf8mb4 COMMENT='字典类型表';";
+        ToolCodegenSQLParser.parse(sql);
+        // TODO 芋艿:后续完善断言
+    }
+
+}