Commit 8d6b14bc9c6771531585a3762d931c3cf7726495

Authored by YunaiV
1 parent 0c8f92fa

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

ruoyi-ui/src/views/tool/gen/genInfoForm.vue
... ... @@ -294,6 +294,11 @@ export default {
294 294 },
295 295 /** 选择生成模板触发 */
296 296 tplSelectChange(value) {
  297 + if (value !== 1) {
  298 + // TODO 芋艿:暂时不考虑支持树形结构
  299 + this.msgError('暂时不考虑支持【树形】和【主子表】的代码生成。原因是:导致 vm 模板过于复杂,不利于胖友二次开发');
  300 + return false;
  301 + }
297 302 if(value !== 'sub') {
298 303 this.info.subTableName = '';
299 304 this.info.subTableFkName = '';
... ...
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenSQLParser.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolSchemaColumnDO;
  5 +import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolSchemaTableDO;
  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 +
  20 +import static com.alibaba.druid.sql.SQLUtils.normalize;
  21 +
  22 +/**
  23 + * SQL 解析器,将创建表的 SQL,解析成 {@link ToolSchemaTableDO} 和 {@link ToolSchemaColumnDO} 对象,
  24 + * 后续可以基于它们,生成代码~
  25 + *
  26 + * @author 芋道源码
  27 + */
  28 +public class ToolCodegenSQLParser {
  29 +
  30 + /**
  31 + * 解析建表 SQL 语句,返回 {@link ToolSchemaTableDO} 和 {@link ToolSchemaColumnDO} 对象
  32 + *
  33 + * @param sql 建表 SQL 语句
  34 + * @return 解析结果
  35 + */
  36 + public static KeyValue<ToolSchemaTableDO, List<ToolSchemaColumnDO>> parse(String sql) {
  37 + // 解析 SQL 成 Statement
  38 + SQLCreateTableStatement statement = parseCreateSQL(sql);
  39 + // 解析 Table 表
  40 + ToolSchemaTableDO table = parseTable(statement);
  41 + // 解析 Column 字段
  42 + List<ToolSchemaColumnDO> columns = parseColumns(statement);
  43 + columns.forEach(column -> column.setTableName(table.getTableName()));
  44 + // 返回
  45 + return new DefaultKeyValue<>(table, columns);
  46 + }
  47 +
  48 + /**
  49 + * 使用 Druid 工具,建表 SQL 语句
  50 + *
  51 + * @param sql 建表 SQL 语句
  52 + * @return 创建 Statement
  53 + */
  54 + private static SQLCreateTableStatement parseCreateSQL(String sql) {
  55 + // 解析 SQL
  56 + SchemaRepository repository = new SchemaRepository(DbType.mysql);
  57 + repository.console(sql);
  58 + // 获得该表对应的 MySqlCreateTableStatement 对象
  59 + String tableName = CollUtil.getFirst(repository.getDefaultSchema().getObjects()).getName();
  60 + return (MySqlCreateTableStatement) repository.findTable(tableName).getStatement();
  61 + }
  62 +
  63 + private static ToolSchemaTableDO parseTable(SQLCreateTableStatement statement) {
  64 + return ToolSchemaTableDO.builder()
  65 + .tableName(statement.getTableSource().getTableName(true))
  66 + .tableComment(((SQLCharExpr) statement.getComment()).getText())
  67 + .build();
  68 + }
  69 +
  70 + private static List<ToolSchemaColumnDO> parseColumns(SQLCreateTableStatement statement) {
  71 + List<ToolSchemaColumnDO> columns = new ArrayList<>();
  72 + statement.getTableElementList().forEach(element -> parseColumn(columns, element));
  73 + return columns;
  74 + }
  75 +
  76 + private static void parseColumn(List<ToolSchemaColumnDO> columns, SQLTableElement element) {
  77 + // 处理主键
  78 + if (element instanceof SQLPrimaryKey) {
  79 + parsePrimaryKey(columns, (SQLPrimaryKey) element);
  80 + return;
  81 + }
  82 + // 处理字段定义
  83 + if (element instanceof SQLColumnDefinition) {
  84 + parseColumnDefinition(columns, (SQLColumnDefinition) element);
  85 + }
  86 + }
  87 +
  88 + private static void parsePrimaryKey(List<ToolSchemaColumnDO> columns, SQLPrimaryKey primaryKey) {
  89 + String columnName = normalize(primaryKey.getColumns().get(0).toString()); // 暂时不考虑联合主键
  90 + // 匹配 columns 主键字段,设置为 primary
  91 + columns.stream().filter(column -> column.getColumnName().equals(columnName))
  92 + .forEach(column -> column.setPrimaryKey(true));
  93 + }
  94 +
  95 + private static void parseColumnDefinition(List<ToolSchemaColumnDO> columns, SQLColumnDefinition definition) {
  96 + String text = definition.toString().toUpperCase();
  97 + columns.add(ToolSchemaColumnDO.builder()
  98 + .columnName(normalize(definition.getColumnName()))
  99 + .columnType(definition.getDataType().toString())
  100 + .columnComment(normalize(definition.getComment().toString()))
  101 + .nullable(!text.contains(" NOT NULL"))
  102 + .primaryKey(false)
  103 + .autoIncrement(text.contains("AUTO_INCREMENT"))
  104 + .ordinalPosition(columns.size() + 1)
  105 + .build());
  106 + }
  107 +
  108 +}
... ...
src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenSQLParserTest.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
  2 +
  3 +import org.junit.jupiter.api.Test;
  4 +
  5 +import static org.junit.jupiter.api.Assertions.*;
  6 +
  7 +class ToolCodegenSQLParserTest {
  8 +
  9 + @Test
  10 + public void testParse() {
  11 + String sql = "CREATE TABLE `tool_test_demo` (\n" +
  12 + " `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',\n" +
  13 + " `name` varchar(100) NOT NULL DEFAULT '' COMMENT '名字',\n" +
  14 + " `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态',\n" +
  15 + " `type` tinyint(4) NOT NULL COMMENT '类型',\n" +
  16 + " `category` tinyint(4) NOT NULL COMMENT '分类',\n" +
  17 + " `remark` varchar(500) DEFAULT NULL COMMENT '备注',\n" +
  18 + " `create_by` varchar(64) DEFAULT '' COMMENT '创建者',\n" +
  19 + " `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n" +
  20 + " `update_by` varchar(64) DEFAULT '' COMMENT '更新者',\n" +
  21 + " `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',\n" +
  22 + " `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',\n" +
  23 + " PRIMARY KEY (`id`) USING BTREE\n" +
  24 + ") ENGINE=InnoDB AUTO_INCREMENT=108 DEFAULT CHARSET=utf8mb4 COMMENT='字典类型表';";
  25 + ToolCodegenSQLParser.parse(sql);
  26 + // TODO 芋艿:后续完善断言
  27 + }
  28 +
  29 +}
... ...