diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java index 01efb65ca7..3e3ff2dbf6 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java +++ b/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 diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java index 76a51e8eda..458acb540b 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java +++ b/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 execute(CodegenTableDO table, List columns, + public Map execute(DbType dbType, CodegenTableDO table, List columns, List subTables, List> subColumnsList) { // 1.1 初始化 bindMap 上下文 - Map bindingMap = initBindingMap(table, columns, subTables, subColumnsList); + Map bindingMap = initBindingMap(dbType, table, columns, subTables, subColumnsList); // 1.2 获得模版 Map templates = getTemplates(table.getFrontType()); @@ -425,10 +427,11 @@ public class CodegenEngine { return content; } - private Map initBindingMap(CodegenTableDO table, List columns, + private Map initBindingMap(DbType dbType, CodegenTableDO table, List columns, List subTables, List> subColumnsList) { // 创建 bindingMap Map bindingMap = new HashMap<>(globalBindingMap); + bindingMap.put("dbType", dbType); bindingMap.put("table", table); bindingMap.put("columns", columns); bindingMap.put("primaryColumn", CollectionUtils.findFirst(columns, CodegenColumnDO::getPrimaryKey)); // 主键字段 diff --git a/yudao-module-infra/src/main/resources/codegen/sql/sql.vm b/yudao-module-infra/src/main/resources/codegen/sql/sql.vm index 41b107dbac..6e50837ca6 100644 --- a/yudao-module-infra/src/main/resources/codegen/sql/sql.vm +++ b/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 --- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 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 \ No newline at end of file +#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 diff --git a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java index 1e2ecbc27c..86f1f10d8c 100644 --- a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java +++ b/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 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 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)); diff --git a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue2Test.java b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue2Test.java index a251484df5..9cc0e05c9b 100644 --- a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue2Test.java +++ b/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 columns = getColumnList("student"); // 调用 - Map result = codegenEngine.execute(table, columns, null, null); + Map result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); // 生成测试文件 //writeResult(result, resourcesPath + "/vue2_one"); // 断言 @@ -44,7 +45,7 @@ public class CodegenEngineVue2Test extends CodegenEngineAbstractTest { List columns = getColumnList("category"); // 调用 - Map result = codegenEngine.execute(table, columns, null, null); + Map result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); // 生成测试文件 //writeResult(result, resourcesPath + "/vue2_tree"); // 断言 @@ -88,7 +89,7 @@ public class CodegenEngineVue2Test extends CodegenEngineAbstractTest { List teacherColumns = getColumnList("teacher"); // 调用 - Map result = codegenEngine.execute(table, columns, + Map result = codegenEngine.execute(DbType.MYSQL, table, columns, Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns)); // 生成测试文件 //writeResult(result, resourcesPath + path); diff --git a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue3Test.java b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue3Test.java index 7695dac70f..109e44ff69 100644 --- a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue3Test.java +++ b/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 columns = getColumnList("student"); // 调用 - Map result = codegenEngine.execute(table, columns, null, null); + Map result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); // 生成测试文件 //writeResult(result, resourcesPath + "/vue3_one"); // 断言 @@ -44,7 +45,7 @@ public class CodegenEngineVue3Test extends CodegenEngineAbstractTest { List columns = getColumnList("category"); // 调用 - Map result = codegenEngine.execute(table, columns, null, null); + Map result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); // 生成测试文件 //writeResult(result, resourcesPath + "/vue3_tree"); // 断言 @@ -88,7 +89,7 @@ public class CodegenEngineVue3Test extends CodegenEngineAbstractTest { List teacherColumns = getColumnList("teacher"); // 调用 - Map result = codegenEngine.execute(table, columns, + Map result = codegenEngine.execute(DbType.MYSQL, table, columns, Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns)); // 生成测试文件 //writeResult(result, resourcesPath + path);