Browse Source

feat:【infra】代码生成:menu 生成时,支持多种

YunaiV 10 months ago
parent
commit
9519ca969c

+ 10 - 1
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java

@@ -4,12 +4,14 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils;
 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
+import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO;
 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper;
 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
@@ -17,7 +19,9 @@ import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
 import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
 import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
 import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
+import cn.iocoder.yudao.module.infra.service.db.DataSourceConfigService;
 import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
+import com.baomidou.mybatisplus.annotation.DbType;
 import com.baomidou.mybatisplus.generator.config.po.TableField;
 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
 import com.google.common.annotations.VisibleForTesting;
@@ -45,6 +49,8 @@ public class CodegenServiceImpl implements CodegenService {
 
     @Resource
     private DatabaseTableService databaseTableService;
+    @Resource
+    private DataSourceConfigService dataSourceConfigService;
 
     @Resource
     private CodegenTableMapper codegenTableMapper;
@@ -284,8 +290,11 @@ public class CodegenServiceImpl implements CodegenService {
             }
         }
 
+        // 获取数据源对应的数据库类型
+        DataSourceConfigDO dataSourceConfig = dataSourceConfigService.getDataSourceConfig(table.getDataSourceConfigId());
+        DbType dbType = JdbcUtils.getDbType(dataSourceConfig.getUrl());
         // 执行生成
-        return codegenEngine.execute(table, columns, subTables, subColumnsList);
+        return codegenEngine.execute(dbType, table, columns, subTables, subColumnsList);
     }
 
     @Override

+ 6 - 3
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java

@@ -33,6 +33,7 @@ import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenVOTypeEnum;
 import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
+import com.baomidou.mybatisplus.annotation.DbType;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableTable;
 import com.google.common.collect.Maps;
@@ -310,16 +311,17 @@ public class CodegenEngine {
     /**
      * 生成代码
      *
+     * @param dbType         数据库类型
      * @param table          表定义
      * @param columns        table 的字段定义数组
      * @param subTables      子表数组,当且仅当主子表时使用
      * @param subColumnsList subTables 的字段定义数组
      * @return 生成的代码,key 是路径,value 是对应代码
      */
-    public Map<String, String> execute(CodegenTableDO table, List<CodegenColumnDO> columns,
+    public Map<String, String> execute(DbType dbType, CodegenTableDO table, List<CodegenColumnDO> columns,
                                        List<CodegenTableDO> subTables, List<List<CodegenColumnDO>> subColumnsList) {
         // 1.1 初始化 bindMap 上下文
-        Map<String, Object> bindingMap = initBindingMap(table, columns, subTables, subColumnsList);
+        Map<String, Object> bindingMap = initBindingMap(dbType, table, columns, subTables, subColumnsList);
         // 1.2 获得模版
         Map<String, String> templates = getTemplates(table.getFrontType());
 
@@ -425,10 +427,11 @@ public class CodegenEngine {
         return content;
     }
 
-    private Map<String, Object> initBindingMap(CodegenTableDO table, List<CodegenColumnDO> columns,
+    private Map<String, Object> initBindingMap(DbType dbType, CodegenTableDO table, List<CodegenColumnDO> columns,
                                                List<CodegenTableDO> subTables, List<List<CodegenColumnDO>> subColumnsList) {
         // 创建 bindingMap
         Map<String, Object> bindingMap = new HashMap<>(globalBindingMap);
+        bindingMap.put("dbType", dbType);
         bindingMap.put("table", table);
         bindingMap.put("columns", columns);
         bindingMap.put("primaryColumn", CollectionUtils.findFirst(columns, CodegenColumnDO::getPrimaryKey)); // 主键字段

+ 157 - 3
yudao-module-infra/src/main/resources/codegen/sql/sql.vm

@@ -1,3 +1,24 @@
+## 通用变量定义
+#set ($functionNames = ['查询', '创建', '更新', '删除', '导出'])
+#set ($functionOps = ['query', 'create', 'update', 'delete', 'export'])
+##
+## 宏定义:生成按钮 SQL(通用部分)
+#macro(insertButtonSql $parentIdVar)
+#foreach ($functionName in $functionNames)
+#set ($index = $foreach.count - 1)
+    INSERT INTO system_menu(
+        name, permission, type, sort, parent_id,
+        path, icon, component, status
+    )
+    VALUES (
+        '${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, ${parentIdVar},
+        '', '', '', 0
+    );
+#end
+#end
+##
+## ======================= MySQL / OceanBase =======================
+#if ($dbType.name() == 'MYSQL' || $dbType.name() == 'OCEAN_BASE')
 -- 菜单 SQL
 INSERT INTO system_menu(
     name, permission, type, sort, parent_id,
@@ -9,12 +30,9 @@ VALUES (
 );
 
 -- 按钮父菜单ID
 SELECT @parentId := LAST_INSERT_ID();
 
 -- 按钮 SQL
-#set ($functionNames = ['查询', '创建', '更新', '删除', '导出'])
-#set ($functionOps = ['query', 'create', 'update', 'delete', 'export'])
 #foreach ($functionName in $functionNames)
 #set ($index = $foreach.count - 1)
 INSERT INTO system_menu(
@@ -25,4 +43,139 @@ VALUES (
     '${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, @parentId,
     '', '', '', 0
 );
-#end
+#end
+##
+## ======================= Oracle / 达梦 DM =======================
+#elseif ($dbType.name() == 'ORACLE' || $dbType.name() == 'DM')
+-- 菜单 SQL
+INSERT INTO system_menu(
+    name, permission, type, sort, parent_id,
+    path, icon, component, status, component_name
+)
+VALUES (
+    '${table.classComment}管理', '', 2, 0, ${table.parentMenuId},
+    '${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 0, '${table.className}'
+);
+
+-- 按钮父菜单ID
+-- 说明:Oracle/达梦 使用序列获取上一个插入的 ID
+DECLARE
+    v_parent_id NUMBER;
+BEGIN
+    SELECT system_menu_seq.CURRVAL INTO v_parent_id FROM DUAL;
+    -- 按钮 SQL
+#foreach ($functionName in $functionNames)
+#set ($index = $foreach.count - 1)
+    INSERT INTO system_menu(
+        name, permission, type, sort, parent_id,
+        path, icon, component, status
+    )
+    VALUES (
+        '${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, v_parent_id,
+        '', '', '', 0
+    );
+#end
+END;
+/
+##
+## ======================= PostgreSQL / 人大金仓 KingbaseES =======================
+#elseif ($dbType.name() == 'POSTGRE_SQL' || $dbType.name() == 'KINGBASE_ES')
+-- 菜单 SQL
+INSERT INTO system_menu(
+    name, permission, type, sort, parent_id,
+    path, icon, component, status, component_name
+)
+VALUES (
+    '${table.classComment}管理', '', 2, 0, ${table.parentMenuId},
+    '${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 0, '${table.className}'
+);
+
+-- 按钮父菜单ID
+-- 说明:PostgreSQL/KingbaseES 使用 lastval() 获取上一个插入的序列值
+DO $$
+DECLARE
+    v_parent_id BIGINT;
+BEGIN
+    v_parent_id := lastval();
+    -- 按钮 SQL
+#foreach ($functionName in $functionNames)
+#set ($index = $foreach.count - 1)
+    INSERT INTO system_menu(
+        name, permission, type, sort, parent_id,
+        path, icon, component, status
+    )
+    VALUES (
+        '${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, v_parent_id,
+        '', '', '', 0
+    );
+#end
+END $$;
+##
+## ======================= SQL Server =======================
+#elseif ($dbType.name() == 'SQL_SERVER' || $dbType.name() == 'SQL_SERVER2005')
+-- 菜单 SQL
+INSERT INTO system_menu(
+    name, permission, type, sort, parent_id,
+    path, icon, component, status, component_name
+)
+VALUES (
+    '${table.classComment}管理', '', 2, 0, ${table.parentMenuId},
+    '${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 0, '${table.className}'
+);
+
+-- 按钮父菜单ID
+-- 说明:SQL Server 使用 SCOPE_IDENTITY() 获取上一个插入的自增 ID
+DECLARE @parentId BIGINT;
+SET @parentId = SCOPE_IDENTITY();
+
+-- 按钮 SQL
+#foreach ($functionName in $functionNames)
+#set ($index = $foreach.count - 1)
+INSERT INTO system_menu(
+    name, permission, type, sort, parent_id,
+    path, icon, component, status
+)
+VALUES (
+    '${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, @parentId,
+    '', '', '', 0
+);
+#end
+##
+## ======================= 不支持的数据库类型 =======================
+#else
+-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+-- 注意:当前数据库类型 ${dbType.name()} 暂不支持自动生成菜单 SQL
+-- 请参考以下 MySQL 语法,手动修改为您的数据库对应的语法
+-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+-- 菜单 SQL
+INSERT INTO system_menu(
+    name, permission, type, sort, parent_id,
+    path, icon, component, status, component_name
+)
+VALUES (
+    '${table.classComment}管理', '', 2, 0, ${table.parentMenuId},
+    '${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 0, '${table.className}'
+);
+
+-- 按钮父菜单ID
+-- TODO: 请根据您的数据库类型,修改获取上一个插入 ID 的方式
+-- MySQL: SELECT @parentId := LAST_INSERT_ID();
+-- Oracle: SELECT system_menu_seq.CURRVAL INTO v_parent_id FROM DUAL;
+-- PostgreSQL: SELECT lastval() INTO v_parent_id;
+-- SQL Server: SET @parentId = SCOPE_IDENTITY();
+SELECT @parentId := LAST_INSERT_ID();
+
+-- 按钮 SQL
+#foreach ($functionName in $functionNames)
+#set ($index = $foreach.count - 1)
+INSERT INTO system_menu(
+    name, permission, type, sort, parent_id,
+    path, icon, component, status
+)
+VALUES (
+    '${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, @parentId,
+    '', '', '', 0
+);
+#end
+#end

+ 13 - 2
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java

@@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTa
 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
+import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO;
 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper;
 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
@@ -19,7 +20,9 @@ import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
 import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
 import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
 import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
+import cn.iocoder.yudao.module.infra.service.db.DataSourceConfigService;
 import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
+import com.baomidou.mybatisplus.annotation.DbType;
 import com.baomidou.mybatisplus.generator.config.po.TableField;
 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
 import jakarta.annotation.Resource;
@@ -62,6 +65,8 @@ public class CodegenServiceImplTest extends BaseDbUnitTest {
 
     @MockitoBean
     private DatabaseTableService databaseTableService;
+    @MockitoBean
+    private DataSourceConfigService dataSourceConfigService;
 
     @MockitoBean
     private CodegenBuilder codegenBuilder;
@@ -453,9 +458,12 @@ public class CodegenServiceImplTest extends BaseDbUnitTest {
         CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())
                 .setOrdinalPosition(2));
         codegenColumnMapper.insert(column02);
+        // mock 数据(DataSourceConfigDO)
+        when(dataSourceConfigService.getDataSourceConfig(eq(table.getDataSourceConfigId())))
+                .thenReturn(randomPojo(DataSourceConfigDO.class, o -> o.setUrl("jdbc:mysql://")));
         // mock 执行生成
         Map<String, String> codes = MapUtil.of(randomString(), randomString());
-        when(codegenEngine.execute(eq(table), argThat(columns -> {
+        when(codegenEngine.execute(eq(DbType.MYSQL), eq(table), argThat(columns -> {
             assertEquals(2, columns.size());
             assertEquals(column01, columns.get(0));
             assertEquals(column02, columns.get(1));
@@ -494,9 +502,12 @@ public class CodegenServiceImplTest extends BaseDbUnitTest {
         // mock 数据(sub CodegenColumnDO)
         CodegenColumnDO subColumn01 = randomPojo(CodegenColumnDO.class, o -> o.setId(1024L).setTableId(subTable.getId()));
         codegenColumnMapper.insert(subColumn01);
+        // mock 数据(DataSourceConfigDO)
+        when(dataSourceConfigService.getDataSourceConfig(eq(table.getDataSourceConfigId())))
+                .thenReturn(randomPojo(DataSourceConfigDO.class, o -> o.setUrl("jdbc:mysql://")));
         // mock 执行生成
         Map<String, String> codes = MapUtil.of(randomString(), randomString());
-        when(codegenEngine.execute(eq(table), argThat(columns -> {
+        when(codegenEngine.execute(eq(DbType.MYSQL), eq(table), argThat(columns -> {
             assertEquals(2, columns.size());
             assertEquals(column01, columns.get(0));
             assertEquals(column02, columns.get(1));

+ 4 - 3
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue2Test.java

@@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
+import com.baomidou.mybatisplus.annotation.DbType;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
@@ -28,7 +29,7 @@ public class CodegenEngineVue2Test extends CodegenEngineAbstractTest {
         List<CodegenColumnDO> columns = getColumnList("student");
 
         // 调用
-        Map<String, String> result = codegenEngine.execute(table, columns, null, null);
+        Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null);
         // 生成测试文件
         //writeResult(result, resourcesPath + "/vue2_one");
         // 断言
@@ -44,7 +45,7 @@ public class CodegenEngineVue2Test extends CodegenEngineAbstractTest {
         List<CodegenColumnDO> columns = getColumnList("category");
 
         // 调用
-        Map<String, String> result = codegenEngine.execute(table, columns, null, null);
+        Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null);
         // 生成测试文件
         //writeResult(result, resourcesPath + "/vue2_tree");
         // 断言
@@ -88,7 +89,7 @@ public class CodegenEngineVue2Test extends CodegenEngineAbstractTest {
         List<CodegenColumnDO> teacherColumns = getColumnList("teacher");
 
         // 调用
-        Map<String, String> result = codegenEngine.execute(table, columns,
+        Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns,
                 Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns));
         // 生成测试文件
         //writeResult(result, resourcesPath + path);

+ 4 - 3
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue3Test.java

@@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
+import com.baomidou.mybatisplus.annotation.DbType;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
@@ -28,7 +29,7 @@ public class CodegenEngineVue3Test extends CodegenEngineAbstractTest {
         List<CodegenColumnDO> columns = getColumnList("student");
 
         // 调用
-        Map<String, String> result = codegenEngine.execute(table, columns, null, null);
+        Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null);
         // 生成测试文件
         //writeResult(result, resourcesPath + "/vue3_one");
         // 断言
@@ -44,7 +45,7 @@ public class CodegenEngineVue3Test extends CodegenEngineAbstractTest {
         List<CodegenColumnDO> columns = getColumnList("category");
 
         // 调用
-        Map<String, String> result = codegenEngine.execute(table, columns, null, null);
+        Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null);
         // 生成测试文件
         //writeResult(result, resourcesPath + "/vue3_tree");
         // 断言
@@ -88,7 +89,7 @@ public class CodegenEngineVue3Test extends CodegenEngineAbstractTest {
         List<CodegenColumnDO> teacherColumns = getColumnList("teacher");
 
         // 调用
-        Map<String, String> result = codegenEngine.execute(table, columns,
+        Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns,
                 Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns));
         // 生成测试文件
         //writeResult(result, resourcesPath + path);