refactor(pigx-common-datasource): 重构数据源类型枚举,新增 AnyLine 解析适配器字段及插件状态查询

This commit is contained in:
PIGCLOUD committed 2026-05-24 18:49:20 +08:00
1 parent 0fca2924d4
commit 1b87ae9787
41 files changed
+1023 -557

No files matched your search

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,8 +30,8 @@ import lombok.RequiredArgsConstructor;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -1,6 +1,6 @@
package com.pig4cloud.pigx.common.datasource.annotation;
import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure;
import com.alibaba.druid.spring.boot4.autoconfigure.DruidDataSourceAutoConfigure;
import com.pig4cloud.pigx.common.datasource.DynamicDataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Import;
@@ -1,5 +1,6 @@
package com.pig4cloud.pigx.common.datasource.config;
import com.baomidou.dynamic.datasource.creator.druid.DruidConfig;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -11,31 +12,31 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
*/
@Data
@ConfigurationProperties("spring.datasource.druid")
public class DruidDataSourceProperties {
public class DruidDataSourceProperties extends DruidConfig {
/**
* 数据源用户名
*/
private String username;
/**
* 数据源用户名
*/
private String username;
/**
* 数据源密码
*/
private String password;
/**
* 数据源密码
*/
private String password;
/**
* jdbcurl
*/
private String url;
/**
* jdbcurl
*/
private String url;
/**
* 数据源驱动
*/
private String driverClassName;
/**
* 数据源驱动
*/
private String driverClassName;
/**
* 查询数据源的SQL
*/
private String queryDsSql = "select * from gen_datasource_conf where del_flag = '0'";
/**
* 查询数据源的SQL(使用参数化查询防止SQL注入,添加租户隔离)
*/
private String queryDsSql = "select * from gen_datasource_conf where del_flag = ?";
}
@@ -24,7 +24,7 @@ import com.baomidou.dynamic.datasource.provider.AbstractJdbcDataSourceProvider;
import com.pig4cloud.pigx.common.core.constant.enums.YesNoEnum;
import com.pig4cloud.pigx.common.datasource.support.DataSourceConstants;
import com.pig4cloud.pigx.common.datasource.util.DsConfTypeEnum;
import com.pig4cloud.pigx.common.datasource.util.DsJdbcUrlEnum;
import com.pig4cloud.pigx.common.datasource.util.DsTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.jasypt.encryption.StringEncryptor;
@@ -90,7 +90,7 @@ public class JdbcDynamicDataSourceProvider extends AbstractJdbcDataSourceProvide
String url;
// JDBC 配置形式
DsJdbcUrlEnum urlEnum = DsJdbcUrlEnum.get(dsType);
DsTypeEnum urlEnum = DsTypeEnum.get(dsType);
if (DsConfTypeEnum.JDBC.getType().equals(confType)) {
url = rs.getString(DataSourceConstants.DS_JDBC_URL);
} else {
@@ -103,6 +103,8 @@ public class JdbcDynamicDataSourceProvider extends AbstractJdbcDataSourceProvide
// Druid Config
DruidConfig druidConfig = new DruidConfig();
druidConfig.setProxyFilters(SQL_LOG_FILTER);
druidConfig.setConnectionErrorRetryAttempts(5);
druidConfig.setBreakAfterAcquireFailure(true);
druidConfig.setValidationQuery(urlEnum.getValidationQuery());
property.setDruid(druidConfig);
property.setUrl(url);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -19,7 +19,6 @@ package com.pig4cloud.pigx.common.datasource.config;
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.creator.druid.DruidConfig;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import javax.sql.DataSource;
@@ -63,9 +62,8 @@ public class MasterDataSourceProvider extends AbstractDataSourceProvider {
property.setPassword(properties.getPassword());
property.setUrl(properties.getUrl());
DruidConfig druidConfig = new DruidConfig();
druidConfig.setProxyFilters(SQL_LOG_FILTER);
property.setDruid(druidConfig);
properties.setProxyFilters(SQL_LOG_FILTER);
property.setDruid(properties);
map.put(DS_MASTER, defaultDataSourceCreator.createDataSource(property));
return map;
}
@@ -1,72 +0,0 @@
package com.pig4cloud.pigx.common.datasource.util;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* @author lengleng
* @date 2020/12/11
* <p>
* jdbc-url
*/
@Getter
@AllArgsConstructor
public enum DsJdbcUrlEnum {
/**
* mysql 数据库
*/
MYSQL("mysql",
"jdbc:mysql://%s:%s/%s?characterEncoding=utf8"
+ "&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true"
+ "&useLegacyDatetimeCode=false&allowMultiQueries=true&allowPublicKeyRetrieval=true",
"select 1", "mysql8 链接"),
/**
* pg 数据库
*/
PG("pg", "jdbc:postgresql://%s:%s/%s", "select 1", "postgresql 链接"),
/**
* SQL SERVER
*/
MSSQL("mssql", "jdbc:sqlserver://%s:%s;database=%s;characterEncoding=UTF-8", "select 1", "sqlserver 链接"),
/**
* oracle
*/
ORACLE("oracle", "jdbc:oracle:thin:@%s:%s:%s", "select 1 from dual", "oracle 链接"),
/**
* db2
*/
DB2("db2", "jdbc:db2://%s:%s/%s", "select 1 from sysibm.sysdummy1", "DB2 TYPE4 连接"),
/**
* 达梦
*/
DM("dm", "jdbc:dm://%s:%s/%s", "select 1 from dual", "达梦连接"),
/**
* pg 数据库
*/
HIGHGO("highgo", "jdbc:highgo://%s:%s/%s", "select 1", "highgo 链接");
private final String dbName;
private final String url;
private final String validationQuery;
private final String description;
public static DsJdbcUrlEnum get(String dsType) {
return Arrays.stream(DsJdbcUrlEnum.values())
.filter(dsJdbcUrlEnum -> dsType.equals(dsJdbcUrlEnum.getDbName()))
.findFirst()
.get();
}
}
@@ -0,0 +1,82 @@
package com.pig4cloud.pigx.common.datasource.util;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* @author lengleng
* @date 2020/12/11
* <p>
* 数据源类型枚举,包含 JDBC URL 模板、连接验证语句、描述及 AnyLine 解析适配器等元数据。
*/
@Getter
@AllArgsConstructor
public enum DsTypeEnum {
/**
* mysql 数据库
*/
MYSQL("mysql",
"jdbc:mysql://%s:%s/%s?characterEncoding=utf8"
+ "&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true"
+ "&useLegacyDatetimeCode=false&allowMultiQueries=true&allowPublicKeyRetrieval=true",
"select 1", "mysql8 链接", "org.anyline.data.jdbc.mysql.MySQLAdapter"),
/**
* pg 数据库
*/
PG("pg", "jdbc:postgresql://%s:%s/%s", "select 1", "postgresql 链接",
"org.anyline.data.jdbc.postgresql.PostgresqlAdapter"),
/**
* SQL SERVER
*/
MSSQL("mssql", "jdbc:sqlserver://%s:%s;database=%s;characterEncoding=UTF-8", "select 1", "sqlserver 链接",
"org.anyline.data.jdbc.mssql.MSSQLAdapter"),
/**
* oracle
*/
ORACLE("oracle", "jdbc:oracle:thin:@%s:%s:%s", "select 1 from dual", "oracle 链接",
"org.anyline.data.jdbc.oracle.OracleAdapter"),
/**
* db2
*/
DB2("db2", "jdbc:db2://%s:%s/%s", "select 1 from sysibm.sysdummy1", "DB2 TYPE4 连接",
"org.anyline.data.jdbc.db2.DB2Adapter"),
/**
* 达梦
*/
DM("dm", "jdbc:dm://%s:%s/%s", "select 1 from dual", "达梦连接", "org.anyline.data.jdbc.dm.DMAdapter"),
/**
* highgo 数据库
*/
HIGHGO("highgo", "jdbc:highgo://%s:%s/%s", "select 1", "highgo 链接",
"org.anyline.data.jdbc.highgo.HighgoAdapter");
private final String dbName;
private final String url;
private final String validationQuery;
private final String description;
/**
* AnyLine JDBC 解析适配器的全类名,用于运行时检测对应数据库方言插件是否已加载。
*/
private final String anylineAdapter;
public static DsTypeEnum get(String dsType) {
return Arrays.stream(DsTypeEnum.values())
.filter(dsTypeEnum -> dsType.equals(dsTypeEnum.getDbName()))
.findFirst()
.get();
}
}
@@ -23,12 +23,12 @@ public class PigxCodeGenDefaultProperties implements InitializingBean {
/**
* 是否开启在线更新
*/
private boolean autoCheckVersion = true;
private boolean autoCheckVersion = false;
/**
* 分支名称,默认为master
*/
private String branch = "next";
/**
* 分支名称,默认为 202601
*/
private String branch = "202601";
/**
* 模板项目地址
@@ -1,6 +1,6 @@
package com.pig4cloud.pigx.codegen.controller;
/*
* Copyright (c) 2018-2026, luolin All rights reserved.
* Copyright (c) 2018-2025, luolin All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -16,13 +16,13 @@ package com.pig4cloud.pigx.codegen.controller;
* Author: luolin (766488893@qq.com)
*/
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.codegen.entity.GenCreateTable;
import com.pig4cloud.pigx.codegen.service.GenCreateTableService;
import com.pig4cloud.pigx.codegen.util.AnylineDataSourceHelper;
import com.pig4cloud.pigx.codegen.util.vo.GenCreateTableVO;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.security.annotation.HasPermission;
@@ -84,12 +84,13 @@ public class GenCreateTableController {
@PostMapping
@HasPermission("codegen_table_add")
public R save(@RequestBody GenCreateTableVO createTableVO) {
// 切换目标数据源
DynamicDataSourceContextHolder.push(createTableVO.getDsName());
createTableService.createTable(createTableVO);
AnylineDataSourceHelper.run(createTableVO.getDsName(), () -> createTableService.createTable(createTableVO));
GenCreateTable createTable = new GenCreateTable();
BeanUtil.copyProperties(createTableVO, createTable);
DynamicDataSourceContextHolder.clear();
createTable.setId(createTableVO.getId());
createTable.setDsName(createTableVO.getDsName());
createTable.setTableName(createTableVO.getTableName());
createTable.setComments(createTableVO.getComments());
createTable.setColumnInfo(JSONUtil.toJsonStr(createTableVO.getColumnInfo()));
return R.ok(createTableService.saveOrUpdate(createTable));
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,7 +32,6 @@ import com.pig4cloud.pigx.common.xss.core.XssCleanIgnore;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.*;
import javax.sql.DataSource;
@@ -75,6 +74,16 @@ public class GenDsConfController {
return R.ok(datasourceConfService.list());
}
/**
* 查询数据源解析插件加载状态
*
* @return R 包含各数据源类型(dsType)与其 AnyLine 解析插件是否已加载(true/false)的映射
*/
@GetMapping("/parser-plugins")
public R parserPlugins() {
return R.ok(datasourceConfService.listParserPlugins());
}
/**
* 通过id查询数据源表
* @param id id
@@ -135,7 +144,7 @@ public class GenDsConfController {
// 生成
byte[] data = screw.documentGeneration(dsName, dataSource, screwProperties).toByteArray();
response.reset();
response.addHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(data.length));
response.setContentLength(data.length);
response.setContentType("application/octet-stream");
IoUtil.write(response.getOutputStream(), Boolean.FALSE, data);
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -126,22 +126,11 @@ public class GenTableController {
*
* @param dsName 数据源名称
* @param tableName 表名称
* @param isBatch 是否批量操作
* @return 操作结果
*/
@GetMapping("/sync/{dsName}/{tableName}")
public R<GenTable> syncTable(@PathVariable("dsName") String dsName, @PathVariable String tableName, @RequestParam(required = false) boolean isBatch) {
// 批量操作同步的时候,不需要删除
if (!isBatch) {
// 表配置删除
tableService.remove(
Wrappers.<GenTable>lambdaQuery().eq(GenTable::getDsName, dsName).eq(GenTable::getTableName, tableName));
// 字段配置删除
tableColumnService.remove(Wrappers.<GenTableColumnEntity>lambdaQuery()
.eq(GenTableColumnEntity::getDsName, dsName)
.eq(GenTableColumnEntity::getTableName, tableName));
}
return R.ok(tableService.queryOrBuildTable(dsName, tableName));
public R<GenTable> syncTable(@PathVariable("dsName") String dsName, @PathVariable String tableName) {
return R.ok(tableService.syncTable(dsName, tableName));
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -76,7 +76,7 @@ public class GeneratorController {
response.reset();
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=code.zip");
response.addHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(data.length));
response.setContentLength(data.length);
response.setContentType("application/octet-stream; charset=UTF-8");
IoUtil.write(response.getOutputStream(), false, data);
}
@@ -132,7 +132,7 @@ public class GeneratorController {
byte[] data = result.getBytes(StandardCharsets.UTF_8);
response.reset();
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=form.vue");
response.addHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(data.length));
response.setContentLength(data.length);
response.setContentType("application/octet-stream; charset=UTF-8");
IoUtil.write(response.getOutputStream(), false, data);
}
@@ -1,6 +1,6 @@
package com.pig4cloud.pigx.codegen.entity;
/*
* Copyright (c) 2018-2026, luolin All rights reserved.
* Copyright (c) 2018-2025, luolin All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -64,6 +64,18 @@ public class GenFieldType extends Model<GenFieldType> {
@Schema(description = "属性包名")
private String packageName;
/**
* 默认表单类型
*/
@Schema(description = "默认表单类型")
private String defaultFormType;
/**
* 默认查询表单类型
*/
@Schema(description = "默认查询表单类型")
private String defaultQueryFormType;
/**
* 创建人
*/
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -43,165 +43,171 @@ import java.util.List;
@Schema(description = "列属性")
public class GenTable extends Model<GenTable> {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "id")
private Long id;
/**
* id
*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "id")
private Long id;
/**
* 数据源名称
*/
@Schema(description = "数据源名称")
private String dsName;
/**
* 数据源名称
*/
@Schema(description = "数据源名称")
private String dsName;
/**
* 数据源类型
*/
@Schema(description = "数据源类型")
private String dbType;
/**
* 数据源类型
*/
@Schema(description = "数据源类型")
private String dbType;
/**
* 表名
*/
@Schema(description = "表名")
private String tableName;
/**
* 表名
*/
@Schema(description = "表名")
private String tableName;
/**
* 类名
*/
@Schema(description = "类名")
private String className;
/**
* 类名
*/
@Schema(description = "类名")
private String className;
/**
* 说明
*/
@Schema(description = "说明")
private String tableComment;
/**
* 说明
*/
@Schema(description = "说明")
private String tableComment;
/**
* 作者
*/
@Schema(description = "作者")
private String author;
/**
* 作者
*/
@Schema(description = "作者")
private String author;
/**
* 邮箱
*/
@Schema(description = "邮箱")
private String email;
/**
* 邮箱
*/
@Schema(description = "邮箱")
private String email;
/**
* 项目包名
*/
@Schema(description = "项目包名")
private String packageName;
/**
* 项目包名
*/
@Schema(description = "项目包名")
private String packageName;
/**
* 项目版本号
*/
@Schema(description = "项目版本号")
private String version;
/**
* 项目版本号
*/
@Schema(description = "项目版本号")
private String version;
/**
* 生成方式 0:zip压缩包 1:自定义目录
*/
@Schema(description = "生成方式 0:zip压缩包 1:自定义目录")
private String generatorType;
/**
* 生成方式 0:zip压缩包 1:自定义目录
*/
@Schema(description = "生成方式 0:zip压缩包 1:自定义目录")
private String generatorType;
/**
* 后端生成路径
*/
@Schema(description = "后端生成路径")
private String backendPath;
/**
* 后端生成路径
*/
@Schema(description = "后端生成路径")
private String backendPath;
/**
* 前端生成路径
*/
@Schema(description = "前端生成路径")
private String frontendPath;
/**
* 前端生成路径
*/
@Schema(description = "前端生成路径")
private String frontendPath;
/**
* 模块名
*/
@Schema(description = "模块名")
private String moduleName;
/**
* 模块名
*/
@Schema(description = "模块名")
private String moduleName;
/**
* 功能名
*/
@Schema(description = "功能名")
private String functionName;
/**
* 功能名
*/
@Schema(description = "功能名")
private String functionName;
/**
* 表单布局 1:一列 2:两列
*/
@Schema(description = "表单布局 1:一列 2:两列")
private Integer formLayout;
/**
* 表单布局 1:一列 2:两列
*/
@Schema(description = "表单布局 1:一列 2:两列")
private Integer formLayout;
/**
* 所属菜单ID
*/
@Schema(description = "所属菜单ID")
private Long syncMenuId;
/**
* 所属菜单ID
*/
@Schema(description = "所属菜单ID")
private Long syncMenuId;
/**
* 是否同步路由
*/
@Schema
private String syncRoute;
/**
* 是否同步路由
*/
@Schema
private String syncRoute;
/**
* 基类ID
*/
@Schema(description = "基类ID")
private Long baseclassId;
/**
* 基类ID
*/
@Schema(description = "基类ID")
private Long baseclassId;
/**
* 创建时间
*/
@Schema(description = "创建时间")
private LocalDateTime createTime;
/**
* 创建时间
*/
@Schema(description = "创建时间")
private LocalDateTime createTime;
/**
* 代码生成风格
*/
private Long style;
/**
* 代码生成风格
*/
private Long style;
/**
* 子表名称
*/
private String childTableName;
/**
* 子表名称
*/
private String childTableName;
/**
* 主表关联键
*/
private String mainField;
/**
* 主表关联键
*/
private String mainField;
/**
* 子表关联键
*/
private String childField;
/**
* 子表关联键
*/
private String childField;
/**
* 字段列表
*/
@TableField(exist = false)
private List<GenTableColumnEntity> fieldList;
/** 父字段 */
private String parentField;
/**
* 子表字段列表
*/
@TableField(exist = false)
private List<GenTableColumnEntity> childFieldList;
/** 名称字段 */
private String nameField;
/**
* 代码风格(模版分组信息)
*/
@TableField(exist = false)
private List<GenGroupEntity> groupList;
/**
* 字段列表
*/
@TableField(exist = false)
private List<GenTableColumnEntity> fieldList;
/**
* 子表字段列表
*/
@TableField(exist = false)
private List<GenTableColumnEntity> childFieldList;
/**
* 代码风格(模版分组信息)
*/
@TableField(exist = false)
private List<GenGroupEntity> groupList;
}
@@ -1,6 +1,6 @@
package com.pig4cloud.pigx.codegen.mapper;
/*
* Copyright (c) 2018-2026, luolin All rights reserved.
* Copyright (c) 2018-2025, luolin All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -1,7 +1,7 @@
package com.pig4cloud.pigx.codegen.service;
/*
* Copyright (c) 2018-2026, luolin All rights reserved.
* Copyright (c) 2018-2025, luolin All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -19,6 +19,8 @@ package com.pig4cloud.pigx.codegen.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.pig4cloud.pigx.codegen.entity.GenDatasourceConf;
import java.util.Map;
/**
* 数据源表
*
@@ -55,6 +57,13 @@ public interface GenDatasourceConfService extends IService<GenDatasourceConf> {
*/
Boolean checkDataSource(GenDatasourceConf datasourceConf);
/**
* 查询数据库解析插件加载状态
*
* @return 数据源类型与解析插件状态
*/
Map<String, Boolean> listParserPlugins();
/**
* 通过数据源名称删除
* @param dsIds 数据源ID
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,6 +32,8 @@ public interface GenTableColumnService extends IService<GenTableColumnEntity> {
void initFieldList(List<GenTableColumnEntity> tableFieldList);
void syncFieldList(String dsName, String tableName, List<GenTableColumnEntity> tableFieldList);
void updateTableField(String dsName, String tableName, List<GenTableColumnEntity> tableFieldList);
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -53,6 +53,15 @@ public interface GenTableService extends IService<GenTable> {
*/
GenTable queryOrBuildTable(String dsName, String tableName);
/**
* 同步表和字段配置
*
* @param dsName 数据源
* @param tableName 表名
* @return 同步后的表配置
*/
GenTable syncTable(String dsName, String tableName);
/**
* 查询表ddl 语句
*
@@ -1,6 +1,6 @@
package com.pig4cloud.pigx.codegen.service.impl;
/*
* Copyright (c) 2018-2026, luolin All rights reserved.
* Copyright (c) 2018-2025, luolin All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -16,14 +16,13 @@ package com.pig4cloud.pigx.codegen.service.impl;
* Author: luolin (766488893@qq.com)
*/
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.codegen.entity.GenCreateTable;
import com.pig4cloud.pigx.codegen.mapper.GenCreateTableMapper;
import com.pig4cloud.pigx.codegen.service.GenCreateTableService;
import com.pig4cloud.pigx.codegen.util.table.CreateTableHandler;
import com.pig4cloud.pigx.codegen.util.table.model.TableInfo;
import com.pig4cloud.pigx.codegen.util.vo.GenCreateTableColumnVO;
import com.pig4cloud.pigx.codegen.util.vo.GenCreateTableVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -32,6 +31,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.LinkedHashMap;
import java.util.List;
/**
* 自动创建表管理
@@ -50,17 +50,52 @@ public class CreateTableServiceImpl extends ServiceImpl<GenCreateTableMapper, Ge
@Override
public Boolean createTable(GenCreateTableVO createTableVO) {
String columnsInfo = createTableVO.getColumnsInfo();
TableInfo tableInfo = new TableInfo();
tableInfo.setName(createTableVO.getTableName());
LinkedHashMap<String, Column> columns = new LinkedHashMap<>();
LinkedHashMap<String, JSONObject> linkedHashMap = JSONUtil.toBean(columnsInfo, LinkedHashMap.class);
linkedHashMap.forEach((key, val) -> {
columns.put(key, JSONUtil.toBean(val, Column.class));
});
List<GenCreateTableColumnVO> columnInfoList = createTableVO.getColumnInfo();
if (columnInfoList != null) {
for (GenCreateTableColumnVO columnInfo : columnInfoList) {
Column column = buildColumn(columnInfo);
columns.put(column.getName(), column);
}
}
tableInfo.setColumns(columns);
tableInfo.setComment(createTableVO.getComments());
return createTableHandler.createTable(tableInfo);
return createTableHandler.createTable(createTableVO.getDsName(), tableInfo);
}
private Column buildColumn(GenCreateTableColumnVO columnInfo) {
Column column = new Column();
column.setName(columnInfo.getName());
column.setType(columnInfo.getType());
column.setComment(columnInfo.getComment());
column.setDefaultValue(columnInfo.getDefaultValue());
if (columnInfo.getLength() != null) {
column.setLength(columnInfo.getLength());
}
if (columnInfo.getPrecision() != null) {
column.setPrecision(columnInfo.getPrecision());
}
if (columnInfo.getScale() != null) {
column.setScale(columnInfo.getScale());
}
if (columnInfo.getNullable() != null) {
column.setNullable(columnInfo.getNullable());
}
if (columnInfo.getPrimary() != null) {
column.setPrimary(columnInfo.getPrimary());
}
if (columnInfo.getAutoIncrement() != null) {
column.setAutoIncrement(columnInfo.getAutoIncrement());
}
return column;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -17,6 +17,7 @@
package com.pig4cloud.pigx.codegen.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
@@ -28,7 +29,7 @@ import com.pig4cloud.pigx.codegen.mapper.GenDatasourceConfMapper;
import com.pig4cloud.pigx.codegen.service.GenDatasourceConfService;
import com.pig4cloud.pigx.common.core.util.SpringContextHolder;
import com.pig4cloud.pigx.common.datasource.util.DsConfTypeEnum;
import com.pig4cloud.pigx.common.datasource.util.DsJdbcUrlEnum;
import com.pig4cloud.pigx.common.datasource.util.DsTypeEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jasypt.encryption.StringEncryptor;
@@ -38,6 +39,8 @@ import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 数据源表
@@ -133,7 +136,7 @@ public class GenDatasourceConfServiceImpl extends ServiceImpl<GenDatasourceConfM
// 增加 ValidationQuery 参数
DruidConfig druidConfig = new DruidConfig();
DsJdbcUrlEnum urlEnum = DsJdbcUrlEnum.get(conf.getDsType());
DsTypeEnum urlEnum = DsTypeEnum.get(conf.getDsType());
druidConfig.setValidationQuery(urlEnum.getValidationQuery());
dataSourceProperty.setDruid(druidConfig);
DataSource dataSource = druidDataSourceCreator.createDataSource(dataSourceProperty);
@@ -153,14 +156,13 @@ public class GenDatasourceConfServiceImpl extends ServiceImpl<GenDatasourceConfM
// JDBC 配置形式
if (DsConfTypeEnum.JDBC.getType().equals(conf.getConfType())) {
url = conf.getUrl();
}
else if (DsJdbcUrlEnum.MSSQL.getDbName().equals(conf.getDsType())) {
} else if (DsTypeEnum.MSSQL.getDbName().equals(conf.getDsType())) {
// 主机形式 sql server 特殊处理
DsJdbcUrlEnum urlEnum = DsJdbcUrlEnum.get(conf.getDsType());
DsTypeEnum urlEnum = DsTypeEnum.get(conf.getDsType());
url = String.format(urlEnum.getUrl(), conf.getHost(), conf.getPort(), conf.getDsName());
}
else {
DsJdbcUrlEnum urlEnum = DsJdbcUrlEnum.get(conf.getDsType());
DsTypeEnum urlEnum = DsTypeEnum.get(conf.getDsType());
url = String.format(urlEnum.getUrl(), conf.getHost(), conf.getPort(), conf.getDsName());
}
@@ -175,4 +177,27 @@ public class GenDatasourceConfServiceImpl extends ServiceImpl<GenDatasourceConfM
return Boolean.TRUE;
}
/**
* 查询数据库解析插件加载状态
*
* @return 数据源类型与解析插件状态
*/
@Override
public Map<String, Boolean> listParserPlugins() {
Map<String, Boolean> result = new LinkedHashMap<>();
for (DsTypeEnum dsEnum : DsTypeEnum.values()) {
result.put(dsEnum.getDbName(), isClassPresent(dsEnum.getAnylineAdapter()));
}
return result;
}
private boolean isClassPresent(String className) {
try {
ClassUtil.loadClass(className, false);
return true;
} catch (Exception e) {
return false;
}
}
}
@@ -10,12 +10,12 @@ import com.pig4cloud.pigx.codegen.mapper.GenTableColumnMapper;
import com.pig4cloud.pigx.codegen.service.GenTableColumnService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 表字段信息管理
@@ -28,6 +28,8 @@ import java.util.concurrent.atomic.AtomicInteger;
public class GenTableColumnServiceImpl extends ServiceImpl<GenTableColumnMapper, GenTableColumnEntity>
implements GenTableColumnService {
private static final String DEFAULT_COMPONENT_TYPE = "text";
private final GenFieldTypeMapper fieldTypeMapper;
/**
@@ -35,39 +37,47 @@ public class GenTableColumnServiceImpl extends ServiceImpl<GenTableColumnMapper,
* @param tableFieldList 表单字段列表
*/
public void initFieldList(List<GenTableColumnEntity> tableFieldList) {
// 字段类型、属性类型映射
List<GenFieldType> list = fieldTypeMapper.selectList(Wrappers.emptyWrapper());
Map<String, GenFieldType> fieldTypeMap = new LinkedHashMap<>(list.size());
list.forEach(
fieldTypeMapping -> fieldTypeMap.put(fieldTypeMapping.getColumnType().toLowerCase(), fieldTypeMapping));
// 索引计数器
Map<String, GenFieldType> fieldTypeMap = this.buildFieldTypeMap();
AtomicInteger index = new AtomicInteger(0);
tableFieldList.forEach(field -> this.initNewField(field, fieldTypeMap, index));
}
@Override
public void syncFieldList(String dsName, String tableName, List<GenTableColumnEntity> tableFieldList) {
Map<String, GenFieldType> fieldTypeMap = this.buildFieldTypeMap();
List<GenTableColumnEntity> existingFieldList = this.list(Wrappers.<GenTableColumnEntity>lambdaQuery()
.eq(GenTableColumnEntity::getDsName, dsName)
.eq(GenTableColumnEntity::getTableName, tableName)
.orderByAsc(GenTableColumnEntity::getSort)
.orderByAsc(GenTableColumnEntity::getId));
Map<String, GenTableColumnEntity> existingFieldMap = existingFieldList.stream()
.collect(Collectors.toMap(GenTableColumnEntity::getFieldName, Function.identity(), (left, right) -> left,
LinkedHashMap::new));
int nextSort = existingFieldList.stream()
.map(GenTableColumnEntity::getSort)
.filter(Objects::nonNull)
.max(Comparator.naturalOrder())
.orElse(-1) + 1;
AtomicInteger sortCounter = new AtomicInteger(nextSort);
List<GenTableColumnEntity> mergedFieldList = new ArrayList<>(tableFieldList.size());
tableFieldList.forEach(field -> {
// 将字段名转化为驼峰格式
field.setAttrName(NamingCase.toCamelCase(field.getFieldName()));
GenTableColumnEntity existingField = existingFieldMap.remove(field.getFieldName());
if (Objects.isNull(existingField)) {
this.initNewField(field, fieldTypeMap, sortCounter);
mergedFieldList.add(field);
return;
}
this.mergeField(existingField, field, fieldTypeMap, sortCounter);
mergedFieldList.add(existingField);
});
// 获取字段对应的类型
GenFieldType fieldTypeMapping = fieldTypeMap.getOrDefault(field.getFieldType().toLowerCase(), null);
if (fieldTypeMapping == null) {
// 没找到对应的类型,则为Object类型
field.setAttrType("Object");
}
else {
field.setAttrType(fieldTypeMapping.getAttrType());
field.setPackageName(fieldTypeMapping.getPackageName());
}
// 设置查询类型和表单查询类型都为“=”
field.setQueryType("=");
field.setQueryFormType("text");
// 设置表单类型为文本框类型
field.setFormType("text");
// 保证审计字段最后显示
field.setSort(Objects.isNull(field.getSort()) ? index.getAndIncrement() : field.getSort());
});
if (!existingFieldMap.isEmpty()) {
this.removeBatchByIds(existingFieldMap.values().stream().map(GenTableColumnEntity::getId).toList());
}
if (!mergedFieldList.isEmpty()) {
this.saveOrUpdateBatch(mergedFieldList);
}
}
/**
@@ -77,7 +87,6 @@ public class GenTableColumnServiceImpl extends ServiceImpl<GenTableColumnMapper,
* @param tableFieldList 表单字段列表
*/
@Override
public void updateTableField(String dsName, String tableName, List<GenTableColumnEntity> tableFieldList) {
AtomicInteger sort = new AtomicInteger();
this.updateBatchById(tableFieldList.stream()
@@ -85,4 +94,59 @@ public class GenTableColumnServiceImpl extends ServiceImpl<GenTableColumnMapper,
.toList());
}
private Map<String, GenFieldType> buildFieldTypeMap() {
List<GenFieldType> list = fieldTypeMapper.selectList(Wrappers.emptyWrapper());
Map<String, GenFieldType> fieldTypeMap = new LinkedHashMap<>(list.size());
list.stream()
.filter(fieldType -> Objects.nonNull(fieldType.getColumnType()))
.forEach(fieldType -> fieldTypeMap.put(this.normalizeColumnType(fieldType.getColumnType()), fieldType));
return fieldTypeMap;
}
private void initNewField(GenTableColumnEntity field, Map<String, GenFieldType> fieldTypeMap,
AtomicInteger sortCounter) {
field.setAttrName(NamingCase.toCamelCase(field.getFieldName()));
this.applyFieldTypeMapping(field, fieldTypeMap);
field.setQueryType("=");
field.setSort(Objects.nonNull(field.getSort()) ? field.getSort() : sortCounter.getAndIncrement());
}
private void mergeField(GenTableColumnEntity existingField, GenTableColumnEntity latestField,
Map<String, GenFieldType> fieldTypeMap, AtomicInteger sortCounter) {
existingField.setFieldType(latestField.getFieldType());
existingField.setFieldComment(latestField.getFieldComment());
existingField.setPrimaryPk(latestField.getPrimaryPk());
this.applyFieldTypeMapping(existingField, fieldTypeMap);
if (Objects.isNull(existingField.getAttrName())) {
existingField.setAttrName(NamingCase.toCamelCase(existingField.getFieldName()));
}
if (Objects.isNull(existingField.getSort())) {
existingField.setSort(Objects.nonNull(latestField.getSort()) ? latestField.getSort() : sortCounter.getAndIncrement());
}
}
private void applyFieldTypeMapping(GenTableColumnEntity field, Map<String, GenFieldType> fieldTypeMap) {
GenFieldType fieldType = Objects.isNull(field.getFieldType()) ? null
: fieldTypeMap.get(this.normalizeColumnType(field.getFieldType()));
if (Objects.isNull(fieldType)) {
field.setAttrType("Object");
field.setPackageName(null);
field.setFormType(DEFAULT_COMPONENT_TYPE);
field.setQueryFormType(DEFAULT_COMPONENT_TYPE);
return;
}
field.setAttrType(fieldType.getAttrType());
field.setPackageName(fieldType.getPackageName());
field.setFormType(this.resolveComponentType(fieldType.getDefaultFormType()));
field.setQueryFormType(this.resolveComponentType(fieldType.getDefaultQueryFormType()));
}
private String resolveComponentType(String type) {
return StringUtils.hasText(type) ? type : DEFAULT_COMPONENT_TYPE;
}
private String normalizeColumnType(String type) {
return type.toLowerCase(Locale.ROOT);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -21,6 +21,9 @@ import cn.hutool.core.text.NamingCase;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.ds.ItemDataSource;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -34,10 +37,8 @@ import com.pig4cloud.pigx.codegen.mapper.GenTableMapper;
import com.pig4cloud.pigx.codegen.service.GenGroupService;
import com.pig4cloud.pigx.codegen.service.GenTableColumnService;
import com.pig4cloud.pigx.codegen.service.GenTableService;
import com.pig4cloud.pigx.codegen.util.AutoFillEnum;
import com.pig4cloud.pigx.codegen.util.BoolFillEnum;
import com.pig4cloud.pigx.codegen.util.CommonColumnFiledEnum;
import com.pig4cloud.pigx.codegen.util.GenKit;
import com.pig4cloud.pigx.codegen.util.*;
import com.pig4cloud.pigx.common.core.util.SpringContextHolder;
import lombok.RequiredArgsConstructor;
import org.anyline.metadata.Column;
import org.anyline.metadata.Database;
@@ -71,7 +72,6 @@ public class GenTableServiceImpl extends ServiceImpl<GenTableMapper, GenTable> i
private final GenGroupService genGroupService;
/**
* 查询表ddl 语句
*
@@ -117,8 +117,7 @@ public class GenTableServiceImpl extends ServiceImpl<GenTableMapper, GenTable> i
// 手动切换数据源
DynamicDataSourceContextHolder.push(table.getDsName());
CacheProxy.clear();
List<Table> tableList = ServiceProxy.metadata().tables()
.values().stream().filter(t -> {
List<Table> tableList = ServiceProxy.metadata().tables().values().stream().filter(t -> {
if (StrUtil.isBlank(table.getTableName())) {
return true;
}
@@ -129,12 +128,13 @@ public class GenTableServiceImpl extends ServiceImpl<GenTableMapper, GenTable> i
})
// 根据 createTime 、updateTime 倒序排序
.sorted((o1, o2) -> {
long time1 = (o1.getUpdateTime() != null ? o1.getUpdateTime().getTime() :
(o1.getCreateTime() != null ? o1.getCreateTime().getTime() : 0));
long time2 = (o2.getUpdateTime() != null ? o2.getUpdateTime().getTime() :
(o2.getCreateTime() != null ? o2.getCreateTime().getTime() : 0));
long time1 = (o1.getUpdateTime() != null ? o1.getUpdateTime().getTime()
: (o1.getCreateTime() != null ? o1.getCreateTime().getTime() : 0));
long time2 = (o2.getUpdateTime() != null ? o2.getUpdateTime().getTime()
: (o2.getCreateTime() != null ? o2.getCreateTime().getTime() : 0));
return NumberUtil.compare(time2, time1);
}).toList();
})
.toList();
// 根据 page 进行分页
List<Table> records = CollUtil.page((int) page.getCurrent() - 1, (int) page.getSize(), tableList);
@@ -152,9 +152,18 @@ public class GenTableServiceImpl extends ServiceImpl<GenTableMapper, GenTable> i
@Override
public List<Table> queryTableList(String dsName) {
// 手动切换数据源
DynamicRoutingDataSource dynamicRoutingDataSource = SpringContextHolder.getBean(DynamicRoutingDataSource.class);
DynamicDataSourceContextHolder.push(dsName);
CacheProxy.clear();
return ServiceProxy.metadata().tables().values().stream().toList();
List<Table> tableList = ServiceProxy.metadata().tables().values().stream().toList();
if (dynamicRoutingDataSource.getDataSource(dsName) instanceof ItemDataSource itemDataSource) {
for (Table table : tableList) {
if (itemDataSource.getDataSource() instanceof DruidDataSource druidDataSource) {
table.setExtend(druidDataSource.getDbType());
}
}
}
return tableList;
}
/**
@@ -185,20 +194,55 @@ public class GenTableServiceImpl extends ServiceImpl<GenTableMapper, GenTable> i
return genTable;
}
@Override
@Transactional(rollbackFor = Exception.class)
public GenTable syncTable(String dsName, String tableName) {
return AnylineDataSourceHelper.execute(dsName, () -> {
CacheProxy.clear();
AnylineService service = ServiceProxy.service(dsName);
Table tableMetadata = service.metadata().table(tableName);
Database database = service.metadata().database();
GenTable genTable = baseMapper.selectOne(
Wrappers.<GenTable>lambdaQuery().eq(GenTable::getTableName, tableName).eq(GenTable::getDsName, dsName));
if (Objects.isNull(genTable)) {
genTable = this.buildGenTable(dsName, tableName, tableMetadata, database);
DynamicDataSourceContextHolder.clear();
this.save(genTable);
} else {
this.refreshTableMetadata(genTable, tableMetadata, database);
DynamicDataSourceContextHolder.clear();
this.updateById(genTable);
}
List<GenTableColumnEntity> tableFieldList = getGenTableColumnEntities(dsName, tableName, tableMetadata);
columnService.syncFieldList(dsName, tableName, tableFieldList);
return this.queryOrBuildTable(dsName, tableName);
});
}
@Transactional(rollbackFor = Exception.class)
protected GenTable tableImport(String dsName, String tableName) {
// 手动切换数据源
DynamicDataSourceContextHolder.push(dsName);
return AnylineDataSourceHelper.execute(dsName, () -> {
CacheProxy.clear();
AnylineService service = ServiceProxy.service(dsName);
Table tableMetadata = service.metadata().table(tableName);
Database database = service.metadata().database();
GenTable table = this.buildGenTable(dsName, tableName, tableMetadata, database);
// 查询表是否存在
DynamicDataSourceContextHolder.clear();
this.save(table);
List<GenTableColumnEntity> tableFieldList = getGenTableColumnEntities(dsName, tableName, tableMetadata);
columnService.initFieldList(tableFieldList);
columnService.saveOrUpdateBatch(tableFieldList);
table.setFieldList(tableFieldList);
return table;
});
}
private GenTable buildGenTable(String dsName, String tableName, Table tableMetadata, Database database) {
GenTable table = new GenTable();
// 从数据库获取表信息
CacheProxy.clear();
AnylineService service = ServiceProxy.service();
Table tableMetadata = service.metadata().table(tableName);
Database database = service.metadata().database();
// 获取默认表配置信息 ()
table.setPackageName(defaultProperties.getPackageName());
table.setVersion(defaultProperties.getVersion());
table.setBackendPath(defaultProperties.getBackendPath());
@@ -208,33 +252,22 @@ public class GenTableServiceImpl extends ServiceImpl<GenTableMapper, GenTable> i
table.setTableName(tableName);
table.setDsName(dsName);
table.setTableComment(tableMetadata.getComment());
table.setDbType(database.getDatabaseType().title());
table.setFormLayout(defaultProperties.getFormLayout());
table.setSyncRoute(defaultProperties.getSyncRoute());
table.setGeneratorType(defaultProperties.getGeneratorType());
table.setClassName(NamingCase.toPascalCase(tableName));
// 模块名称默认为 admin
table.setModuleName(defaultProperties.getModuleName());
table.setFunctionName(GenKit.getFunctionName(tableName));
table.setCreateTime(LocalDateTime.now());
// 使用默认数据源
DynamicDataSourceContextHolder.clear();
this.save(table);
// 获取原生字段数据
List<GenTableColumnEntity> tableFieldList = getGenTableColumnEntities(dsName, tableName, tableMetadata);
// 初始化字段数据
columnService.initFieldList(tableFieldList);
// 保存列数据
columnService.saveOrUpdateBatch(tableFieldList);
table.setFieldList(tableFieldList);
return table;
}
private void refreshTableMetadata(GenTable table, Table tableMetadata, Database database) {
table.setTableComment(tableMetadata.getComment());
table.setDbType(database.getDatabaseType().title());
}
/**
* 获取表字段信息
*
@@ -255,7 +288,7 @@ public class GenTableServiceImpl extends ServiceImpl<GenTableMapper, GenTable> i
genTableColumnEntity.setFieldComment(column.getComment());
genTableColumnEntity.setFieldType(column.getTypeName());
genTableColumnEntity.setPrimaryPk(
column.isPrimaryKey() == 1 ? BoolFillEnum.TRUE.getValue() : BoolFillEnum.FALSE.getValue());
column.isPrimaryKey() ? BoolFillEnum.TRUE.getValue() : BoolFillEnum.FALSE.getValue());
genTableColumnEntity.setAutoFill(AutoFillEnum.DEFAULT.name());
genTableColumnEntity.setFormItem(BoolFillEnum.TRUE.getValue());
genTableColumnEntity.setGridItem(BoolFillEnum.TRUE.getValue());
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -41,9 +41,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@@ -55,8 +53,11 @@ import java.util.Set;
@Slf4j
@Service
@RequiredArgsConstructor
public class GenTemplateServiceImpl extends ServiceImpl<GenTemplateMapper, GenTemplateEntity>
implements GenTemplateService {
public class GenTemplateServiceImpl extends ServiceImpl<GenTemplateMapper, GenTemplateEntity> implements GenTemplateService {
private static final String CONFIG_JSON_FILE = "config.json";
private static final String VERSION_FILE = "VERSION";
private final PigxCodeGenDefaultProperties defaultProperties;
@@ -64,7 +65,6 @@ public class GenTemplateServiceImpl extends ServiceImpl<GenTemplateMapper, GenTe
private final GenGroupMapper genGroupMapper;
/**
* 在线更新
*
@@ -74,17 +74,16 @@ public class GenTemplateServiceImpl extends ServiceImpl<GenTemplateMapper, GenTe
@Transactional(rollbackFor = Exception.class)
public R onlineUpdate() {
// 获取 config.json 和 version 文件
Map<String, Object> configAndVersion = getConfigAndVersion();
JSONObject configJsonObj = (JSONObject) configAndVersion.get("configJsonObj");
String versionFile = (String) configAndVersion.get("versionFile");
ConfigAndVersion configAndVersion = getConfigAndVersion();
JSONObject configJsonObj = configAndVersion.getConfigJsonObj();
String versionFile = configAndVersion.getVersionFile();
// 查询出全部的模板组名称
Set<String> cgtmConfigGroupNames = configJsonObj.keySet();
// 根据模板组名称+version 查询是否存在,不存在则新增,存在跳过
for (String cgtmConfigGroupName : cgtmConfigGroupNames) {
boolean exists = genGroupMapper.exists(Wrappers.<GenGroupEntity>lambdaQuery()
.eq(GenGroupEntity::getGroupName, cgtmConfigGroupName + versionFile));
boolean exists = groupExists(withVersion(cgtmConfigGroupName, versionFile));
if (exists) {
continue;
@@ -101,6 +100,7 @@ public class GenTemplateServiceImpl extends ServiceImpl<GenTemplateMapper, GenTe
*
* @return {@link R }
*/
@Override
public R checkVersion() {
// 关闭在线更新提示
if (!defaultProperties.isAutoCheckVersion()) {
@@ -108,16 +108,15 @@ public class GenTemplateServiceImpl extends ServiceImpl<GenTemplateMapper, GenTe
}
// 获取 config.json 和 version 文件
Map<String, Object> configAndVersion = getConfigAndVersion();
JSONObject configJsonObj = (JSONObject) configAndVersion.get("configJsonObj");
String versionFile = (String) configAndVersion.get("versionFile");
ConfigAndVersion configAndVersion = getConfigAndVersion();
JSONObject configJsonObj = configAndVersion.getConfigJsonObj();
String versionFile = configAndVersion.getVersionFile();
// 查询出全部的模板组名称
boolean exists = false;
Set<String> cgtmConfigGroupNames = configJsonObj.keySet();
for (String cgtmConfigGroupName : cgtmConfigGroupNames) {
exists = genGroupMapper.exists(Wrappers.<GenGroupEntity>lambdaQuery()
.eq(GenGroupEntity::getGroupName, cgtmConfigGroupName + versionFile));
exists = groupExists(withVersion(cgtmConfigGroupName, versionFile));
}
return R.ok(exists);
@@ -126,25 +125,19 @@ public class GenTemplateServiceImpl extends ServiceImpl<GenTemplateMapper, GenTe
/**
* 获取配置和版本
*
* @return {@link Map }<{@link String }, {@link Object }>
* @return {@link ConfigAndVersion }
*/
private Map<String, Object> getConfigAndVersion() {
private ConfigAndVersion getConfigAndVersion() {
// 获取 config.json 和 version 文件
String configFile = getCGTMFile("config.json");
String versionFile = getCGTMFile("VERSION");
String configFile = getCGTMFile(CONFIG_JSON_FILE);
String versionFile = getCGTMFile(VERSION_FILE);
// 解析 config.json
JSONObject configJsonObj = JSONUtil.parseObj(configFile);
// 将 configJsonObj 和 versionFile 放入 Map 中
Map<String, Object> configAndVersion = new HashMap<>();
configAndVersion.put("configJsonObj", configJsonObj);
configAndVersion.put("versionFile", versionFile);
return configAndVersion;
return new ConfigAndVersion(configJsonObj, versionFile);
}
/**
* 插入模板文件
*
@@ -154,33 +147,16 @@ public class GenTemplateServiceImpl extends ServiceImpl<GenTemplateMapper, GenTe
*/
private void insertTemplateFiles(String version, JSONObject configJsonObj, String groupName) {
// 创建新的 group
GenGroupEntity genGroupEntity = new GenGroupEntity();
genGroupEntity.setGroupName(groupName + version);
genGroupMapper.insert(genGroupEntity);
GenGroupEntity genGroupEntity = createGroup(groupName, version);
// 解析json配置文件
List<GenTemplateFileVO> templateFileVOList = configJsonObj.getBeanList(groupName, GenTemplateFileVO.class);
for (GenTemplateFileVO genTemplateFileVO : templateFileVOList) {
// 1. 获取模板文件
String templateFile = getCGTMFile(genTemplateFileVO.getTemplateFile());
// 2. 插入模板文件
GenTemplateEntity genTemplateEntity = new GenTemplateEntity();
genTemplateEntity.setTemplateName(genTemplateFileVO.getTemplateName() + version);
genTemplateEntity.setTemplateDesc(genTemplateFileVO.getTemplateName() + version);
genTemplateEntity.setTemplateCode(templateFile);
genTemplateEntity.setGeneratorPath(genTemplateFileVO.getGeneratorPath());
baseMapper.insert(genTemplateEntity);
// 3. 插入模板组关联
GenTemplateGroupEntity genTemplateGroupEntity = new GenTemplateGroupEntity();
genTemplateGroupEntity.setTemplateId(genTemplateEntity.getId());
genTemplateGroupEntity.setGroupId(genGroupEntity.getId());
genTemplateGroupMapper.insert(genTemplateGroupEntity);
GenTemplateEntity genTemplateEntity = getOrCreateTemplate(genTemplateFileVO, version);
createTemplateGroupRelationIfAbsent(genTemplateEntity.getId(), genGroupEntity.getId());
}
}
/**
* 获取 cgtmfile
*
@@ -188,14 +164,82 @@ public class GenTemplateServiceImpl extends ServiceImpl<GenTemplateMapper, GenTe
* @return {@link String }
*/
private String getCGTMFile(String fileName) {
HttpResponse response = HttpRequest.get(String.format("%s/CGTM/raw/%s/%s", DefaultConstants.CGTM_URL, defaultProperties.getBranch(), fileName))
.execute();
String requestUrl = String.format("%s/CGTM/raw/%s/%s", DefaultConstants.CGTM_URL, defaultProperties.getBranch(), fileName);
HttpResponse response = HttpRequest.get(requestUrl).execute();
String responseBody = response.body();
int httpStatus = response.getStatus();
if (response.getStatus() == HttpStatus.HTTP_OK || StrUtil.isNotBlank(response.body())) {
return response.body();
} else {
log.warn("在线更新模板失败:{} ,Http Code:{}", fileName, response.getStatus());
throw new CheckedException("在线更新模板失败,任务终止!");
if (httpStatus == HttpStatus.HTTP_OK || StrUtil.isNotBlank(responseBody)) {
return responseBody;
}
log.warn("在线更新模板失败:{} ,Http Code:{}", fileName, httpStatus);
throw new CheckedException("在线更新模板失败,任务终止!");
}
private boolean groupExists(String groupName) {
return genGroupMapper.exists(Wrappers.<GenGroupEntity>lambdaQuery().eq(GenGroupEntity::getGroupName, groupName));
}
private GenGroupEntity createGroup(String groupName, String version) {
GenGroupEntity genGroupEntity = new GenGroupEntity();
genGroupEntity.setGroupName(withVersion(groupName, version));
genGroupMapper.insert(genGroupEntity);
return genGroupEntity;
}
private GenTemplateEntity getOrCreateTemplate(GenTemplateFileVO templateFileVO, String version) {
String templateName = withVersion(templateFileVO.getTemplateName(), version);
GenTemplateEntity genTemplateEntity = findTemplateByName(templateName);
if (genTemplateEntity != null) {
log.info("模板文件已存在,复用: {}", templateName);
return genTemplateEntity;
}
GenTemplateEntity templateEntity = new GenTemplateEntity();
templateEntity.setTemplateName(templateName);
templateEntity.setTemplateDesc(templateName);
templateEntity.setTemplateCode(getCGTMFile(templateFileVO.getTemplateFile()));
templateEntity.setGeneratorPath(templateFileVO.getGeneratorPath());
baseMapper.insert(templateEntity);
log.info("模板文件已插入: {}", templateName);
return templateEntity;
}
private GenTemplateEntity findTemplateByName(String templateName) {
return baseMapper.selectOne(Wrappers.<GenTemplateEntity>lambdaQuery().eq(GenTemplateEntity::getTemplateName, templateName));
}
private void createTemplateGroupRelationIfAbsent(Long templateId, Long groupId) {
boolean relationExists = genTemplateGroupMapper.exists(Wrappers.<GenTemplateGroupEntity>lambdaQuery().eq(GenTemplateGroupEntity::getTemplateId, templateId).eq(GenTemplateGroupEntity::getGroupId, groupId));
if (relationExists) {
return;
}
GenTemplateGroupEntity genTemplateGroupEntity = new GenTemplateGroupEntity();
genTemplateGroupEntity.setTemplateId(templateId);
genTemplateGroupEntity.setGroupId(groupId);
genTemplateGroupMapper.insert(genTemplateGroupEntity);
}
private String withVersion(String name, String version) {
return name + version;
}
@RequiredArgsConstructor
private static final class ConfigAndVersion {
private final JSONObject configJsonObj;
private final String versionFile;
private JSONObject getConfigJsonObj() {
return configJsonObj;
}
private String getVersionFile() {
return versionFile;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2026, lengleng All rights reserved.
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -223,10 +223,10 @@ public class GeneratorServiceImpl implements GeneratorService {
Map<String, Object> dataModel = getDataModel(genTable.getId());
// 获取模板信息,Lambda 表达式简化代码
GenTemplateEntity genTemplateEntity = genTemplateService.getOneOpt(Wrappers.<GenTemplateEntity>lambdaQuery()
GenTemplateEntity genTemplateEntity = genTemplateService
.getOneOpt(Wrappers.<GenTemplateEntity>lambdaQuery()
.likeRight(GenTemplateEntity::getTemplateName, GeneratorStyleEnum.VFORM_JSON.getDesc())
.orderByDesc(GenTemplateEntity::getCreateTime), false
)
.orderByDesc(GenTemplateEntity::getCreateTime), false)
.orElseThrow(() -> new CheckedException("模板不存在"));
// 渲染模板并返回结果
return VelocityKit.renderStr(genTemplateEntity.getTemplateCode(), dataModel);
@@ -257,10 +257,10 @@ public class GeneratorServiceImpl implements GeneratorService {
dataModel.put("resultMap", resultMap);
// 获取模板信息 查询模板中最新的 vform.json 文件
GenTemplateEntity genTemplateEntity = genTemplateService.getOneOpt(Wrappers.<GenTemplateEntity>lambdaQuery()
GenTemplateEntity genTemplateEntity = genTemplateService
.getOneOpt(Wrappers.<GenTemplateEntity>lambdaQuery()
.likeRight(GenTemplateEntity::getTemplateName, GeneratorStyleEnum.VFORM_VUE.getDesc())
.orderByDesc(GenTemplateEntity::getCreateTime), false
)
.orderByDesc(GenTemplateEntity::getCreateTime), false)
.orElseThrow(() -> new CheckedException("模板不存在"));
// 渲染模板并返回结果
@@ -294,7 +294,9 @@ public class GeneratorServiceImpl implements GeneratorService {
query.setName(menuName);
query.setMenuType(MenuTypeEnum.LEFT_MENU.getType());
List<SysMenu> existingMenus = RetOps.of(menuService.getMenuDetails(query)).getData().orElse(Collections.emptyList());
List<SysMenu> existingMenus = RetOps.of(menuService.getMenuDetails(query))
.getData()
.orElse(Collections.emptyList());
if (!CollUtil.isEmpty(existingMenus)) {
return;
@@ -320,7 +322,11 @@ public class GeneratorServiceImpl implements GeneratorService {
sysMenu.setParentId(table.getSyncMenuId());
sysMenu.setName(menuName);
sysMenu.setMenuType(MenuTypeEnum.LEFT_MENU.getType());
sysMenu.setPath(String.format("/%s/%s/index", table.getModuleName(), table.getFunctionName()));
sysMenu.setVisible(YesNoEnum.YES.getCode());
sysMenu.setKeepAlive(YesNoEnum.NO.getCode());
sysMenu.setEmbedded(YesNoEnum.NO.getCode());
sysMenu.setSortOrder(0);
sysMenu.setPath(String.format("/%s/%s/index", normalizedModuleName(table), table.getFunctionName()));
return sysMenu;
}
@@ -333,13 +339,19 @@ public class GeneratorServiceImpl implements GeneratorService {
private void createButtons(GenTable table, Long parentId) {
String[] buttonNames = {"查看", "新增", "编辑", "删除", "导入导出"};
String[] permissions = {"view", "add", "edit", "del", "export"};
String moduleName = normalizedModuleName(table);
for (int i = 0; i < buttonNames.length; i++) {
String permission = String.format("%s_%s_%s", moduleName, table.getFunctionName(), permissions[i]);
SysMenu button = new SysMenu();
button.setParentId(parentId);
button.setMenuType(MenuTypeEnum.BUTTON.getType());
button.setName(buttonNames[i]);
button.setPermission(String.format("%s_%s_%s", table.getModuleName(), table.getFunctionName(), permissions[i]));
button.setVisible(YesNoEnum.YES.getCode());
button.setKeepAlive(YesNoEnum.NO.getCode());
button.setEmbedded(YesNoEnum.NO.getCode());
button.setSortOrder(0);
button.setPermission(StrUtil.toLowerCase(permission));
menuService.saveMenu(button);
}
}
@@ -354,7 +366,9 @@ public class GeneratorServiceImpl implements GeneratorService {
return;
}
List<SysRouteConf> existingRoutes = RetOps.of(routeService.getRouteDetails()).getData().orElse(Collections.emptyList());
List<SysRouteConf> existingRoutes = RetOps.of(routeService.getRouteDetails())
.getData()
.orElse(Collections.emptyList());
boolean exist = existingRoutes.stream()
.anyMatch(routeConf -> routeConf.getRouteId().equals(table.getModuleName()));
@@ -376,7 +390,9 @@ public class GeneratorServiceImpl implements GeneratorService {
SysRouteConf sysRouteConf = new SysRouteConf();
sysRouteConf.setRouteId(table.getModuleName());
sysRouteConf.setRouteName(table.getModuleName());
sysRouteConf.setPredicates(String.format("[{\"args\": {\"_genkey_0\": \"/%s/**\"}, \"name\": \"Path\"}]", table.getModuleName()));
sysRouteConf.setPredicates(
String.format("[{\"args\": {\"_genkey_0\": \"/%s/**\"}, \"name\": \"Path\"}]"
, normalizedModuleName(table)));
sysRouteConf.setFilters("[]");
sysRouteConf.setUri(String.format("lb://%s-biz", table.getModuleName()));
return sysRouteConf;
@@ -410,8 +426,9 @@ public class GeneratorServiceImpl implements GeneratorService {
dataModel.put(DataModelConstants.PACKAGE, table.getPackageName());
dataModel.put(DataModelConstants.PACKAGE_PATH, table.getPackageName().replace(".", "/"));
dataModel.put(DataModelConstants.VERSION, table.getVersion());
dataModel.put(DataModelConstants.MODULE_NAME, table.getModuleName());
dataModel.put(DataModelConstants.MODULE_NAME_UPPER_FIRST, StrUtil.upperFirst(table.getModuleName()));
String moduleName = normalizedModuleName(table);
dataModel.put(DataModelConstants.MODULE_NAME, moduleName);
dataModel.put(DataModelConstants.MODULE_NAME_UPPER_FIRST, StrUtil.upperFirst(moduleName));
dataModel.put(DataModelConstants.FUNCTION_NAME, table.getFunctionName());
dataModel.put(DataModelConstants.FUNCTION_NAME_UPPER_FIRST, StrUtil.upperFirst(table.getFunctionName()));
dataModel.put(DataModelConstants.FORM_LAYOUT, table.getFormLayout());
@@ -445,15 +462,27 @@ public class GeneratorServiceImpl implements GeneratorService {
dataModel.put(DataModelConstants.MAIN_FIELD, NamingCase.toCamelCase(table.getMainField()));
dataModel.put(DataModelConstants.CHILD_FIELD, NamingCase.toCamelCase(table.getChildField()));
dataModel.put(DataModelConstants.CHILD_CLASS_NAME_UPPER_FIRST, NamingCase.toPascalCase(childTableName));
dataModel.put(DataModelConstants.CHILD_CLASS_NAME, StrUtil.lowerFirst(NamingCase.toPascalCase(childTableName)));
dataModel.put(DataModelConstants.CHILD_CLASS_NAME,
StrUtil.lowerFirst(NamingCase.toPascalCase(childTableName)));
// 设置是否是多租户模式 (判断字段列表中是否包含 tenant_id 字段)
childFieldList.stream().filter(genTableColumnEntity -> genTableColumnEntity.getFieldName().equals("tenant_id"))
.findFirst().ifPresent(columnEntity -> dataModel.put(DataModelConstants.IS_CHILD_TENANT, true));
childFieldList.stream()
.filter(genTableColumnEntity -> genTableColumnEntity.getFieldName().equals("tenant_id"))
.findFirst()
.ifPresent(columnEntity -> dataModel.put(DataModelConstants.IS_CHILD_TENANT, true));
}
// 设置树表
if (StrUtil.isNotBlank(table.getParentField())) {
dataModel.put(DataModelConstants.TREE_PARENT_FIELD, NamingCase.toCamelCase(table.getParentField()));
dataModel.put(DataModelConstants.TREE_NAME_FIELD, NamingCase.toCamelCase(table.getNameField()));
}
// 设置是否是多租户模式 (判断字段列表中是否包含 tenant_id 字段)
table.getFieldList().stream().filter(genTableColumnEntity -> genTableColumnEntity.getFieldName().equals("tenant_id"))
.findFirst().ifPresent(columnEntity -> dataModel.put(DataModelConstants.IS_TENANT, true));
table.getFieldList()
.stream()
.filter(genTableColumnEntity -> genTableColumnEntity.getFieldName().equals("tenant_id"))
.findFirst()
.ifPresent(columnEntity -> dataModel.put(DataModelConstants.IS_TENANT, true));
return dataModel;
}
@@ -467,6 +496,16 @@ public class GeneratorServiceImpl implements GeneratorService {
return StrUtil.startWith(SpringBootVersion.getVersion(), "3");
}
/**
* 获取去掉中划线的模块名称
*
* @param table 表配置
* @return 去掉中划线后的模块名称
*/
private String normalizedModuleName(GenTable table) {
return StrUtil.removeAll(table.getModuleName(), StrUtil.DASHED);
}
/**
* 将表字段按照类型分组并存储到数据模型中
*
@@ -0,0 +1,88 @@
package com.pig4cloud.pigx.codegen.util;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import lombok.experimental.UtilityClass;
import org.anyline.data.datasource.DataSourceHolder;
import javax.sql.DataSource;
import java.util.function.Supplier;
/**
* Anyline 动态数据源辅助类。
* <p>
* 统一封装以下动作:
* <ul>
* <li>根据数据源名称获取动态数据源</li>
* <li>按需向 Anyline 注册 {@link javax.sql.DataSource}</li>
* <li>切换 {@link DynamicDataSourceContextHolder} 上下文并在执行结束后清理</li>
* </ul>
* 业务层只需要关注具体操作逻辑,不再重复处理数据源切换细节。
*/
@UtilityClass
public class AnylineDataSourceHelper {
/**
* 在指定数据源上下文中执行无返回值逻辑。
*
* @param dsName 数据源名称
* @param action 要执行的业务逻辑
*/
public void run(String dsName, Runnable action) {
execute(dsName, () -> {
action.run();
return null;
});
}
/**
* 在指定数据源上下文中执行有返回值逻辑。
* <p>
* 进入执行前会确保 Anyline 已注册对应数据源,并在 finally 中清理动态数据源上下文。
*
* @param dsName 数据源名称
* @param action 要执行的业务逻辑
* @param <T> 返回值类型
* @return 业务逻辑返回值
*/
public <T> T execute(String dsName, Supplier<T> action) {
if (StrUtil.isBlank(dsName)) {
throw new IllegalArgumentException("dsName must not be blank");
}
DynamicRoutingDataSource routingDataSource = SpringUtil.getBean(DynamicRoutingDataSource.class);
DataSource dataSource = routingDataSource.getDataSource(dsName);
if (dataSource == null) {
throw new IllegalArgumentException("DataSource not found: " + dsName);
}
registerIfAbsent(dsName, dataSource);
DynamicDataSourceContextHolder.push(dsName);
try {
return action.get();
} finally {
DynamicDataSourceContextHolder.clear();
}
}
/**
* 按需向 Anyline 注册数据源,避免重复注册。
*
* @param dsName 数据源名称
* @param dataSource Spring 动态数据源中解析出的数据源实例
*/
private void registerIfAbsent(String dsName, DataSource dataSource) {
if (DataSourceHolder.exists(dsName)) {
return;
}
try {
DataSourceHolder.reg(dsName, dataSource);
} catch (Exception e) {
throw new IllegalStateException("Failed to register Anyline datasource: " + dsName, e);
}
}
}
@@ -1,7 +1,7 @@
package com.pig4cloud.pigx.codegen.util;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* @author lengleng
@@ -10,7 +10,7 @@ import lombok.Getter;
* 通用字段的填充策略和显示策略
*/
@Getter
@AllArgsConstructor
@RequiredArgsConstructor
public enum CommonColumnFiledEnum {
/**
@@ -42,21 +42,21 @@ public enum CommonColumnFiledEnum {
/**
* 表单是否默认显示 1/0
*/
private String formItem;
private final String formItem;
/**
* 表格是否默认显示 1/0
*/
private String gridItem;
private final String gridItem;
/**
* 自动填充策略
*/
private String autoFill;
private final String autoFill;
/**
* 排序值
*/
private Integer sort;
private final Integer sort;
}
@@ -7,52 +7,81 @@ package com.pig4cloud.pigx.codegen.util;
* @date 2024/7/16
*/
public class DataModelConstants {
// 基本信息
public static final String IS_SPRING_BOOT_3 = "isSpringBoot3";
public static final String SYNC_MENU_ID = "syncMenuId";
public static final String DB_TYPE = "dbType";
public static final String PACKAGE = "package";
public static final String PACKAGE_PATH = "packagePath";
public static final String VERSION = "version";
// 模块和功能名称
public static final String MODULE_NAME = "moduleName";
public static final String MODULE_NAME_UPPER_FIRST = "ModuleName";
public static final String FUNCTION_NAME = "functionName";
public static final String FUNCTION_NAME_UPPER_FIRST = "FunctionName";
// 基本信息
public static final String IS_SPRING_BOOT_3 = "isSpringBoot3";
// 布局和样式
public static final String FORM_LAYOUT = "formLayout";
public static final String STYLE = "style";
public static final String SYNC_MENU_ID = "syncMenuId";
// 作者和时间
public static final String AUTHOR = "author";
public static final String DATETIME = "datetime";
public static final String DATE = "date";
public static final String DB_TYPE = "dbType";
// 导入列表
public static final String IMPORT_LIST = "importList";
public static final String PACKAGE = "package";
// 表信息
public static final String TABLE_NAME = "tableName";
public static final String TABLE_COMMENT = "tableComment";
public static final String CLASS_NAME = "className";
public static final String CLASS_NAME_UPPER_FIRST = "ClassName";
public static final String FIELD_LIST = "fieldList";
public static final String PACKAGE_PATH = "packagePath";
// 路径
public static final String BACKEND_PATH = "backendPath";
public static final String FRONTEND_PATH = "frontendPath";
public static final String VERSION = "version";
// 子表信息
public static final String CHILD_FIELD_LIST = "childFieldList";
public static final String CHILD_TABLE_NAME = "childTableName";
public static final String MAIN_FIELD = "mainField";
public static final String CHILD_FIELD = "childField";
public static final String CHILD_CLASS_NAME_UPPER_FIRST = "ChildClassName";
public static final String CHILD_CLASS_NAME = "childClassName";
public static final String IS_CHILD_TENANT = "isChildTenant";
// 模块和功能名称
public static final String MODULE_NAME = "moduleName";
public static final String MODULE_NAME_UPPER_FIRST = "ModuleName";
public static final String FUNCTION_NAME = "functionName";
public static final String FUNCTION_NAME_UPPER_FIRST = "FunctionName";
// 布局和样式
public static final String FORM_LAYOUT = "formLayout";
public static final String STYLE = "style";
// 作者和时间
public static final String AUTHOR = "author";
public static final String DATETIME = "datetime";
public static final String DATE = "date";
// 导入列表
public static final String IMPORT_LIST = "importList";
// 表信息
public static final String TABLE_NAME = "tableName";
public static final String TABLE_COMMENT = "tableComment";
public static final String CLASS_NAME = "className";
public static final String CLASS_NAME_UPPER_FIRST = "ClassName";
public static final String FIELD_LIST = "fieldList";
// 路径
public static final String BACKEND_PATH = "backendPath";
public static final String FRONTEND_PATH = "frontendPath";
// 子表信息
public static final String CHILD_FIELD_LIST = "childFieldList";
public static final String CHILD_TABLE_NAME = "childTableName";
public static final String MAIN_FIELD = "mainField";
public static final String CHILD_FIELD = "childField";
public static final String CHILD_CLASS_NAME_UPPER_FIRST = "ChildClassName";
public static final String CHILD_CLASS_NAME = "childClassName";
public static final String IS_CHILD_TENANT = "isChildTenant";
// 树表信息
public static final String TREE_PARENT_FIELD = "parentField";
public static final String TREE_NAME_FIELD = "nameField";
// 租户信息
public static final String IS_TENANT = "isTenant";
// 租户信息
public static final String IS_TENANT = "isTenant";
}
@@ -1,7 +1,7 @@
package com.pig4cloud.pigx.codegen.util;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* 代码生成主题
@@ -9,7 +9,7 @@ import lombok.Getter;
* @author 冷冷
*/
@Getter
@AllArgsConstructor
@RequiredArgsConstructor
public enum GeneratorStyleEnum {
VFORM_JSON(1L, "vform.json"),
@@ -19,11 +19,11 @@ public enum GeneratorStyleEnum {
/**
* 对应模板ID
*/
private Long templateId;
private final Long templateId;
/**
* 描述
*/
private String desc;
private final String desc;
}
@@ -2,6 +2,8 @@ package com.pig4cloud.pigx.codegen.util;
import cn.hutool.core.text.NamingCase;
import java.util.Locale;
/**
* 命名规则处理,针对驼峰,下划线等处理
*
@@ -10,26 +12,37 @@ import cn.hutool.core.text.NamingCase;
*/
public class NamingCaseTool {
/**
* 传入字段获取的get方法
* @param in 字段名称
* @return
*/
public static String getProperty(String in) {
return String.format("get%s", NamingCase.toPascalCase(in));
}
/**
* 传入字段获取的get方法
*
* @param in 字段名称
* @return
*/
public static String getProperty(String in) {
return "get" + NamingCase.toPascalCase(in);
}
public static String setProperty(String in) {
return String.format("set%s", NamingCase.toPascalCase(in));
}
public static String setProperty(String in) {
return "set" + NamingCase.toPascalCase(in);
}
/**
* 首字母大写
* @param in 字段
* @return 首字母大写
*/
public static String pascalCase(String in) {
return String.format(NamingCase.toPascalCase(in));
}
/**
* 首字母大写
*
* @param in 字段
* @return 首字母大写
*/
public static String pascalCase(String in) {
return NamingCase.toPascalCase(in);
}
/**
* 将字符串转换为小写
*
* @param in 输入字符串
* @return 转换为小写后的字符串
*/
public static String lowerCase(String in) {
return in.toLowerCase(Locale.ROOT);
}
}
@@ -1,7 +1,7 @@
package com.pig4cloud.pigx.codegen.util;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* vfrom 字段类型
@@ -10,7 +10,7 @@ import lombok.Getter;
* @date 2023/6/5
*/
@Getter
@AllArgsConstructor
@RequiredArgsConstructor
public enum VFormTypeEnum {
GRID("grid"),
@@ -36,36 +36,37 @@ import org.springframework.stereotype.Component;
@RequiredArgsConstructor
public class CreateTableHandler {
/**
* 运行表单主键ID
*/
private final static String RUN_FORM_COLUMN_NAME = "run_form_id";
/**
* 运行表单主键ID
*/
private final static String RUN_FORM_COLUMN_NAME = "run_form_id";
/**
* 自动创建表
* @param tableInfo 表信息
*/
public Boolean createTable(TableInfo tableInfo) {
if (tableInfo.getColumns() == null || tableInfo.getColumns().isEmpty()) {
throw new RuntimeException("自动创建表[" + tableInfo.getName() + "]中至少需要一个字段");
}
if (!TableModelEnum.CREATE.name().toLowerCase().equals(tableInfo.getModel())) {
throw new RuntimeException("自动创建表[" + tableInfo.getModel() + "]模式的处理未找到,请检查");
}
try {
AnylineService service = ServiceProxy.service();
// 如果已存在,删除重键
Table table = service.metadata().table(tableInfo.getName(), false);
if (null != table)
service.ddl().drop(table);
// 执行建表SQL
service.ddl().create(tableInfo);
log.info("自动创建表处理完成!");
}
catch (Exception e) {
throw new RuntimeException("自动创建表异常", e);
}
return Boolean.TRUE;
}
/**
* 自动创建表
*
* @param dsName
* @param tableInfo 表信息
*/
public Boolean createTable(String dsName, TableInfo tableInfo) {
if (tableInfo.getColumns() == null || tableInfo.getColumns().isEmpty()) {
throw new RuntimeException("自动创建表[" + tableInfo.getName() + "]中至少需要一个字段");
}
if (!TableModelEnum.CREATE.name().toLowerCase().equals(tableInfo.getModel())) {
throw new RuntimeException("自动创建表[" + tableInfo.getModel() + "]模式的处理未找到,请检查");
}
try {
AnylineService service = ServiceProxy.service(dsName);
// 如果已存在,删除重键
Table table = service.metadata().table(tableInfo.getName(), false);
if (null != table)
service.ddl().drop(table);
// 执行建表SQL
service.ddl().create(tableInfo);
log.info("自动创建表处理完成!");
} catch (Exception e) {
throw new RuntimeException("自动创建表异常", e);
}
return Boolean.TRUE;
}
}
@@ -1,6 +1,6 @@
package com.pig4cloud.pigx.codegen.util.table.enums;
/*
* Copyright (c) 2018-2026, luolin All rights reserved.
* Copyright (c) 2018-2025, luolin All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -1,6 +1,6 @@
package com.pig4cloud.pigx.codegen.util.table.model;
/*
* Copyright (c) 2018-2026, luolin All rights reserved.
* Copyright (c) 2018-2025, luolin All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -0,0 +1,48 @@
package com.pig4cloud.pigx.codegen.util.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.FieldNameConstants;
/**
* 自动创建表字段信息
*
* @author luolin
* @date 2026-04-10
*/
@Data
@FieldNameConstants
@Schema(description = "自动创建表字段信息")
public class GenCreateTableColumnVO {
@Schema(description = "字段名称")
private String name;
@Schema(description = "字段注释")
private String comment;
@Schema(description = "字段类型")
private String type;
@Schema(description = "字段长度")
private Integer length;
@Schema(description = "精度")
private Integer precision;
@Schema(description = "小数位")
private Integer scale;
@Schema(description = "默认值")
private Object defaultValue;
@Schema(description = "是否主键")
private Boolean primary;
@Schema(description = "是否允许为空")
private Boolean nullable;
@Schema(description = "是否自增")
private Boolean autoIncrement;
}
@@ -1,6 +1,6 @@
package com.pig4cloud.pigx.codegen.util.vo;
/*
* Copyright (c) 2018-2026, luolin All rights reserved.
* Copyright (c) 2018-2025, luolin All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -19,8 +19,10 @@ package com.pig4cloud.pigx.codegen.util.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.experimental.FieldNameConstants;
import java.time.LocalDateTime;
import java.util.List;
/**
* 自动创建表管理
@@ -29,6 +31,7 @@ import java.time.LocalDateTime;
* @date 2022-09-23 21:56:11
*/
@Data
@FieldNameConstants
@Schema(description = "自动创建表管理")
public class GenCreateTableVO {
@@ -80,16 +83,10 @@ public class GenCreateTableVO {
@Schema(description = "创建时间")
private LocalDateTime createTime;
/**
* 表字段信息
*/
@Schema(description = "表字段信息")
private String columnsInfo;
/**
* 字段信息
*/
@Schema(description = "字段信息")
private String columnInfo;
private List<GenCreateTableColumnVO> columnInfo;
}
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2018-2026, lengleng All rights reserved.
~ Copyright (c) 2018-2025, lengleng All rights reserved.
~
~ Redistribution and use in source and binary forms, with or without
~ modification, are permitted provided that the following conditions are met:
@@ -2,7 +2,7 @@
<!--
~
~ Copyright (c) 2018-2026, lengleng All rights reserved.
~ Copyright (c) 2018-2025, lengleng All rights reserved.
~
~ Redistribution and use in source and binary forms, with or without
~ modification, are permitted provided that the following conditions are met:
@@ -28,6 +28,8 @@
<result property="columnType" column="column_type"/>
<result property="attrType" column="attr_type"/>
<result property="packageName" column="package_name"/>
<result property="defaultFormType" column="default_form_type"/>
<result property="defaultQueryFormType" column="default_query_form_type"/>
<result property="createTime" column="create_time"/>
</resultMap>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2018-2026, lengleng All rights reserved.
~ Copyright (c) 2018-2025, lengleng All rights reserved.
~
~ Redistribution and use in source and binary forms, with or without
~ modification, are permitted provided that the following conditions are met:
@@ -2,7 +2,7 @@
<!--
~
~ Copyright (c) 2018-2026, lengleng All rights reserved.
~ Copyright (c) 2018-2025, lengleng All rights reserved.
~
~ Redistribution and use in source and binary forms, with or without
~ modification, are permitted provided that the following conditions are met: