diff --git a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue index 959ab9f6d..912cea478 100644 --- a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue +++ b/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 = ''; diff --git a/src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenSQLParser.java b/src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenSQLParser.java new file mode 100644 index 000000000..d653ab639 --- /dev/null +++ b/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> parse(String sql) { + // 解析 SQL 成 Statement + SQLCreateTableStatement statement = parseCreateSQL(sql); + // 解析 Table 表 + ToolSchemaTableDO table = parseTable(statement); + // 解析 Column 字段 + List 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 parseColumns(SQLCreateTableStatement statement) { + List columns = new ArrayList<>(); + statement.getTableElementList().forEach(element -> parseColumn(columns, element)); + return columns; + } + + private static void parseColumn(List 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 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 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()); + } + +} diff --git a/src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenSQLParserTest.java b/src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenSQLParserTest.java new file mode 100644 index 000000000..0e91b8ecb --- /dev/null +++ b/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 芋艿:后续完善断言 + } + +}