Преглед на файлове

创建数据源独立模块

aokunsang преди 3 седмици
родител
ревизия
ecf61b7aa6
променени са 33 файла, в които са добавени 2887 реда и са изтрити 0 реда
  1. 76 0
      platomix-gmetry-datasource/pom.xml
  2. 196 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/AbstractGmetryDialect.java
  3. 137 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/IGmetryDialect.java
  4. 60 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/config/GmetryDatasourceAutoConfiguration.java
  5. 30 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/constants/DbConstant.java
  6. 25 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/constants/DsConstant.java
  7. 43 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/context/DialectContext.java
  8. 153 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/ClickhouseGmetryDialect.java
  9. 86 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/DamengGmetryDialect.java
  10. 90 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/KingbaseGmetryDialect.java
  11. 90 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/MysqlGmetryDialect.java
  12. 91 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/OracleGmetryDialect.java
  13. 97 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/PostgresqlGmetryDialect.java
  14. 224 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/SqlServerGmetryDialect.java
  15. 96 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/UXDBGmetryDialect.java
  16. 90 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/XuGuGmetryDialect.java
  17. 24 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/ColumnTypeEnum.java
  18. 54 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/DateFormatEnum.java
  19. 104 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/DetailColumnTypeEnum.java
  20. 251 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/DsTypeEnum.java
  21. 68 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/FunctionMethodEnum.java
  22. 101 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/NumberFormatEnum.java
  23. 98 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/ViewColumnTypeEnum.java
  24. 67 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/model/DatasourceDto.java
  25. 114 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/model/FileStructureDto.java
  26. 17 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/model/LongReference.java
  27. 77 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/model/TableColumnDto.java
  28. 39 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/model/TableViewDto.java
  29. 87 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/support/BladexDataSourceProvider.java
  30. 94 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/support/DynamicDataSourceSupport.java
  31. 105 0
      platomix-gmetry-datasource/src/main/java/org/springblade/datasource/util/DatasourceUtil.java
  32. 2 0
      platomix-gmetry-datasource/src/main/resources/META-INF/spring.factories
  33. 1 0
      pom.xml

+ 76 - 0
platomix-gmetry-datasource/pom.xml

@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.platomix</groupId>
+        <artifactId>platomix-pom</artifactId>
+        <version>1.2.1</version>
+        <relativePath />
+    </parent>
+    <artifactId>platomix-gmetry-datasource</artifactId>
+    <version>1.0.0</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.platomix</groupId>
+            <artifactId>platomix-gmetry-common</artifactId>
+            <version>1.1.8</version>
+        </dependency>
+        <!-- 导入mybatis-plus依赖 -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>dynamic-datasource-creator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.clickhouse</groupId>
+            <artifactId>clickhouse-jdbc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.oracle</groupId>
+            <artifactId>ojdbc7</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.microsoft.sqlserver</groupId>
+            <artifactId>mssql-jdbc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.kingbase8</groupId>
+            <artifactId>kingbase8</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.dameng</groupId>
+            <artifactId>DmJdbcDriver18</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.uxdb</groupId>
+            <artifactId>UxJdbcDriver</artifactId>
+            <version>${uxdb.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 196 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/AbstractGmetryDialect.java

@@ -0,0 +1,196 @@
+/**
+ * 
+ */
+package org.springblade.datasource;
+
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.datasource.constants.DbConstant;
+import org.springblade.datasource.enums.DateFormatEnum;
+import org.springblade.datasource.enums.DetailColumnTypeEnum;
+import org.springblade.datasource.enums.FunctionMethodEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+import org.springblade.datasource.model.DatasourceDto;
+import org.springblade.datasource.model.TableColumnDto;
+import org.springblade.datasource.model.TableViewDto;
+import org.springblade.datasource.util.DatasourceUtil;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author wookvn
+ *
+ */
+@Slf4j
+public abstract class AbstractGmetryDialect implements IGmetryDialect {
+
+	protected final Map<ViewColumnTypeEnum, String> columnTypeMap = new ConcurrentHashMap<>();
+	
+	protected final Map<FunctionMethodEnum, String> functionMethodMap = new ConcurrentHashMap<>();
+	
+	protected final Map<DateFormatEnum, String> dateFormatMap = new ConcurrentHashMap<>();
+	
+	@Override
+	public List<TableViewDto> listTableViewsByDatasource(DatasourceDto datasource) {
+		return listTableViewsByDatasource(datasource, null);
+	}
+	
+	@Override
+	public List<TableColumnDto> listTableColumnsByTableViewName(DatasourceDto datasource, String tableViewName) {
+		if(datasource == null) {
+			return null;
+		}
+		List<TableColumnDto> list = new ArrayList<TableColumnDto>();
+		try (Connection connection = DatasourceUtil.createConnection(datasource);){
+			DatabaseMetaData metaData = connection.getMetaData();
+			String schemaPattern = "%" + dbSchema(datasource) + "%";
+			ResultSet rs = metaData.getColumns(null, schemaPattern, tableViewName, "%");
+			ResultSet pkRs = metaData.getPrimaryKeys(null, schemaPattern, tableViewName);
+			List<String> primaryKeyColumnList = new ArrayList<>();
+			while(pkRs.next()) {
+				primaryKeyColumnList.add(pkRs.getString("COLUMN_NAME"));
+			}
+			while(rs.next()) {
+				TableColumnDto columnDto = new TableColumnDto();
+				columnDto.setColumnComments(rs.getString("REMARKS"));
+				columnDto.setDataType(rs.getString("TYPE_NAME"));
+				columnDto.setColumnName(rs.getString("COLUMN_NAME"));
+				columnDto.setColumnSize(rs.getInt("COLUMN_SIZE"));
+				columnDto.setDecimalDigits(rs.getInt("DECIMAL_DIGITS"));
+				columnDto.setColumnType(ViewColumnTypeEnum.resolve(rs.getInt("DATA_TYPE")));
+				columnDto.setDetailColumnType(DetailColumnTypeEnum.resolve(rs.getInt("DATA_TYPE")));
+				//IS_NULLABLE - YES/NO  NULLABLE - 1(允许为空)/2(不确定)/0(不允许为空)
+				columnDto.setNullAbleStatus("yes".equalsIgnoreCase(rs.getString("IS_NULLABLE")) ? 1 : 0); 
+				//是否主键
+				columnDto.setPrimaryKeyStatus(primaryKeyColumnList.contains(rs.getString("COLUMN_NAME")) ? 1 : 0);
+				//IS_AUTOINCREMENT YES/NO 是否自增
+				if(primaryKeyColumnList.contains(rs.getString("COLUMN_NAME")) && "YES".equals(rs.getString("IS_AUTOINCREMENT"))) {
+					columnDto.setAutoIncrementStatus(1);
+				}
+				list.add(columnDto);
+			}
+			pkRs.close();
+			rs.close();
+		} catch (Exception e) {
+			log.error(e.getMessage(), e);
+		}
+		return list;
+	}
+
+	@Override
+	public String getColumnType(ViewColumnTypeEnum columnType, Integer columnSize, Integer decimalDigits) {
+		String value = columnTypeMap.get(columnType);
+		if(StrUtil.isEmpty(value)) {
+			throw new RuntimeException("数据类型不存在|"+columnType);
+		}
+		if(columnType == ViewColumnTypeEnum.STRING) {
+			return String.format(value, columnSize == null || columnSize <= 0 ? DbConstant.DEFAULT_COLUMN_STRING_SIZE : columnSize);
+		}
+		if(columnType == ViewColumnTypeEnum.NUMBER) {
+			columnSize = columnSize == null || columnSize <= 0 ? DbConstant.DEFAULT_COLUMN_NUMBER_SIZE : columnSize;
+			decimalDigits = decimalDigits == null ? DbConstant.DEFAULT_COLUMN_NUMBER_DIGITS : decimalDigits;
+			return String.format(value, columnSize, decimalDigits);
+		}
+		return value;
+	}
+	
+	@Override
+	public String formatDateTime(DateFormatEnum dateTimeFormat, String columnSql) {
+		String value = dateFormatMap.get(dateTimeFormat);
+		if(StrUtil.isEmpty(value)) {
+			throw new RuntimeException("日期类型不存在|"+dateTimeFormat+"或不支持该格式转换");
+		}
+		return formatMethodFunction(FunctionMethodEnum.DATE_TO_STR, columnSql, value);
+	}
+	
+	@Override
+	public String formatMethodFunction(FunctionMethodEnum functionMethod, Object... args) {
+		String value = functionMethodMap.get(functionMethod);
+		if(StrUtil.isEmpty(value)) {
+			throw new RuntimeException("函数方法不存在|"+functionMethod+"或不支持该函数方法");
+		}
+		return String.format(value, args);
+	}
+	
+	@Override
+	public String buildCreateViewSql(String viewName, String sqlStatement) {
+		return String.format(DbConstant.CREATE_REPLACE_VIEW_SQL_FORMAT, viewName, sqlStatement);
+	}
+	
+	@Override
+	public String convertDataType(ViewColumnTypeEnum oldColumnType, ViewColumnTypeEnum newColumnType, String columnSql,
+			DateFormatEnum dateFormat) {
+		FunctionMethodEnum functionMethod = null;
+		if(oldColumnType == ViewColumnTypeEnum.STRING && newColumnType == ViewColumnTypeEnum.DATETIME) {
+			functionMethod = FunctionMethodEnum.STR_TO_DATE;
+		}else if(oldColumnType == ViewColumnTypeEnum.NUMBER && newColumnType == ViewColumnTypeEnum.DATETIME) {
+			functionMethod = FunctionMethodEnum.NUMBER_TO_DATE;
+		}else if(oldColumnType == ViewColumnTypeEnum.DATETIME && newColumnType == ViewColumnTypeEnum.STRING) {
+			functionMethod = FunctionMethodEnum.DATE_TO_STR;
+		}
+		if(oldColumnType == null || oldColumnType == newColumnType || functionMethod == null) {
+			return columnSql;
+		}
+		String dateTimeFormat = "";
+		if(dateFormat != null && (oldColumnType == ViewColumnTypeEnum.DATETIME || newColumnType == ViewColumnTypeEnum.DATETIME)) {
+			dateTimeFormat = dateFormatMap.get(dateFormat);
+			if(StrUtil.isEmpty(dateTimeFormat)) {
+				throw new RuntimeException("日期类型不存在|"+dateTimeFormat+"或不支持日期格式");
+			}
+		}
+		return formatMethodFunction(functionMethod, columnSql, dateTimeFormat);
+	}
+
+	@Override
+	public List<TableViewDto> listTableViewsByDatasource(DatasourceDto datasource,String tableName) {
+		if(datasource == null) {
+			return null;
+		}
+		List<TableViewDto> list = new ArrayList<TableViewDto>();
+		try (Connection connection = DatasourceUtil.createConnection(datasource);){
+			DatabaseMetaData metaData = connection.getMetaData();
+			//此处添加两个类型:"REMOTE TABLE", "MEMORY TABLE" - clickhouse支持
+			String schemaPattern = "%" + dbSchema(datasource) + "%",
+					tableNamePattern = StrUtil.isNotBlank(tableName) ? ("%" + tableName + "%") : null;
+			ResultSet rs = metaData.getTables(null, schemaPattern, tableNamePattern, new String[] {"TABLE", "VIEW", "REMOTE TABLE", "MEMORY TABLE"});
+			while(rs.next()) {
+				list.add(new TableViewDto(rs.getString("TABLE_NAME"), rs.getString("REMARKS"), datasource.getId()));
+			}
+			rs.close();
+		} catch (Exception e) {
+			log.error(e.getMessage(), e);
+		}
+		return list;
+	}
+	
+	@Override
+	public void executeSql(List<String> sqls, DatasourceDto datasource) throws Exception {
+		Connection connection = null;
+        Statement statement = null;
+        try {
+            connection = DatasourceUtil.createConnection(datasource);
+            statement = connection.createStatement();
+            connection.setAutoCommit(false);
+            for (String sql : sqls) {
+                statement.execute(sql);
+            }
+            connection.commit();
+        } catch(Exception e){
+            if(connection != null){
+				connection.rollback();
+			}
+            throw e;
+        } finally {
+			IoUtil.close(statement);
+			IoUtil.close(connection);
+        }
+	}
+}

+ 137 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/IGmetryDialect.java

@@ -0,0 +1,137 @@
+/**
+ * 
+ */
+package org.springblade.datasource;
+
+import cn.hutool.core.util.StrUtil;
+import org.springblade.datasource.enums.DateFormatEnum;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springblade.datasource.enums.FunctionMethodEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+import org.springblade.datasource.model.TableColumnDto;
+import org.springblade.datasource.model.TableViewDto;
+import org.springblade.datasource.model.DatasourceDto;
+import org.springblade.datasource.model.FileStructureDto;
+
+import java.util.List;
+
+/**
+ * @author wookvn
+ *
+ *	
+ */
+public interface IGmetryDialect {
+
+	/**
+	 * 查询表或视图列表
+	 * @param datasource
+	 * @return
+	 */
+	public List<TableViewDto> listTableViewsByDatasource(DatasourceDto datasource);
+
+	/**
+	 * 查询某一个视图或表的信息
+	 * @param datasource
+	 * @param tableViewName
+	 * @return
+	 */
+	public List<TableViewDto> listTableViewsByDatasource(DatasourceDto datasource, String tableViewName);
+	
+	/**
+	 * 查询字段列表
+	 * @param datasource
+	 * @param tableViewName
+	 * @return
+	 */
+	public List<TableColumnDto> listTableColumnsByTableViewName(DatasourceDto datasource, String tableViewName);
+	
+	/**
+	 * 通过上传的文件生成创建表的SQL
+	 * @param tableName
+	 * @param tableComment
+	 * @param structureList
+	 * @return
+	 */
+	public List<String> buildCreateTableSql(String tableName, String tableComment, List<FileStructureDto> structureList);
+	
+	/**
+	 * 构造创建视图的SQL
+	 * @param viewName
+	 * @param sqlStatement
+	 * @return
+	 */
+	public String buildCreateViewSql(String viewName, String sqlStatement);
+	
+	/**
+	 * 数据的类型转换
+	 * @param oldColumnType
+	 * @param newColumnType
+	 * @param columnSql
+	 * @param dateFormat
+	 * @return
+	 */
+	public String convertDataType(ViewColumnTypeEnum oldColumnType, ViewColumnTypeEnum newColumnType, String columnSql, DateFormatEnum dateFormat);
+	
+	/**
+	 * 获取字段类型数据
+	 * @param columnType
+	 * @return
+	 */
+	public String getColumnType(ViewColumnTypeEnum columnType, Integer columnSize, Integer decimalDigits);
+	
+	/**
+	 * 获取日期格式化后的字符串
+	 * @param dateTimeFormat
+	 * @return
+	 */
+	public String formatDateTime(DateFormatEnum dateTimeFormat, String columnSql);
+	
+	/**
+	 * 获取方法函数格式化后的字符串
+	 * @param functionMethod
+	 * @param args
+	 * @return
+	 */
+	public String formatMethodFunction(FunctionMethodEnum functionMethod, Object... args);
+	
+	/**
+	 * 数据源类型
+	 * @return
+	 */
+	public DsTypeEnum dsType();
+
+	/**
+	 * 获取DB Schema
+	 * @param datasource
+	 * @return
+	 */
+	default String dbSchema(DatasourceDto datasource) {
+		return StrUtil.isBlank(datasource.getDbSchema()) ? datasource.getDsUser() : datasource.getDbSchema();
+	}
+
+	/**
+	 * 获取SELECT SQL的表名,比如:SQLServer需要特殊处理。 dbo.xxx_table
+	 * @param datasource
+	 * @param tableName
+	 * @return
+	 */
+	default String dbTableName(DatasourceDto datasource, String tableName) {
+		return quoteIdentifier(tableName);
+	}
+
+	/**
+	 * 数据库转义处理 - 比如:mysql字段名和表名添加``
+	 * @param name
+	 * @return
+	 */
+	default String quoteIdentifier(String name) {
+		return name;
+	}
+
+	/**
+	 * 执行SQL
+	 * @param sqls
+	 */
+	public void executeSql(List<String> sqls, DatasourceDto datasource) throws Exception;
+
+}

+ 60 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/config/GmetryDatasourceAutoConfiguration.java

@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018-2028, AoKunSang All rights reserved.
+ * 我问青山何时老,青山问我几时闲,
+ * 不是闲人闲不得,能闲必非等闲人。
+ */
+package org.springblade.datasource.config;
+
+import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
+import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
+import com.baomidou.dynamic.datasource.creator.druid.DruidDataSourceCreator;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
+import org.springblade.datasource.support.BladexDataSourceProvider;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Arrays;
+
+/**
+ * 启动配置类
+ *
+ * @author wookvn
+ * @datetime 2025-01-13 17:35:58
+ */
+@Configuration
+@ComponentScan("org.springblade.datasource")
+@EnableConfigurationProperties(DynamicDataSourceProperties.class)
+public class GmetryDatasourceAutoConfiguration {
+
+    /**
+     * 初始化动态数据源
+     * @return
+     */
+    @Bean
+    @ConditionalOnProperty(value = "blade.dynamic-db.enabled", havingValue = "true", matchIfMissing = false)
+    public BladexDataSourceProvider bdsProvider(DefaultDataSourceCreator defaultDataSourceCreator, DynamicDataSourceProperties dynamicDataSourceProperties) {
+        DataSourceProperty master = dynamicDataSourceProperties.getDatasource().get(dynamicDataSourceProperties.getPrimary());
+        return new BladexDataSourceProvider(
+                defaultDataSourceCreator,
+                dynamicDataSourceProperties,
+                master.getUrl(),
+                master.getUsername(),
+                master.getPassword());
+    }
+
+    /**
+     * 动态数据源创建类
+     * @param dataSourceCreator
+     * @return
+     */
+    @Bean
+    @ConditionalOnProperty(value = "blade.dynamic-db.enabled", havingValue = "true", matchIfMissing = false)
+    public DefaultDataSourceCreator defaultDataSourceCreator(DruidDataSourceCreator dataSourceCreator) {
+        DefaultDataSourceCreator defaultDataSourceCreator = new DefaultDataSourceCreator();
+        defaultDataSourceCreator.setCreators(Arrays.asList(dataSourceCreator));
+        return defaultDataSourceCreator;
+    }
+}

+ 30 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/constants/DbConstant.java

@@ -0,0 +1,30 @@
+package org.springblade.datasource.constants;
+
+/**
+ * <p>数据库相关的常量</p>
+ * @author  wookvn
+ * @datetime 2025-01-13 17:09:59
+ */
+public interface DbConstant {
+
+    /**
+     * 默认数字DECIMAL精度长度
+     */
+    int DEFAULT_COLUMN_NUMBER_SIZE = 30;
+
+    /**
+     * 默认数组DECIMAL的小数长度
+     */
+    int DEFAULT_COLUMN_NUMBER_DIGITS = 4;
+
+    /**
+     * 默认字符串的长度
+     */
+    int DEFAULT_COLUMN_STRING_SIZE = 255;
+
+    /**
+     * 创建或更新视图语句格式
+     */
+    String CREATE_REPLACE_VIEW_SQL_FORMAT = "CREATE OR REPLACE VIEW %s AS %s";
+
+}

+ 25 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/constants/DsConstant.java

@@ -0,0 +1,25 @@
+/**
+ * 
+ */
+package org.springblade.datasource.constants;
+
+/**
+ * @author wookvn
+ *
+ * 数据源常量
+ */
+public interface DsConstant {
+
+	/**
+	 * 连接超时[单位:毫秒]
+	 */
+	int CONNECT_TIMEOUT = 2000;
+	/**
+	 * 读取超时[单位:毫秒]
+	 */
+	int READ_TIMEOUT = 10000;
+
+	String COLUMN_USER_ID = "JHBI_USER_ID";
+
+	String COLUMN_PRIMARY_KEY = "ID";
+}

+ 43 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/context/DialectContext.java

@@ -0,0 +1,43 @@
+/**
+ * 
+ */
+package org.springblade.datasource.context;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.springblade.datasource.IGmetryDialect;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springframework.stereotype.Component;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author wookvn
+ *
+ */
+@Slf4j
+@Component
+public class DialectContext {
+
+	private final Map<DsTypeEnum, IGmetryDialect> dialectMap = new ConcurrentHashMap<>();
+	
+	public DialectContext(List<IGmetryDialect> dialectList) {
+		log.info(":::::::[开始]注入数据库方言:::::::");
+		dialectList.forEach(item -> {
+			log.info("=====>>注入数据库方言:{}", item.dsType().name());
+			dialectMap.put(item.dsType(), item);
+		});
+		log.info(":::::::[结束]注入数据库方言:::::::");
+	}
+	
+	/**
+	 * 获取
+	 * @param dsType
+	 * @return
+	 */
+	public IGmetryDialect getDialect(DsTypeEnum dsType) {
+		return dialectMap.get(dsType);
+	}
+}

+ 153 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/ClickhouseGmetryDialect.java

@@ -0,0 +1,153 @@
+/**
+ * 
+ */
+package org.springblade.datasource.dialect;
+
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.datasource.AbstractGmetryDialect;
+import org.springblade.datasource.constants.DsConstant;
+import org.springblade.datasource.enums.DateFormatEnum;
+import org.springblade.datasource.enums.DetailColumnTypeEnum;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springblade.datasource.enums.FunctionMethodEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+import org.springblade.datasource.model.DatasourceDto;
+import org.springblade.datasource.model.FileStructureDto;
+import org.springblade.datasource.model.TableColumnDto;
+import org.springblade.datasource.util.DatasourceUtil;
+import org.springframework.stereotype.Component;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author wookvn
+ *
+ */
+@Slf4j
+@Component
+public class ClickhouseGmetryDialect extends AbstractGmetryDialect {
+	
+	{
+		//数据类型
+		columnTypeMap.put(ViewColumnTypeEnum.NUMBER, "Decimal64(4)");
+		columnTypeMap.put(ViewColumnTypeEnum.STRING, "String");
+		columnTypeMap.put(ViewColumnTypeEnum.DATETIME, "Datetime");
+		columnTypeMap.put(ViewColumnTypeEnum.BIGINT, "UInt64");
+		columnTypeMap.put(ViewColumnTypeEnum.INT, "UInt32");
+		columnTypeMap.put(ViewColumnTypeEnum.LARGE_STRING, "String");
+		
+		//函数方法
+		functionMethodMap.put(FunctionMethodEnum.DATE_TO_STR, "formatDateTime(%s,'%s','Asia/Shanghai')");
+		functionMethodMap.put(FunctionMethodEnum.STR_TO_DATE, "parseDateTimeBestEffortOrNull(%s,'Asia/Shanghai')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_TO_DATE, "parseDateTimeBestEffortOrNull(toString(%s),'Asia/Shanghai')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_JOINT_PERCENT, "concat(toString(%s),'%%')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_YEAR, "formatDateTime(%s,'%%Y','Asia/Shanghai')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_QUARTER, "formatDateTime(%s,'%%YQ%%q','Asia/Shanghai')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MONTH, "formatDateTime(%s,'%%Y%%m','Asia/Shanghai')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_WEEK, "formatDateTime(%s,'%%Y-%%V','Asia/Shanghai')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_DAY, "formatDateTime(%s,'%%Y%%m%%d','Asia/Shanghai')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_HOUR, "formatDateTime(%s,'%%H:00:00','Asia/Shanghai')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MINUTE, "formatDateTime(%s,'%%H:%%M:00','Asia/Shanghai')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_SECOND, "formatDateTime(%s,'%%H:%%M:%%S','Asia/Shanghai')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_FULL, "formatDateTime(%s,'%%Y%%m%%d %%H:%%M:%%S','Asia/Shanghai')");
+
+		//日期格式化
+		dateFormatMap.put(DateFormatEnum.yyyy, "%Y");
+		dateFormatMap.put(DateFormatEnum.yyyyMM, "%Y%m");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM, "%Y-%m");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM, "%Y/%m");
+		dateFormatMap.put(DateFormatEnum.yyyyMMdd, "%Y%m%d");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_dd, "%Y-%m-%d");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$dd, "%Y/%m/%d");
+		dateFormatMap.put(DateFormatEnum.yyyyMMddhh$mm$ss,"%Y%m%d %H:%M:%S");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_ddhh$mm$ss,"%Y-%m-%d %H:%M:%S");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$ddhh$mm$ss,"%Y/%m/%d %H:%M:%S");
+		dateFormatMap.put(DateFormatEnum.hh,"%H");
+		dateFormatMap.put(DateFormatEnum.hh$mm,"%H:%M");
+		dateFormatMap.put(DateFormatEnum.hh$mm$ss,"%H:%M:%S");
+	}
+
+	//create table user_test(ID UInt64, NAME Nullable(String), PRIMARY KEY (ID)) ENGINE=MergeTree COMMENT '测试用户表';
+	@Override
+	public List<String> buildCreateTableSql(String tableName, String tableComment, List<FileStructureDto> structureList) {
+		StringBuilder fieldSql = new StringBuilder();
+		String primaryKey = "";
+		for(FileStructureDto item : structureList) {
+			String _columnType = getColumnType(item.getColumnType(), item.getColumnSize(), item.getDecimalDigits());
+			String columnType = StrUtil.equalsAnyIgnoreCase(item.getColumnName(), DsConstant.COLUMN_USER_ID, DsConstant.COLUMN_PRIMARY_KEY)
+					? _columnType : "Nullable(" + _columnType + ")";
+			fieldSql.append(String.format("%s %s COMMENT '%s',", item.getColumnName(), columnType, item.getComment()));
+			if(item.isPrimaryKey()) {
+				primaryKey = item.getColumnName();
+			}
+		}
+		fieldSql.append("PRIMARY KEY(" + primaryKey + ")");
+		return Arrays.asList(String.format("create table %s (%s) ENGINE=MergeTree COMMENT '%s'", tableName, fieldSql.toString(), tableComment));
+	}
+	
+	/**
+	 * clickhouse查询列 - 因为clickhouse的列备注不返回,需要特殊处理
+	 */
+	@Override
+	public List<TableColumnDto> listTableColumnsByTableViewName(DatasourceDto datasource, String tableViewName) {
+		List<TableColumnDto> dataList = new ArrayList<TableColumnDto>();
+		Connection connection = null;
+		Statement statement = null;
+		try {
+			connection = DatasourceUtil.createConnection(datasource);
+			statement = connection.createStatement();
+			ResultSet rs = statement.executeQuery("DESCRIBE TABLE "+datasource.getDsDb()+"."+tableViewName);
+			while(rs.next()) {
+				TableColumnDto columnDto = new TableColumnDto();
+				String dataType = rs.getString("type");
+				columnDto.setColumnComments(rs.getString("comment"));
+				columnDto.setDataType(dataType);
+				columnDto.setColumnName(rs.getString("name"));
+				columnDto.setColumnSize(0);
+				columnDto.setDecimalDigits(0);
+				columnDto.setNullAbleStatus(StrUtil.containsIgnoreCase(dataType, "nullable") ? 1 : 0);
+				if(StrUtil.containsIgnoreCase(dataType, "string")) {
+					columnDto.setColumnType(ViewColumnTypeEnum.STRING);
+					columnDto.setDetailColumnType(DetailColumnTypeEnum.STRING);
+				}else if(StrUtil.containsAnyIgnoreCase(dataType, "date", "time")) {
+					columnDto.setColumnType(ViewColumnTypeEnum.DATETIME);
+					columnDto.setDetailColumnType(DetailColumnTypeEnum.DATETIME);
+				}else if(StrUtil.containsAnyIgnoreCase(dataType, "float", "decimal")) {
+					columnDto.setColumnType(ViewColumnTypeEnum.NUMBER);
+					columnDto.setDetailColumnType(DetailColumnTypeEnum.FLT);
+				}else if(StrUtil.containsIgnoreCase(dataType, "bigint")) {
+					columnDto.setColumnType(ViewColumnTypeEnum.NUMBER);
+					columnDto.setDetailColumnType(DetailColumnTypeEnum.LONG);
+				}else{
+					columnDto.setColumnType(ViewColumnTypeEnum.NUMBER);
+					columnDto.setDetailColumnType(DetailColumnTypeEnum.INT);
+				}
+				dataList.add(columnDto);
+			}
+			rs.close();
+		} catch (Exception e) {
+			log.error(e.getMessage(), e);
+		} finally {
+			IoUtil.close(connection);
+			IoUtil.close(statement);
+		}
+		return dataList;
+	}
+
+	@Override
+	public String dbSchema(DatasourceDto datasource) {
+		return datasource.getDsDb();
+	}
+
+	@Override
+	public DsTypeEnum dsType() {
+		return DsTypeEnum.clickhouse;
+	}
+}

+ 86 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/DamengGmetryDialect.java

@@ -0,0 +1,86 @@
+/**
+ * 
+ */
+package org.springblade.datasource.dialect;
+
+import org.springblade.datasource.AbstractGmetryDialect;
+import org.springblade.datasource.enums.DateFormatEnum;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springblade.datasource.enums.FunctionMethodEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+import org.springblade.datasource.model.FileStructureDto;
+import org.springframework.stereotype.Component;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author wookvn
+ *
+ */
+@Component
+public class DamengGmetryDialect extends AbstractGmetryDialect {
+	
+	{
+		//数据类型
+		columnTypeMap.put(ViewColumnTypeEnum.NUMBER, "decimal(%s, %s)");
+		columnTypeMap.put(ViewColumnTypeEnum.STRING, "varchar(%s)");
+		columnTypeMap.put(ViewColumnTypeEnum.DATETIME, "datetime");
+		columnTypeMap.put(ViewColumnTypeEnum.BIGINT, "bigint");
+		columnTypeMap.put(ViewColumnTypeEnum.INT, "int");
+		columnTypeMap.put(ViewColumnTypeEnum.LARGE_STRING, "text");
+		
+		//函数方法
+		functionMethodMap.put(FunctionMethodEnum.DATE_TO_STR, "DATE_FORMAT(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.STR_TO_DATE, "CONVERT(datetime, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_TO_DATE, "CONVERT(datetime, CONCAT(%s, ''))");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_JOINT_PERCENT, "CONCAT(%s, '%%')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_YEAR, "DATE_FORMAT(%s,'%%Y')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_QUARTER, "CONCAT(YEAR(%s),'Q',QUARTER(%s))");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MONTH, "DATE_FORMAT(%s,'%%Y%%m')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_WEEK, "DATE_FORMAT(%s,'%%Y-%%v')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_DAY, "DATE_FORMAT(%s,'%%Y%%m%%d')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_HOUR, "DATE_FORMAT(%s,'%%H:00:00')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MINUTE, "DATE_FORMAT(%s,'%%H:%%i:00')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_SECOND, "DATE_FORMAT(%s,'%%H:%%i:%%S')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_FULL, "DATE_FORMAT(%s,'%%Y%%m%%d %%H:%%i:%%S')");
+		
+		//日期格式化函数
+		dateFormatMap.put(DateFormatEnum.yyyy, "%Y");
+		dateFormatMap.put(DateFormatEnum.yyyyMM, "%Y%m");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM, "%Y-%m");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM, "%Y/%m");
+		dateFormatMap.put(DateFormatEnum.yyyyMMdd, "%Y%m%d");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_dd, "%Y-%m-%d");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$dd, "%Y/%m/%d");
+		dateFormatMap.put(DateFormatEnum.yyyyMMddhh$mm$ss,"%Y%m%d %H:%i:%S");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_ddhh$mm$ss,"%Y-%m-%d %H:%i:%S");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$ddhh$mm$ss,"%Y/%m/%d %H:%i:%S");
+		dateFormatMap.put(DateFormatEnum.hh,"%H");
+		dateFormatMap.put(DateFormatEnum.hh$mm,"%H:%i");
+		dateFormatMap.put(DateFormatEnum.hh$mm$ss,"%H:%i:%S");
+	}
+	
+	@Override
+	public List<String> buildCreateTableSql(String tableName, String tableComment, List<FileStructureDto> structureList) {
+		String tableCommentSql = "COMMENT ON table %s IS '%s'";
+		List<String> sqlList = new LinkedList<String>();
+		StringBuilder fieldSql = new StringBuilder();
+		structureList.stream().forEach(f -> {
+			fieldSql.append(String.format("%s %s %s comment '%s',", 
+					f.getColumnName(), getColumnType(f.getColumnType(), f.getColumnSize(), f.getDecimalDigits()),
+					f.isPrimaryKey() ? "primary key" : "", f.getComment()));
+		});
+		fieldSql.deleteCharAt(fieldSql.length() - 1);
+		//创建表语句【不带表注释】
+		sqlList.add(String.format("create table %s (%s)", tableName, fieldSql.toString()));
+		//表注释语句
+		sqlList.add(String.format(tableCommentSql, tableName, tableComment));
+		return sqlList;
+	}
+	
+	@Override
+	public DsTypeEnum dsType() {
+		return DsTypeEnum.dameng;
+	}
+}

+ 90 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/KingbaseGmetryDialect.java

@@ -0,0 +1,90 @@
+/**
+ * 
+ */
+package org.springblade.datasource.dialect;
+
+import org.springblade.datasource.AbstractGmetryDialect;
+import org.springblade.datasource.enums.DateFormatEnum;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springblade.datasource.enums.FunctionMethodEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+import org.springblade.datasource.model.FileStructureDto;
+import org.springframework.stereotype.Component;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author wookvn
+ *
+ */
+@Component
+public class KingbaseGmetryDialect extends AbstractGmetryDialect {
+
+	{
+		//数据类型
+		columnTypeMap.put(ViewColumnTypeEnum.NUMBER, "decimal(%s, %s)");
+		columnTypeMap.put(ViewColumnTypeEnum.STRING, "varchar(%s)");
+		columnTypeMap.put(ViewColumnTypeEnum.DATETIME, "datetime");
+		columnTypeMap.put(ViewColumnTypeEnum.BIGINT, "bigint");
+		columnTypeMap.put(ViewColumnTypeEnum.INT, "int");
+		columnTypeMap.put(ViewColumnTypeEnum.LARGE_STRING, "text");
+		
+		//函数方法
+		functionMethodMap.put(FunctionMethodEnum.DATE_TO_STR, "TO_CHAR(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.STR_TO_DATE, "TO_DATE(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_TO_DATE, "TO_DATE(TO_CHAR(%s), '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_JOINT_PERCENT, "CONCAT(%s, '%%')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_YEAR, "TO_CHAR(%s,'yyyy')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_QUARTER, "TO_CHAR(%s,'YYYY\"Q\"Q')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MONTH, "TO_CHAR(%s,'yyyyMM')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_WEEK, "TO_CHAR(%s,'yyyy-WW')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_DAY, "TO_CHAR(%s,'yyyyMMdd')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_HOUR, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MINUTE, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_SECOND, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_FULL, "TO_CHAR(%s,'yyyyMMdd HH24:mi:ss')");
+		
+		//日期格式化函数
+		dateFormatMap.put(DateFormatEnum.yyyy, "yyyy");
+		dateFormatMap.put(DateFormatEnum.yyyyMM, "yyyyMM");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM, "yyyy-MM");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM, "yyyy/MM");
+		dateFormatMap.put(DateFormatEnum.yyyyMMdd, "yyyyMMdd");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_dd, "yyyy-MM-dd");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$dd, "yyyy/MM/dd");
+		dateFormatMap.put(DateFormatEnum.yyyyMMddhh$mm$ss,"yyyyMMdd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_ddhh$mm$ss,"yyyy-MM-dd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$ddhh$mm$ss,"yyyy/MM/dd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.hh,"HH24");
+		dateFormatMap.put(DateFormatEnum.hh$mm,"HH24:mi");
+		dateFormatMap.put(DateFormatEnum.hh$mm$ss,"HH24:mi:ss");
+	}
+	
+	@Override
+	public List<String> buildCreateTableSql(String tableName, String tableComment, List<FileStructureDto> structureList) {
+		String createColumnCommentSql = "COMMENT ON column %s.%s IS '%s'",
+			   createTableCommentSql = "COMMENT ON table %s IS '%s'",
+			   createTableSql = "create table %s (%s)";
+		List<String> sqlList = new LinkedList<String>();
+		StringBuilder fieldSql = new StringBuilder();
+		structureList.stream().forEach(f -> {
+			fieldSql.append(String.format("%s %s %s,", 
+					f.getColumnName(), getColumnType(f.getColumnType(), f.getColumnSize(), f.getDecimalDigits()),
+					f.isPrimaryKey() ? "primary key" : ""));
+			//添加字段注释SQL
+			sqlList.add(String.format(createColumnCommentSql, tableName, f.getColumnName(), f.getComment()));
+		});
+		fieldSql.deleteCharAt(fieldSql.length() - 1);
+		//创建表SQL
+		sqlList.add(0, String.format(createTableSql, tableName, fieldSql.toString()));
+		//添加表注释SQL
+		sqlList.add(1, String.format(createTableCommentSql, tableName, tableComment));
+		return sqlList;
+	}
+
+	@Override
+	public DsTypeEnum dsType() {
+		return DsTypeEnum.kingbase;
+	}
+}

+ 90 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/MysqlGmetryDialect.java

@@ -0,0 +1,90 @@
+/**
+ * 
+ */
+package org.springblade.datasource.dialect;
+
+import org.springblade.datasource.AbstractGmetryDialect;
+import org.springblade.datasource.enums.DateFormatEnum;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springblade.datasource.enums.FunctionMethodEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+import org.springblade.datasource.model.DatasourceDto;
+import org.springblade.datasource.model.FileStructureDto;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author wookvn
+ *
+ */
+@Component
+public class MysqlGmetryDialect extends AbstractGmetryDialect {
+	
+	{
+		//数据类型
+		columnTypeMap.put(ViewColumnTypeEnum.NUMBER, "decimal(%s, %s)");
+		columnTypeMap.put(ViewColumnTypeEnum.STRING, "varchar(%s)");
+		columnTypeMap.put(ViewColumnTypeEnum.DATETIME, "datetime");
+		columnTypeMap.put(ViewColumnTypeEnum.BIGINT, "bigint");
+		columnTypeMap.put(ViewColumnTypeEnum.INT, "int");
+		columnTypeMap.put(ViewColumnTypeEnum.LARGE_STRING, "text");
+
+		//函数方法
+		functionMethodMap.put(FunctionMethodEnum.DATE_TO_STR, "DATE_FORMAT(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.STR_TO_DATE, "STR_TO_DATE(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_TO_DATE, "STR_TO_DATE(CONCAT(%s, ''), '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_JOINT_PERCENT, "CONCAT(%s, '%%')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_YEAR, "DATE_FORMAT(%s,'%%Y')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_QUARTER, "CONCAT(YEAR(%s),'Q',QUARTER(%s))");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MONTH, "DATE_FORMAT(%s,'%%Y%%m')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_WEEK, "DATE_FORMAT(%s,'%%Y-%%v')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_DAY, "DATE_FORMAT(%s,'%%Y%%m%%d')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_HOUR, "DATE_FORMAT(%s,'%%H:00:00')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MINUTE, "DATE_FORMAT(%s,'%%H:%%i:00')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_SECOND, "DATE_FORMAT(%s,'%%H:%%i:%%S')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_FULL, "DATE_FORMAT(%s,'%%Y%%m%%d %%H:%%i:%%S')");
+		
+		//日期格式化函数
+		dateFormatMap.put(DateFormatEnum.yyyy, "%Y");
+		dateFormatMap.put(DateFormatEnum.yyyyMM, "%Y%m");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM, "%Y-%m");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM, "%Y/%m");
+		dateFormatMap.put(DateFormatEnum.yyyyMMdd, "%Y%m%d");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_dd, "%Y-%m-%d");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$dd, "%Y/%m/%d");
+		dateFormatMap.put(DateFormatEnum.yyyyMMddhh$mm$ss,"%Y%m%d %H:%i:%S");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_ddhh$mm$ss,"%Y-%m-%d %H:%i:%S");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$ddhh$mm$ss,"%Y/%m/%d %H:%i:%S");
+		dateFormatMap.put(DateFormatEnum.hh,"%H");
+		dateFormatMap.put(DateFormatEnum.hh$mm,"%H:%i");
+		dateFormatMap.put(DateFormatEnum.hh$mm$ss,"%H:%i:%S");
+	}
+
+	@Override
+	public String quoteIdentifier(String name) {
+		return "`" + name + "`";
+	}
+
+	@Override
+	public String dbSchema(DatasourceDto datasource) {
+		return datasource.getDsDb();
+	}
+
+	@Override
+	public List<String> buildCreateTableSql(String tableName, String tableComment, List<FileStructureDto> structureList) {
+		StringBuilder fieldSql = new StringBuilder();
+		structureList.stream().forEach(f -> fieldSql.append(String.format("%s %s %s comment '%s',",
+				f.getColumnName(), getColumnType(f.getColumnType(), f.getColumnSize(), f.getDecimalDigits()),
+				f.isPrimaryKey() ? "primary key" : "", f.getComment())));
+		fieldSql.deleteCharAt(fieldSql.length() - 1);
+		return Arrays.asList(String.format("create table %s (%s) comment '%s'", tableName, fieldSql.toString(), tableComment));
+	}
+	
+	@Override
+	public DsTypeEnum dsType() {
+		return DsTypeEnum.mysql;
+	}
+
+}

+ 91 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/OracleGmetryDialect.java

@@ -0,0 +1,91 @@
+/**
+ * 
+ */
+package org.springblade.datasource.dialect;
+
+import org.springblade.datasource.AbstractGmetryDialect;
+import org.springblade.datasource.enums.DateFormatEnum;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springblade.datasource.enums.FunctionMethodEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+import org.springblade.datasource.model.FileStructureDto;
+import org.springframework.stereotype.Component;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author wookvn
+ *
+ */
+@Component
+public class OracleGmetryDialect extends AbstractGmetryDialect {
+
+	{
+		//数据类型
+		columnTypeMap.put(ViewColumnTypeEnum.NUMBER, "NUMBER(%s, %s)");
+		columnTypeMap.put(ViewColumnTypeEnum.STRING, "VARCHAR2(%s)");
+		columnTypeMap.put(ViewColumnTypeEnum.DATETIME, "DATE");
+		columnTypeMap.put(ViewColumnTypeEnum.BIGINT, "NUMBER(20)");
+		columnTypeMap.put(ViewColumnTypeEnum.INT, "NUMBER(10)");
+		columnTypeMap.put(ViewColumnTypeEnum.LARGE_STRING, "VARCHAR2(4000)");
+		
+		//函数方法
+		functionMethodMap.put(FunctionMethodEnum.DATE_TO_STR, "TO_CHAR(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.STR_TO_DATE, "TO_DATE(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_TO_DATE, "TO_DATE(TO_CHAR(%s), '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_JOINT_PERCENT, "TO_CHAR(%s, '%s') || '%%'");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_YEAR, "TO_CHAR(%s,'yyyy')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_QUARTER, "TO_CHAR(%s,'YYYY\"Q\"Q')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MONTH, "TO_CHAR(%s,'yyyyMM')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_WEEK, "TO_CHAR(%s,'yyyy-WW')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_DAY, "TO_CHAR(%s,'yyyyMMdd')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_HOUR, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MINUTE, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_SECOND, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_FULL, "TO_CHAR(%s,'yyyyMMdd HH24:mi:ss')");
+		
+		//日期格式化函数
+		dateFormatMap.put(DateFormatEnum.yyyy, "yyyy");
+		dateFormatMap.put(DateFormatEnum.yyyyMM, "yyyyMM");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM, "yyyy-MM");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM, "yyyy/MM");
+		dateFormatMap.put(DateFormatEnum.yyyyMMdd, "yyyyMMdd");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_dd, "yyyy-MM-dd");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$dd, "yyyy/MM/dd");
+		dateFormatMap.put(DateFormatEnum.yyyyMMddhh$mm$ss,"yyyyMMdd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_ddhh$mm$ss,"yyyy-MM-dd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$ddhh$mm$ss,"yyyy/MM/dd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.hh,"HH24");
+		dateFormatMap.put(DateFormatEnum.hh$mm,"HH24:mi");
+		dateFormatMap.put(DateFormatEnum.hh$mm$ss,"HH24:mi:ss");
+	}
+	
+	@Override
+	public List<String> buildCreateTableSql(String tableName, String tableComment, List<FileStructureDto> structureList) {
+		String createColumnCommentSql = "COMMENT ON column %s.%s IS '%s'",
+			   createTableCommentSql = "COMMENT ON table %s IS '%s'",
+			   createTableSql = "create table %s (%s)";
+		List<String> sqlList = new LinkedList<String>();
+		StringBuilder fieldSql = new StringBuilder();
+		structureList.stream().forEach(f -> {
+			fieldSql.append(String.format("%s %s %s,", 
+					f.getColumnName(), getColumnType(f.getColumnType(), f.getColumnSize(), f.getDecimalDigits()),
+					f.isPrimaryKey() ? "primary key" : ""));
+			//添加字段注释SQL
+			sqlList.add(String.format(createColumnCommentSql, tableName, f.getColumnName(), f.getComment()));
+		});
+		fieldSql.deleteCharAt(fieldSql.length() - 1);
+		//创建表SQL
+		sqlList.add(0, String.format(createTableSql, tableName, fieldSql.toString()));
+		//添加表注释SQL
+		sqlList.add(1, String.format(createTableCommentSql, tableName, tableComment));
+		return sqlList;
+	}
+	
+	@Override
+	public DsTypeEnum dsType() {
+		return DsTypeEnum.oracle;
+	}
+	
+}

+ 97 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/PostgresqlGmetryDialect.java

@@ -0,0 +1,97 @@
+/**
+ * 
+ */
+package org.springblade.datasource.dialect;
+
+import cn.hutool.core.util.StrUtil;
+import org.springblade.datasource.AbstractGmetryDialect;
+import org.springblade.datasource.enums.DateFormatEnum;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springblade.datasource.enums.FunctionMethodEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+import org.springblade.datasource.model.DatasourceDto;
+import org.springblade.datasource.model.FileStructureDto;
+import org.springframework.stereotype.Component;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author wookvn
+ *
+ */
+@Component
+public class PostgresqlGmetryDialect extends AbstractGmetryDialect {
+
+	{
+		//数据类型
+		columnTypeMap.put(ViewColumnTypeEnum.NUMBER, "decimal(30, 4)");
+		columnTypeMap.put(ViewColumnTypeEnum.STRING, "varchar(1000)");
+		columnTypeMap.put(ViewColumnTypeEnum.DATETIME, "date");
+		columnTypeMap.put(ViewColumnTypeEnum.BIGINT, "bigint");
+		columnTypeMap.put(ViewColumnTypeEnum.INT, "int");
+		columnTypeMap.put(ViewColumnTypeEnum.LARGE_STRING, "text");
+		
+		//函数方法
+		functionMethodMap.put(FunctionMethodEnum.DATE_TO_STR, "TO_CHAR(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.STR_TO_DATE, "TO_DATE(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_TO_DATE, "TO_DATE(TO_CHAR(%s), '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_JOINT_PERCENT, "CONCAT(%s, '%%')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_YEAR, "TO_CHAR(%s,'yyyy')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_QUARTER, "TO_CHAR(%s,'YYYY\"Q\"Q')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MONTH, "TO_CHAR(%s,'yyyyMM')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_WEEK, "TO_CHAR(%s,'yyyy-WW')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_DAY, "TO_CHAR(%s,'yyyyMMdd')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_HOUR, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MINUTE, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_SECOND, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_FULL, "TO_CHAR(%s,'yyyyMMdd HH24:mi:ss')");
+
+		//日期格式化函数
+		dateFormatMap.put(DateFormatEnum.yyyy, "yyyy");
+		dateFormatMap.put(DateFormatEnum.yyyyMM, "yyyyMM");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM, "yyyy-MM");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM, "yyyy/MM");
+		dateFormatMap.put(DateFormatEnum.yyyyMMdd, "yyyyMMdd");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_dd, "yyyy-MM-dd");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$dd, "yyyy/MM/dd");
+		dateFormatMap.put(DateFormatEnum.yyyyMMddhh$mm$ss,"yyyyMMdd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_ddhh$mm$ss,"yyyy-MM-dd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$ddhh$mm$ss,"yyyy/MM/dd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.hh,"HH24");
+		dateFormatMap.put(DateFormatEnum.hh$mm,"HH24:mi");
+		dateFormatMap.put(DateFormatEnum.hh$mm$ss,"HH24:mi:ss");
+	}
+	
+	@Override
+	public List<String> buildCreateTableSql(String tableName, String tableComment, List<FileStructureDto> structureList) {
+		String createColumnCommentSql = "COMMENT ON column %s.%s IS '%s'",
+			   createTableCommentSql = "COMMENT ON table %s IS '%s'",
+			   createTableSql = "create table %s (%s)";
+		List<String> sqlList = new LinkedList<String>();
+		StringBuilder fieldSql = new StringBuilder();
+		structureList.stream().forEach(f -> {
+			fieldSql.append(String.format("%s %s %s,", 
+					f.getColumnName(), getColumnType(f.getColumnType(), f.getColumnSize(), f.getDecimalDigits()),
+					f.isPrimaryKey() ? "primary key" : ""));
+			//添加字段注释SQL
+			sqlList.add(String.format(createColumnCommentSql, tableName, f.getColumnName(), f.getComment()));
+		});
+		fieldSql.deleteCharAt(fieldSql.length() - 1);
+		//创建表SQL
+		sqlList.add(0, String.format(createTableSql, tableName, fieldSql.toString()));
+		//添加表注释SQL
+		sqlList.add(1, String.format(createTableCommentSql, tableName, tableComment));
+		return sqlList;
+	}
+
+	@Override
+	public String dbSchema(DatasourceDto datasource) {
+		return StrUtil.isBlank(datasource.getDbSchema()) ? "public" : datasource.getDbSchema();
+	}
+	
+	@Override
+	public DsTypeEnum dsType() {
+		return DsTypeEnum.postgresql;
+	}
+}

+ 224 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/SqlServerGmetryDialect.java

@@ -0,0 +1,224 @@
+/**
+ * 
+ */
+package org.springblade.datasource.dialect;
+
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.datasource.AbstractGmetryDialect;
+import org.springblade.datasource.enums.DateFormatEnum;
+import org.springblade.datasource.enums.DetailColumnTypeEnum;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springblade.datasource.enums.FunctionMethodEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+import org.springblade.datasource.model.DatasourceDto;
+import org.springblade.datasource.model.FileStructureDto;
+import org.springblade.datasource.model.TableColumnDto;
+import org.springblade.datasource.model.TableViewDto;
+import org.springblade.datasource.util.DatasourceUtil;
+import org.springframework.stereotype.Component;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * @author wookvn
+ *
+ */
+@Slf4j
+@Component
+public class SqlServerGmetryDialect extends AbstractGmetryDialect {
+	
+	{
+		//数据类型
+		columnTypeMap.put(ViewColumnTypeEnum.NUMBER, "decimal(%s, %s)");
+		columnTypeMap.put(ViewColumnTypeEnum.STRING, "nvarchar(%s)");
+		columnTypeMap.put(ViewColumnTypeEnum.DATETIME, "datetime");
+		columnTypeMap.put(ViewColumnTypeEnum.BIGINT, "bigint");
+		columnTypeMap.put(ViewColumnTypeEnum.INT, "int");
+		columnTypeMap.put(ViewColumnTypeEnum.LARGE_STRING, "text");
+		
+		//函数方法
+		functionMethodMap.put(FunctionMethodEnum.DATE_TO_STR, "FORMAT(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.STR_TO_DATE, "CONVERT(datetime, %s)");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_TO_DATE, "CONVERT(datetime, convert(varchar(50), %s))");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_JOINT_PERCENT, "CONVERT(varchar(50), %s)+'%%'");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_YEAR, "FORMAT(%s,'yyyy')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_QUARTER, "CONCAT(DATEPART(year,%s),'Q',DATEPART(quarter,%s))");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MONTH, "FORMAT(%s,'yyyyMM')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_WEEK, "CONCAT(DATEPART(year,%s),'-',DATEPART(week,%s))");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_DAY, "FORMAT(%s,'yyyyMMdd')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_HOUR, "FORMAT(%s,'hh:00:00')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MINUTE, "FORMAT(%s,'hh:mm:00')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_SECOND, "FORMAT(%s,'hh:mm:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_FULL, "FORMAT(%s,'yyyyMMdd hh:mm:ss')");
+
+		//日期格式化
+		dateFormatMap.put(DateFormatEnum.yyyy, "yyyy");
+		dateFormatMap.put(DateFormatEnum.yyyyMM, "yyyyMM");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM, "yyyy-MM");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM, "yyyy/MM");
+		dateFormatMap.put(DateFormatEnum.yyyyMMdd, "yyyyMMdd");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_dd, "yyyy-MM-dd");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$dd, "yyyy/MM/dd");
+		dateFormatMap.put(DateFormatEnum.yyyyMMddhh$mm$ss,"yyyyMMdd hh:mm:ss");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_ddhh$mm$ss,"yyyy-MM-dd hh:mm:ss");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$ddhh$mm$ss,"yyyy/MM/dd hh:mm:ss");
+		dateFormatMap.put(DateFormatEnum.hh,"hh");
+		dateFormatMap.put(DateFormatEnum.hh$mm,"hh:mm");
+		dateFormatMap.put(DateFormatEnum.hh$mm$ss,"hh:mm:ss");
+	}
+
+
+	@Override
+	public List<String> buildCreateTableSql(String tableName, String tableComment, List<FileStructureDto> structureList) {
+		String createColumnCommentSql = "EXEC sp_addextendedproperty N'MS_Description', N'%s', N'user', N'dbo', N'table', N'%s', N'COLUMN', N'%s'",
+				createTableCommentSql = "EXEC sp_addextendedproperty N'MS_Description', N'%s', N'user', N'dbo', N'table', N'%s', NULL, NULL",
+				createTableSql = "create table %s (%s)";
+		List<String> sqlList = new LinkedList<String>();
+		StringBuilder fieldSql = new StringBuilder();
+		structureList.stream().forEach(f -> {
+			fieldSql.append(String.format("%s %s %s,",
+					f.getColumnName(), getColumnType(f.getColumnType(), f.getColumnSize(), f.getDecimalDigits()),
+					f.isPrimaryKey() ? "primary key" : ""));
+			//添加字段注释SQL
+			sqlList.add(String.format(createColumnCommentSql, f.getComment(), tableName, f.getColumnName()));
+		});
+		fieldSql.deleteCharAt(fieldSql.length() - 1);
+		//创建表SQL
+		sqlList.add(0, String.format(createTableSql, tableName, fieldSql.toString()));
+		//添加表注释SQL
+		sqlList.add(1, String.format(createTableCommentSql, tableComment, tableName));
+		return sqlList;
+	}
+
+	@Override
+	public List<TableColumnDto> listTableColumnsByTableViewName(DatasourceDto datasource, String tableViewName) {
+		String querySql = "SELECT B.NAME AS column_name,C.NAME AS data_type,B.PREC AS column_size,B.SCALE AS decimal_digits,\n" +
+				"	 B.isnullable AS null_able_status,\n" +
+				"    (CASE WHEN NOT F.ID IS NULL THEN 1 ELSE 0 END) AS primary_key_status,\n" +
+				"    (CASE WHEN COLUMNPROPERTY(B.ID,B.NAME,'ISIDENTITY') = 1 THEN 1 ELSE 0 END) AS auto_increment_status,\n" +
+				"    CONVERT(NVARCHAR(1000),ISNULL(G.VALUE,'')) AS column_comments\n" +
+				"FROM SYSOBJECTS A INNER JOIN SYSCOLUMNS B ON A.ID=B.ID and A.XTYPE in ('U','V')\n" +
+				"	 INNER JOIN SYSTYPES C ON B.XTYPE=C.XUSERTYPE\n" +
+				"    LEFT JOIN SYSOBJECTS D ON B.ID=D.PARENT_OBJ AND D.XTYPE='PK'\n" +
+				"    LEFT JOIN SYSINDEXES E ON B.ID=E.ID AND D.NAME=E.NAME\n" +
+				"    LEFT JOIN SYSINDEXKEYS F ON B.ID=F.ID AND B.COLID=F.COLID AND E.INDID=F.INDID\n" +
+				"    LEFT JOIN SYS.EXTENDED_PROPERTIES G ON B.ID=G.MAJOR_ID AND B.COLID=G.MINOR_ID\n" +
+				"    LEFT JOIN SYS.OBJECTS H on B.id= H.object_id\n" +
+				"    LEFT JOIN SYS.SCHEMAS I on H.schema_id=I.schema_id\n" +
+				"WHERE OBJECT_NAME(B.ID)=N'" + tableViewName + "' AND I.NAME = N'" + dbSchema(datasource) + "'";
+		List<TableColumnDto> dataList = new ArrayList<>();
+		_query(datasource, querySql, rs -> {
+			try {
+				while (rs.next()) {
+					TableColumnDto tableColumnDto = new TableColumnDto();
+					tableColumnDto.setColumnName(rs.getString("column_name"));
+					tableColumnDto.setColumnComments(rs.getString("column_comments"));
+					tableColumnDto.setColumnSize(rs.getInt("column_size"));
+					tableColumnDto.setDataType(rs.getString("data_type"));
+					tableColumnDto.setDecimalDigits(rs.getInt("decimal_digits"));
+					tableColumnDto.setNullAbleStatus(rs.getInt("null_able_status"));
+					tableColumnDto.setPrimaryKeyStatus(rs.getInt("primary_key_status"));
+					tableColumnDto.setAutoIncrementStatus(rs.getInt("auto_increment_status"));
+					setUpColumnType(tableColumnDto);
+					dataList.add(tableColumnDto);
+				}
+			} catch (Exception e) {
+				log.error(e.getMessage(), e);
+			}
+		});
+		return dataList;
+	}
+
+	@Override
+	public List<TableViewDto> listTableViewsByDatasource(DatasourceDto datasource) {
+		return this.listTableViewsByDatasource(datasource, null);
+	}
+
+	@Override
+	public List<TableViewDto> listTableViewsByDatasource(DatasourceDto datasource, String tableName) {
+		String querySql = "select top 1000 ROW_NUMBER() OVER (ORDER BY a.name) AS oder_num, a.name AS table_view_name, g.[value] AS table_comments " +
+				"from sys.objects a left join sys.extended_properties g on (a.object_id = g.major_id AND g.minor_id = 0) " +
+				"left join sys.schemas c on a.schema_id = c.schema_id where a.type in ('V', 'U') and c.name = N'" + dbSchema(datasource) + "'";
+		if (StrUtil.isNotBlank(tableName)) {
+			querySql += " and a.name like N'%" + tableName + "%'";
+		}
+		List<TableViewDto> dataList = new ArrayList<>();
+		_query(datasource, querySql, rs -> {
+			try {
+				while (rs.next()) {
+					TableViewDto tableView = new TableViewDto();
+					tableView.setDatasourceId(datasource.getId());
+					tableView.setTableComments(rs.getString("table_comments"));
+					tableView.setTableViewName(rs.getString("table_view_name"));
+					dataList.add(tableView);
+				}
+			} catch (SQLException e) {
+				log.error(e.getMessage(), e);
+			}
+		});
+		return dataList;
+	}
+
+	@Override
+	public String dbSchema(DatasourceDto datasource) {
+		return StrUtil.isBlank(datasource.getDbSchema()) ? "dbo" : datasource.getDbSchema();
+	}
+
+	@Override
+	public String dbTableName(DatasourceDto datasource, String tableName) {
+		return dbSchema(datasource) + "." + tableName;
+	}
+
+	@Override
+	public DsTypeEnum dsType() {
+		return DsTypeEnum.sqlserver;
+	}
+
+	private void _query(DatasourceDto datasource, String sql, Consumer<ResultSet> consumer) {
+		Connection connection = null;
+		Statement statement = null;
+		try {
+			connection = DatasourceUtil.createConnection(datasource);
+			statement = connection.createStatement();
+			if (statement.execute(sql)) {
+				ResultSet resultSet = statement.executeQuery(sql);
+				consumer.accept(resultSet);
+			}
+		} catch (Exception e) {
+			log.error(e.getMessage());
+			throw new RuntimeException("查询表或字段信息出错,请稍后重试", e);
+		} finally {
+			IoUtil.close(connection);
+			IoUtil.close(statement);
+		}
+	}
+
+	private void setUpColumnType(TableColumnDto tableColumn) {
+		if (StrUtil.containsAnyIgnoreCase(tableColumn.getDataType(), "char", "text")) {
+			tableColumn.setColumnType(ViewColumnTypeEnum.STRING);
+			tableColumn.setDetailColumnType(DetailColumnTypeEnum.STRING);
+		} else if (StrUtil.containsIgnoreCase(tableColumn.getDataType(), "date")) {
+			tableColumn.setColumnType(ViewColumnTypeEnum.DATETIME);
+			tableColumn.setDetailColumnType(DetailColumnTypeEnum.DATETIME);
+		} else if (StrUtil.containsAnyIgnoreCase(tableColumn.getDataType(), "float", "double", "real", "decimal")) {
+			tableColumn.setColumnType(ViewColumnTypeEnum.NUMBER);
+			tableColumn.setDetailColumnType(DetailColumnTypeEnum.FLT);
+		} else if (StrUtil.containsAnyIgnoreCase(tableColumn.getDataType(), "bigint")) {
+			tableColumn.setColumnType(ViewColumnTypeEnum.NUMBER);
+			tableColumn.setDetailColumnType(DetailColumnTypeEnum.LONG);
+		} else {
+			tableColumn.setColumnType(ViewColumnTypeEnum.NUMBER);
+			tableColumn.setDetailColumnType(DetailColumnTypeEnum.INT);
+		}
+	}
+
+}

+ 96 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/UXDBGmetryDialect.java

@@ -0,0 +1,96 @@
+/**
+ * 
+ */
+package org.springblade.datasource.dialect;
+
+import org.springblade.datasource.AbstractGmetryDialect;
+import org.springblade.datasource.enums.DateFormatEnum;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springblade.datasource.enums.FunctionMethodEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+import org.springblade.datasource.model.DatasourceDto;
+import org.springblade.datasource.model.FileStructureDto;
+import org.springframework.stereotype.Component;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author heyabo
+ *
+ */
+@Component
+public class UXDBGmetryDialect extends AbstractGmetryDialect {
+
+	{
+		//数据类型
+		columnTypeMap.put(ViewColumnTypeEnum.NUMBER, "decimal(%s, %s)");
+		columnTypeMap.put(ViewColumnTypeEnum.STRING, "varchar(%s)");
+		columnTypeMap.put(ViewColumnTypeEnum.DATETIME, "date");
+		columnTypeMap.put(ViewColumnTypeEnum.BIGINT, "bigint");
+		columnTypeMap.put(ViewColumnTypeEnum.INT, "int");
+		columnTypeMap.put(ViewColumnTypeEnum.LARGE_STRING, "text");
+		
+		//函数方法
+		functionMethodMap.put(FunctionMethodEnum.DATE_TO_STR, "TO_CHAR(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.STR_TO_DATE, "TO_DATE(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_TO_DATE, "TO_DATE(TO_CHAR(%s), '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_JOINT_PERCENT, "CONCAT(%s, '%%')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_YEAR, "TO_CHAR(%s,'yyyy')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_QUARTER, "TO_CHAR(%s,'YYYY\"Q\"Q')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MONTH, "TO_CHAR(%s,'yyyyMM')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_WEEK, "TO_CHAR(%s,'yyyy-WW')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_DAY, "TO_CHAR(%s,'yyyyMMdd')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_HOUR, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MINUTE, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_SECOND, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_FULL, "TO_CHAR(%s,'yyyyMMdd HH24:mi:ss')");
+		
+		//日期格式化函数
+		dateFormatMap.put(DateFormatEnum.yyyy, "yyyy");
+		dateFormatMap.put(DateFormatEnum.yyyyMM, "yyyyMM");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM, "yyyy-MM");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM, "yyyy/MM");
+		dateFormatMap.put(DateFormatEnum.yyyyMMdd, "yyyyMMdd");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_dd, "yyyy-MM-dd");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$dd, "yyyy/MM/dd");
+		dateFormatMap.put(DateFormatEnum.yyyyMMddhh$mm$ss,"yyyyMMdd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_ddhh$mm$ss,"yyyy-MM-dd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$ddhh$mm$ss,"yyyy/MM/dd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.hh,"HH24");
+		dateFormatMap.put(DateFormatEnum.hh$mm,"HH24:mi");
+		dateFormatMap.put(DateFormatEnum.hh$mm$ss,"HH24:mi:ss");
+	}
+	
+	@Override
+	public List<String> buildCreateTableSql(String tableName, String tableComment, List<FileStructureDto> structureList) {
+		String createColumnCommentSql = "COMMENT ON column %s.%s IS '%s'",
+			   createTableCommentSql = "COMMENT ON table %s IS '%s'",
+			   createTableSql = "create table %s (%s)";
+		List<String> sqlList = new LinkedList<>();
+		StringBuilder fieldSql = new StringBuilder();
+		structureList.forEach(f -> {
+			fieldSql.append(String.format("%s %s %s,", 
+					f.getColumnName(), getColumnType(f.getColumnType(), f.getColumnSize(), f.getDecimalDigits()),
+					f.isPrimaryKey() ? "primary key" : ""));
+			//添加字段注释SQL
+			sqlList.add(String.format(createColumnCommentSql, tableName, f.getColumnName(), f.getComment()));
+		});
+		fieldSql.deleteCharAt(fieldSql.length() - 1);
+		//创建表SQL
+		sqlList.add(0, String.format(createTableSql, tableName, fieldSql));
+		//添加表注释SQL
+		sqlList.add(1, String.format(createTableCommentSql, tableName, tableComment));
+		return sqlList;
+	}
+
+	@Override
+	public String dbSchema(DatasourceDto datasource) {
+		return datasource.getDsDb();
+	}
+	
+	@Override
+	public DsTypeEnum dsType() {
+		return DsTypeEnum.uxdb;
+	}
+}

+ 90 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/dialect/XuGuGmetryDialect.java

@@ -0,0 +1,90 @@
+/**
+ * 
+ */
+package org.springblade.datasource.dialect;
+
+import org.springblade.datasource.AbstractGmetryDialect;
+import org.springblade.datasource.enums.DateFormatEnum;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springblade.datasource.enums.FunctionMethodEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+import org.springblade.datasource.model.FileStructureDto;
+import org.springframework.stereotype.Component;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author wookvn
+ *
+ */
+@Component
+public class XuGuGmetryDialect extends AbstractGmetryDialect {
+
+	{
+		//数据类型
+		columnTypeMap.put(ViewColumnTypeEnum.NUMBER, "NUMERIC[(%s[,%s])]");
+		columnTypeMap.put(ViewColumnTypeEnum.STRING, "VARCHAR(%s)");
+		columnTypeMap.put(ViewColumnTypeEnum.DATETIME, "DATE");
+		columnTypeMap.put(ViewColumnTypeEnum.BIGINT, "BIGINT");
+		columnTypeMap.put(ViewColumnTypeEnum.INT, "INT");
+		columnTypeMap.put(ViewColumnTypeEnum.LARGE_STRING, "TEXT");
+		
+		//函数方法
+		functionMethodMap.put(FunctionMethodEnum.DATE_TO_STR, "TO_CHAR(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.STR_TO_DATE, "TO_DATE(%s, '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_TO_DATE, "TO_DATE(TO_CHAR(%s), '%s')");
+		functionMethodMap.put(FunctionMethodEnum.NUMBER_JOINT_PERCENT, "TO_CHAR(%s, '%s') || '%%'");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_YEAR, "TO_CHAR(%s,'yyyy')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_QUARTER, "TO_CHAR(%s,'YYYY\"Q\"Q')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MONTH, "TO_CHAR(%s,'yyyyMM')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_WEEK, "TO_CHAR(%s,'yyyy-WW')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_DAY, "TO_CHAR(%s,'yyyyMMdd')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_HOUR, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_MINUTE, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_SECOND, "TO_CHAR(%s,'HH24:mi:ss')");
+		functionMethodMap.put(FunctionMethodEnum.EXTRACT_FULL, "TO_CHAR(%s,'yyyyMMdd HH24:mi:ss')");
+		
+		//日期格式化函数
+		dateFormatMap.put(DateFormatEnum.yyyy, "yyyy");
+		dateFormatMap.put(DateFormatEnum.yyyyMM, "yyyyMM");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM, "yyyy-MM");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM, "yyyy/MM");
+		dateFormatMap.put(DateFormatEnum.yyyyMMdd, "yyyyMMdd");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_dd, "yyyy-MM-dd");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$dd, "yyyy/MM/dd");
+		dateFormatMap.put(DateFormatEnum.yyyyMMddhh$mm$ss,"yyyyMMdd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.yyyy_MM_ddhh$mm$ss,"yyyy-MM-dd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.yyyy$MM$ddhh$mm$ss,"yyyy/MM/dd HH24:mi:ss");
+		dateFormatMap.put(DateFormatEnum.hh,"HH24");
+		dateFormatMap.put(DateFormatEnum.hh$mm,"HH24:mi");
+		dateFormatMap.put(DateFormatEnum.hh$mm$ss,"HH24:mi:ss");
+	}
+	
+	@Override
+	public List<String> buildCreateTableSql(String tableName, String tableComment, List<FileStructureDto> structureList) {
+		String createColumnCommentSql = "COMMENT ON column %s.%s IS '%s'",
+			   createTableCommentSql = "COMMENT ON table %s IS '%s'",
+			   createTableSql = "create table %s (%s)";
+		List<String> sqlList = new LinkedList<String>();
+		StringBuilder fieldSql = new StringBuilder();
+		structureList.stream().forEach(f ->{
+			fieldSql.append(String.format("%s %s %s,", 
+					f.getColumnName(), getColumnType(f.getColumnType(), f.getColumnSize(), f.getDecimalDigits()),
+					f.isPrimaryKey() ? "primary key" : ""));
+			//添加字段注释SQL
+			sqlList.add(String.format(createColumnCommentSql, tableName, f.getColumnName(), f.getComment()));
+		});
+		fieldSql.deleteCharAt(fieldSql.length() - 1);
+		//创建表SQL
+		sqlList.add(0, String.format(createTableSql, tableName, fieldSql.toString()));
+		//添加表注释SQL
+		sqlList.add(1, String.format(createTableCommentSql, tableName, tableComment));
+		return sqlList;
+	}
+	
+	@Override
+	public DsTypeEnum dsType() {
+		return DsTypeEnum.xugu;
+	}
+}

+ 24 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/ColumnTypeEnum.java

@@ -0,0 +1,24 @@
+///**
+// *
+// */
+//package org.springblade.datasource.enums;
+//
+//import lombok.AllArgsConstructor;
+//import lombok.Getter;
+//
+///**
+// * @author wookvn
+// *
+// */
+//@Getter
+//@AllArgsConstructor
+//public enum ColumnTypeEnum {
+//
+//	NUMBER(0, "数字类型"),
+//	STRING(1, "字符串类型"),
+//	DATETIME(2, "日期类型"),
+//	BIGINT(3, "数字类型");
+//
+//	private Integer value;
+//	private String message;
+//}

+ 54 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/DateFormatEnum.java

@@ -0,0 +1,54 @@
+/**
+ * 
+ */
+package org.springblade.datasource.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+
+/**
+ * @author wookvn
+ *	
+ *	日期格式化类型
+ */
+public enum DateFormatEnum {
+	yyyy(1, "yyyy"),
+	yyyyMM(2, "yyyyMM"),
+	yyyy_MM(3, "yyyy-MM"),
+	yyyy$MM(4, "yyyy/MM"),
+	yyyyMMdd(5, "yyyyMMdd"),
+	yyyy_MM_dd(6, "yyyy-MM-dd"),
+	yyyy$MM$dd(7, "yyyy/MM/dd"),
+	yyyyMMddhh$mm$ss(8, "yyyyMMdd HH:mm:ss"),
+	yyyy_MM_ddhh$mm$ss(9, "yyyy-MM-dd HH:mm:ss"),
+	yyyy$MM$ddhh$mm$ss(10, "yyyy/MM/dd HH:mm:ss"),
+	hh(11, "HH"),
+	hh$mm(12, "HH:mm"),
+	hh$mm$ss(13, "HH:mm:ss"),
+	timestamp(14, "");
+	
+	@EnumValue
+	private int value;
+	private String format;
+
+	/**
+	 * @param value
+	 */
+	private DateFormatEnum(int value, String format) {
+		this.value = value;
+		this.format = format;
+	}
+
+	/**
+	 * @return the value
+	 */
+	public int getValue() {
+		return value;
+	}
+
+	/**
+	 * @return the format
+	 */
+	public String getFormat() {
+		return format;
+	}
+}

+ 104 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/DetailColumnTypeEnum.java

@@ -0,0 +1,104 @@
+/**
+ * 
+ */
+package org.springblade.datasource.enums;
+
+import static java.sql.Types.ARRAY;
+import static java.sql.Types.BINARY;
+import static java.sql.Types.BIT;
+import static java.sql.Types.BLOB;
+import static java.sql.Types.BOOLEAN;
+import static java.sql.Types.CHAR;
+import static java.sql.Types.CLOB;
+import static java.sql.Types.DATE;
+import static java.sql.Types.DECIMAL;
+import static java.sql.Types.DOUBLE;
+import static java.sql.Types.FLOAT;
+import static java.sql.Types.INTEGER;
+import static java.sql.Types.LONGNVARCHAR;
+import static java.sql.Types.LONGVARBINARY;
+import static java.sql.Types.LONGVARCHAR;
+import static java.sql.Types.NCHAR;
+import static java.sql.Types.NCLOB;
+import static java.sql.Types.NUMERIC;
+import static java.sql.Types.NVARCHAR;
+import static java.sql.Types.REAL;
+import static java.sql.Types.SMALLINT;
+import static java.sql.Types.TIME;
+import static java.sql.Types.TIMESTAMP;
+import static java.sql.Types.TINYINT;
+import static java.sql.Types.VARBINARY;
+import static java.sql.Types.VARCHAR;
+import static java.sql.Types.BIGINT;
+
+import java.util.stream.Stream;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+
+/**
+ * @author wookvn
+ *
+ * 显示的字段类型
+ */
+public enum DetailColumnTypeEnum {
+	/**
+	 * 字符串
+	 */
+	STRING(1, new Integer[] {CHAR, VARCHAR, LONGVARCHAR, BINARY, VARBINARY, LONGVARBINARY, BLOB, CLOB, NCHAR, NVARCHAR, LONGNVARCHAR, NCLOB, ARRAY}),
+	
+	/**
+	 * 日期
+	 */
+	DATETIME(2, new Integer[] {DATE, TIME, TIMESTAMP}),
+	
+	/**
+	 * 整数
+	 */
+	INT(3, new Integer[] {BIT, TINYINT, SMALLINT, INTEGER, BOOLEAN }),
+	
+	/**
+	 * 
+	 */
+	LONG(4, new Integer[] {BIGINT}),
+	
+	/**
+	 * 浮点数
+	 */
+	FLT(5, new Integer[] {FLOAT, REAL, DOUBLE, NUMERIC, DECIMAL});
+	
+	@EnumValue
+	private int value;
+	private Integer[] types;
+
+	/**
+	 * @param value
+	 */
+	private DetailColumnTypeEnum(int value, Integer[] types) {
+		this.value = value;
+		this.types = types;
+	}
+
+	/**
+	 * @return the value
+	 */
+	public int getValue() {
+		return value;
+	}
+	
+	/**
+	 * @return the types
+	 */
+	public Integer[] getTypes() {
+		return types;
+	}
+	
+	public static DetailColumnTypeEnum resolve(Integer type) {
+		DetailColumnTypeEnum[] values = DetailColumnTypeEnum.values();
+		for(DetailColumnTypeEnum columnType : values) {
+			if(Stream.of(columnType.getTypes()).anyMatch(f -> type != null && f.intValue() == type)) {
+				return columnType;
+			}
+		}
+		return DetailColumnTypeEnum.STRING;
+	}
+}

+ 251 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/DsTypeEnum.java

@@ -0,0 +1,251 @@
+/**
+ * 
+ */
+package org.springblade.datasource.enums;
+
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Map;
+import java.util.function.Function;
+
+import org.springblade.datasource.constants.DsConstant;
+import org.springblade.datasource.model.DatasourceDto;
+
+/**
+ * @author wookvn
+ *	数据源
+ */
+@Getter
+@AllArgsConstructor
+public enum DsTypeEnum {
+
+	/**
+	 * zeroDateTimeBehavior=convertToNull - 解决java.sql.SQLException: Zero date value prohibited 
+	 * allowPublicKeyRetrieval=true - 解决mysql8.0 Public Key Retrieval is not allowed
+	 * rewriteBatchedStatements=true - 低版本的mysql驱动批量插入优化
+	 */
+	mysql(0, false, "com.mysql.cj.jdbc.Driver", "select 1", 3000, 1000000,
+			args -> String.format("select count(*) from (select 1 from %s limit %s) a", args), 
+			ds -> String.format("jdbc:mysql://%s:%s/%s", ds.getDsIp(), ds.getDsPort(), ds.getDsDb()) + "?useSSL=false&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8",
+			sql -> StrUtil.containsAnyIgnoreCase(sql, " limit ")){
+		@Override
+		public Map<String, String> jdbcConnectionPropTimeout() {
+			//https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html
+			return MapUtil.builder("connectTimeout", String.valueOf(DsConstant.CONNECT_TIMEOUT * 5))
+					.put("socketTimeout", String.valueOf(DsConstant.READ_TIMEOUT * 18))
+					.map();
+		}
+		@Override
+		public Map<String, String> jdbcConnectionPropDefault() {
+			return null;
+		}
+	},
+	
+	oracle(1, false, "oracle.jdbc.OracleDriver", "select 1 from dual", 5000, 1000000,
+			args -> String.format("SELECT count(1) FROM %s WHERE ROWNUM <= %s", args), 
+			ds -> String.format("jdbc:oracle:thin:@%s:%s/%s", ds.getDsIp(), ds.getDsPort(), ds.getDsDb()),
+			sql -> StrUtil.containsAnyIgnoreCase(sql, " top ", "row_number()", " offset ")){
+		@Override
+		public Map<String, String> jdbcConnectionPropTimeout() {
+			//https://docs.oracle.com/en/database/oracle/oracle-database/21/jajdb/oracle/jdbc/OracleConnection.html
+			//http://www.javamonamour.org/2012/09/oraclenetconnecttimeout.html
+			//oracle.net.READ_TIMEOUT for jdbc versions < 10.1.0.5 oracle.jdbc.ReadTimeout for jdbc versions >=10.1.0.5
+			return MapUtil.builder("oracle.net.CONNECT_TIMEOUT", String.valueOf(DsConstant.CONNECT_TIMEOUT))
+					.put("oracle.net.READ_TIMEOUT", String.valueOf(DsConstant.READ_TIMEOUT * 2))
+					.put("oracle.jdbc.ReadTimeout", String.valueOf(DsConstant.READ_TIMEOUT * 2))
+					.map();
+		}
+		@Override
+		public Map<String, String> jdbcConnectionPropDefault() {
+			return null;
+		}
+	},
+	
+	sqlserver(2, false, "com.microsoft.sqlserver.jdbc.SQLServerDriver", "select 1", 3000, 1000000,
+			args -> String.format("SELECT rows FROM sysindexes WHERE id = OBJECT_ID('%s') AND indid < 2", args), 
+			ds -> String.format("jdbc:sqlserver://%s:%s;DatabaseName=%s;encrypt=true;trustServerCertificate=true", ds.getDsIp(), ds.getDsPort(), ds.getDsDb()),
+			sql -> StrUtil.containsAnyIgnoreCase(sql, " top ", "fetch next")){
+		@Override
+		public Map<String, String> jdbcConnectionPropTimeout() {
+			//https://learn.microsoft.com/en-us/sql/connect/jdbc/understand-timeouts?view=sql-server-ver16
+			return MapUtil.builder("loginTimeout", String.valueOf(DsConstant.CONNECT_TIMEOUT/1000))
+					.put("queryTimeout", String.valueOf(DsConstant.READ_TIMEOUT/1000))
+					.put("socketTimeout", String.valueOf(DsConstant.READ_TIMEOUT))
+					.put("lockTimeout", String.valueOf(DsConstant.READ_TIMEOUT))
+					.map();
+		}
+		@Override
+		public Map<String, String> jdbcConnectionPropDefault() {
+			return null;
+		}
+	},
+	
+	postgresql(3, false, "org.postgresql.Driver", "select 1", 3000, 1000000,
+			args -> String.format("select count(*) from (select 1 from %s limit %s) a", args), 
+			ds -> String.format("jdbc:postgresql://%s:%s/%s?currentSchema=%s", ds.getDsIp(), ds.getDsPort(), ds.getDsDb(), ds.getDbSchema()),
+			sql -> StrUtil.containsAnyIgnoreCase(sql, " limit ", " offset ")){
+		@Override
+		public Map<String, String> jdbcConnectionPropTimeout() {
+			//https://jdbc.postgresql.org/documentation/use/
+			return MapUtil.builder("loginTimeout", String.valueOf(DsConstant.CONNECT_TIMEOUT/1000))
+					.put("connectTimeout", String.valueOf(DsConstant.CONNECT_TIMEOUT/1000))
+					.put("socketTimeout", String.valueOf(DsConstant.READ_TIMEOUT/1000))
+					.map();
+		}
+		@Override
+		public Map<String, String> jdbcConnectionPropDefault() {
+			return null;
+		}
+	},
+	
+	clickhouse(4, false, "com.clickhouse.jdbc.ClickHouseDriver", "select 1", 50000, 100000000,
+			args -> String.format("select count(1) from %s", args), 
+			ds -> String.format("jdbc:clickhouse://%s:%s/%s", ds.getDsIp(), ds.getDsPort(), ds.getDsDb()),
+			sql -> StrUtil.containsAnyIgnoreCase(sql, " limit ")){
+		@Override
+		public Map<String, String> jdbcConnectionPropTimeout() {
+			return MapUtil.builder("socket_timeout", String.valueOf(DsConstant.READ_TIMEOUT))
+					.put("connect_timeout", String.valueOf(DsConstant.CONNECT_TIMEOUT))
+					.map();
+		}
+		@Override
+		public Map<String, String> jdbcConnectionPropDefault() {
+			return null;
+		}
+	},
+	
+	kingbase(5, true, "com.kingbase8.Driver", "select 1", 3000, 1000000, 
+			args -> String.format("select count(*) from (select 1 from %s limit %s) a", args), 
+			ds -> String.format("jdbc:kingbase8://%s:%s/%s?currentSchema=%s", ds.getDsIp(), ds.getDsPort(), ds.getDsDb(), ds.getDbSchema()),
+			sql -> StrUtil.containsAnyIgnoreCase(sql, " limit ", " offset ")){
+		@Override
+		public Map<String, String> jdbcConnectionPropTimeout() {
+			//https://help.kingbase.com.cn/v8/development/client-interfaces/jdbc/jdbc-2.html#id2
+			return MapUtil.builder("loginTimeout", String.valueOf(DsConstant.CONNECT_TIMEOUT/1000))
+					.put("connectTimeout", String.valueOf(DsConstant.CONNECT_TIMEOUT/1000))
+					.put("socketTimeout", String.valueOf(DsConstant.READ_TIMEOUT/1000))
+					.map();
+		}
+		@Override
+		public Map<String, String> jdbcConnectionPropDefault() {
+			return null;
+		}
+	},
+	
+	dameng(6, false, "dm.jdbc.driver.DmDriver", "select 1", 3000, 1000000, 
+			args -> String.format("select count(*) from (select 1 from %s limit %s) a", args), 
+			ds -> String.format("jdbc:dm://%s:%s/%s?schema=%s&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8", ds.getDsIp(), ds.getDsPort(), ds.getDsDb(), ds.getDbSchema()),
+			sql -> StrUtil.containsAnyIgnoreCase(sql, " limit ", "row_number()", " top ")){
+		@Override
+		public Map<String, String> jdbcConnectionPropTimeout() {
+			//https://eco.dameng.com/document/dm/zh-cn/pm/jdbc-rogramming-guide.html#4.5.4%20DM%20%E6%89%A9%E5%B1%95%E8%BF%9E%E6%8E%A5%E5%B1%9E%E6%80%A7%E7%9A%84%E4%BD%BF%E7%94%A8
+			return MapUtil.builder("connectTimeout", String.valueOf(DsConstant.CONNECT_TIMEOUT))
+					.put("socketTimeout", String.valueOf(DsConstant.READ_TIMEOUT))
+					.put("sessionTimeout", String.valueOf(DsConstant.READ_TIMEOUT))
+					.map();
+		}
+		@Override
+		public Map<String, String> jdbcConnectionPropDefault() {
+			return null;
+		}
+	},
+
+	uxdb(7, false, "com.uxsino.uxdb.Driver", "select 1", 3000, 1000000,
+			args -> String.format("select count(*) from (select 1 from %s limit %s) a", args),
+			ds -> String.format("jdbc:uxdb://%s:%s/%s?transfer=true", ds.getDsIp(), ds.getDsPort(), ds.getDsDb()),
+			sql -> StrUtil.containsAnyIgnoreCase(sql, " limit ", " offset ")){
+		@Override
+		public Map<String, String> jdbcConnectionPropTimeout() {
+			return MapUtil.builder("connectTimeout", String.valueOf(DsConstant.CONNECT_TIMEOUT/1000))
+					.put("loginTimeout", String.valueOf(DsConstant.CONNECT_TIMEOUT/1000))
+					.put("socketTimeout", String.valueOf(DsConstant.READ_TIMEOUT/1000))
+					.put("queryTimeout", String.valueOf(DsConstant.READ_TIMEOUT/1000))
+					.map();
+		}
+		@Override
+		public Map<String, String> jdbcConnectionPropDefault() {
+			return null;
+		}
+	},
+	// jdbc:xugu://121.204.249.37:5138/platomix
+	// com.xugu.cloudjdbc.Driver
+	xugu(8, false, "com.xugu.cloudjdbc.Driver", "select 1", 3000, 1000000,
+			args -> String.format("select count(1) from %s?char_set=UTF8", args),
+			ds -> String.format("jdbc:xugu://%s:%s/%s", ds.getDsIp(), ds.getDsPort(), ds.getDsDb()),
+			sql -> StrUtil.containsAnyIgnoreCase(sql, "  rownum ")){
+		@Override
+		public Map<String, String> jdbcConnectionPropTimeout() {
+			return MapUtil.builder("loginTimeout", String.valueOf(DsConstant.CONNECT_TIMEOUT/10000))
+					.put("maxWaitTimeout", String.valueOf(DsConstant.READ_TIMEOUT/10000))
+					.map();
+		}
+		@Override
+		public Map<String, String> jdbcConnectionPropDefault() {
+			return null;
+		}
+	},
+
+	//通用版本
+	common(-1, false, "common", "common", 0, 0, args -> null, t -> null, t -> null){
+		@Override
+		public Map<String, String> jdbcConnectionPropTimeout() { return null; }
+		@Override
+		public Map<String, String> jdbcConnectionPropDefault() {return null;}
+	};
+	
+	@EnumValue
+	private Integer value;
+	/**
+	 * 数据库查询出来的字段名是否都是小写
+	 */
+	private boolean fieldLowerCase;
+	private String driverClassName;
+	private String validationQuery;
+	/**
+	 * 批量入库数量
+	 */
+	private int batchSize;
+	/**
+	 * 查询最大限制数量
+	 */
+	private int selectLimitVal;
+	/**
+	 * 校验数据量大小函数
+	 */
+	private Function<Object[], String> checkLimitValueFunction;
+	private Function<DatasourceDto, String> driverUrlFunction;
+	/**
+	 * 是否包含分页语句
+	 */
+	private Function<String, Boolean> hasLimitStatementFunction;
+	
+	/**
+	 * jdbc驱动连接超时配置 [测试连接超时]
+	 * @return
+	 */
+	public abstract Map<String, String> jdbcConnectionPropTimeout();
+	/**
+	 * jdbc驱动默认连接配置
+	 * @return
+	 */
+	public abstract Map<String, String> jdbcConnectionPropDefault();
+
+	/**
+	 * 解析
+	 * @param value
+	 * @return
+	 */
+	public static DsTypeEnum resolve(Integer value) {
+		DsTypeEnum[] values = DsTypeEnum.values();
+		for(DsTypeEnum dsType : values) {
+			if(value != null && dsType.getValue().intValue() == value) {
+				return dsType;
+			}
+		}
+		return DsTypeEnum.mysql;
+	}
+}

+ 68 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/FunctionMethodEnum.java

@@ -0,0 +1,68 @@
+/**
+ * 
+ */
+package org.springblade.datasource.enums;
+
+/**
+ * @author wookvn
+ *
+ */
+public enum FunctionMethodEnum {
+
+	/**
+	 * 日期转字符串
+	 */
+	DATE_TO_STR,
+	/**
+	 * 字符串转日期
+	 */
+	STR_TO_DATE,
+	/**
+	 * 数字转日期
+	 */
+	NUMBER_TO_DATE,
+	/**
+	 * 数字连接百分号
+	 */
+	NUMBER_JOINT_PERCENT,
+	/**
+	 * 年份提取
+	 */
+	EXTRACT_YEAR,
+	/**
+	 * 季度提取
+	 */
+	EXTRACT_QUARTER,
+	/**
+	 * 月份提取
+	 */
+	EXTRACT_MONTH,
+	/**
+	 * 周提取
+	 */
+	EXTRACT_WEEK,
+	/**
+	 * 日提取
+	 */
+	EXTRACT_DAY,
+	/**
+	 * 小时提取
+	 */
+	EXTRACT_HOUR,
+	/**
+	 * 分钟提取
+	 */
+	EXTRACT_MINUTE,
+	/**
+	 * 秒提取
+	 */
+	EXTRACT_SECOND,
+	/**
+	 * 全日期
+	 */
+	EXTRACT_FULL,
+	;
+	
+	private Integer value;
+	private String message;
+}

+ 101 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/NumberFormatEnum.java

@@ -0,0 +1,101 @@
+/**
+ * 
+ */
+package org.springblade.datasource.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+
+/**
+ * @author wookvn
+ *	
+ *	数字格式化
+ */
+public enum NumberFormatEnum {
+
+	/**
+	 * 自动
+	 */
+	AUTO(0, "%s", ""),
+	
+	/**
+	 * 整数
+	 */
+	INTEGER(1, "round(%s, 0)", ""),
+	
+	/**
+	 * 保留一位小数
+	 */
+	RETAIN1(2, "round(%s, 1)", ""),
+	
+	/**
+	 * 保留二位小数
+	 */
+	RETAIN2(3, "round(%s, 2)", ""),
+	
+	/**
+	 * 百分比
+	 */
+	PERCENT(4, "round(%s*100, 0)", "fm99999999990"),
+	
+	/**
+	 * 百分比保留一位小数
+	 */
+	PERCENT1(5, "round(%s*100, 1)", "fm99999999990.0"),
+	
+	/**
+	 * 百分比保留二位小数
+	 */
+	PERCENT2(6, "round(%s*100, 2)", "fm99999999990.00"),
+	
+	/**
+	 * 自定义公式(前端处理)
+	 */
+	CUSTOM(7, "%s", "");
+	
+	@EnumValue
+	private int value;
+	private String method;
+	private String oracleFmFormat;
+
+	/**
+	 * @param value
+	 */
+	private NumberFormatEnum(int value, String method, String oracleFmFormat) {
+		this.value = value;
+		this.method = method;
+		this.oracleFmFormat = oracleFmFormat;
+	}
+
+	/**
+	 * @return the value
+	 */
+	public int getValue() {
+		return value;
+	}
+
+	/**
+	 * @return the method
+	 */
+	public String getMethod() {
+		return method;
+	}
+	
+	/**
+	 * 
+	 * @return
+	 */
+	public String getOracleFmFormat() {
+		return oracleFmFormat;
+	}
+	
+	/**
+	 * 是否百分比显示
+	 * @param numberFormat
+	 * @return
+	 */
+	public static boolean isPercentFormat(NumberFormatEnum numberFormat) {
+		return numberFormat == NumberFormatEnum.PERCENT || numberFormat == NumberFormatEnum.PERCENT1
+				||numberFormat == NumberFormatEnum.PERCENT2;
+	}
+	
+}

+ 98 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/enums/ViewColumnTypeEnum.java

@@ -0,0 +1,98 @@
+/**
+ *
+ */
+package org.springblade.datasource.enums;
+
+import static java.sql.Types.ARRAY;
+import static java.sql.Types.BINARY;
+import static java.sql.Types.BIT;
+import static java.sql.Types.BLOB;
+import static java.sql.Types.BOOLEAN;
+import static java.sql.Types.CHAR;
+import static java.sql.Types.CLOB;
+import static java.sql.Types.DATE;
+import static java.sql.Types.DECIMAL;
+import static java.sql.Types.DOUBLE;
+import static java.sql.Types.FLOAT;
+import static java.sql.Types.INTEGER;
+import static java.sql.Types.LONGNVARCHAR;
+import static java.sql.Types.LONGVARBINARY;
+import static java.sql.Types.LONGVARCHAR;
+import static java.sql.Types.NCHAR;
+import static java.sql.Types.NCLOB;
+import static java.sql.Types.NUMERIC;
+import static java.sql.Types.NVARCHAR;
+import static java.sql.Types.REAL;
+import static java.sql.Types.SMALLINT;
+import static java.sql.Types.TIME;
+import static java.sql.Types.TIMESTAMP;
+import static java.sql.Types.TINYINT;
+import static java.sql.Types.VARBINARY;
+import static java.sql.Types.VARCHAR;
+
+import java.util.stream.Stream;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+
+/**
+ * @author wookvn
+ *
+ * 显示的字段类型
+ */
+public enum ViewColumnTypeEnum {
+
+    STRING(1, new Integer[]{CHAR, VARCHAR, LONGVARCHAR, BINARY, VARBINARY, LONGVARBINARY, BLOB, CLOB, NCHAR, NVARCHAR, LONGNVARCHAR, NCLOB, ARRAY}),
+
+    DATETIME(2, new Integer[]{DATE, TIME, TIMESTAMP}),
+
+    NUMBER(3, new Integer[]{BIT, TINYINT, SMALLINT, INTEGER, java.sql.Types.BIGINT, FLOAT, REAL, DOUBLE, NUMERIC, DECIMAL, BOOLEAN}),
+
+    //特殊处理
+    BIGINT(4, new Integer[0]),
+    /**
+     * 长字符串
+     */
+    LARGE_STRING(5, new Integer[0]),
+    /**
+     * 整数
+     */
+    INT(6, new Integer[0]),
+
+    ;
+
+    @EnumValue
+    private int value;
+    private Integer[] types;
+
+    /**
+     * @param value
+     */
+    private ViewColumnTypeEnum(int value, Integer[] types) {
+        this.value = value;
+        this.types = types;
+    }
+
+    /**
+     * @return the value
+     */
+    public int getValue() {
+        return value;
+    }
+
+    /**
+     * @return the types
+     */
+    public Integer[] getTypes() {
+        return types;
+    }
+
+    public static ViewColumnTypeEnum resolve(Integer type) {
+        ViewColumnTypeEnum[] values = ViewColumnTypeEnum.values();
+        for (ViewColumnTypeEnum columnType : values) {
+            if (Stream.of(columnType.getTypes()).anyMatch(f -> type != null && f.intValue() == type)) {
+                return columnType;
+            }
+        }
+        return ViewColumnTypeEnum.STRING;
+    }
+}

+ 67 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/model/DatasourceDto.java

@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018-2028, AoKunSang All rights reserved.
+ * 我问青山何时老,青山问我几时闲,
+ * 不是闲人闲不得,能闲必非等闲人。
+ */
+package org.springblade.datasource.model;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import org.springblade.datasource.enums.DsTypeEnum;
+
+/**
+ * 数据源Dto
+ *
+ * @author wookvn
+ * @datetime 2025-01-13 16:37:31
+ */
+@Data
+public class DatasourceDto implements Serializable {
+
+    private Integer id;
+    /**
+     * ip地址
+     */
+    private String dsIp;
+    /**
+     * 端口
+     */
+    private Integer dsPort;
+    /**
+     * 数据库名/SID
+     */
+    private String dsDb;
+    /**
+     * 连接url
+     */
+    private String url;
+    /**
+     * 连接唯一标识符
+     */
+    private String poolName;
+    /**
+     * driverClassName
+     */
+    private String driverClassName;
+    /**
+     * 用户名
+     */
+    private String dsUser;
+    /**
+     * 密码
+     */
+    private String dsPassword;
+    /**
+     * 数据库schema
+     */
+    private String dbSchema;
+    /**
+     * 数据源类型
+     */
+    private DsTypeEnum dsTypeSyl;
+    /**
+     * 数据源连接参数
+     */
+    private String customConnectProperties;
+}

+ 114 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/model/FileStructureDto.java

@@ -0,0 +1,114 @@
+/**
+ * 
+ */
+package org.springblade.datasource.model;
+
+import lombok.Data;
+import org.springblade.datasource.enums.DetailColumnTypeEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+
+import java.io.Serializable;
+
+/**
+ * <p>文件上传结构体</p>
+ * @author  wookvn
+ * @datetime 2025-01-13 16:44:13
+ */
+@Data
+public class FileStructureDto implements Serializable {
+
+	/**
+	 *
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 字段名
+	 */
+	private String columnName;
+
+	/**
+	 * 字段类型
+	 */
+	private ViewColumnTypeEnum columnType;
+
+	/**
+	 * 字段归类细化类型
+	 */
+	private DetailColumnTypeEnum detailColumnType;
+
+	/**
+	 * 注释
+	 */
+	private String comment;
+
+	/**
+	 * 是否主键
+	 */
+	private boolean primaryKey;
+
+	/**
+	 * 字段长度
+	 */
+	private Integer columnSize;
+
+	/**
+	 * 小数点后的位数
+	 */
+	private Integer decimalDigits;
+
+	/**
+	 * 系统默认字段名(COL_开头)
+	 */
+	private String systemColumnName;
+	/**
+	 * 全拼字段名
+	 */
+	private String pinyinAllColumnName;
+	/**
+	 * 首字母字段名
+	 */
+	private String pinyinFirstLetterColumnName;
+
+	/**
+	 * 字段在excel的索引 - 主要用于取数据
+	 */
+	private int columnIndex;
+
+	/**
+	 * @param columnName
+	 * @param columnType
+	 * @param comment
+	 * @param columnIndex
+	 */
+	public FileStructureDto(String columnName, ViewColumnTypeEnum columnType, String comment, int columnIndex) {
+		super();
+		this.columnName = columnName;
+		this.columnType = columnType;
+		this.comment = comment;
+		this.columnIndex = columnIndex;
+	}
+
+	public FileStructureDto(String columnName, ViewColumnTypeEnum columnType, String comment, boolean primaryKey) {
+		super();
+		this.columnName = columnName;
+		this.columnType = columnType;
+		this.comment = comment;
+		this.primaryKey = primaryKey;
+	}
+	public FileStructureDto(String columnName, ViewColumnTypeEnum columnType, DetailColumnTypeEnum detailColumnType, String comment, boolean primaryKey) {
+		super();
+		this.columnName = columnName;
+		this.columnType = columnType;
+		this.detailColumnType = detailColumnType;
+		this.comment = comment;
+		this.primaryKey = primaryKey;
+	}
+
+	/**
+	 *
+	 */
+	public FileStructureDto() {
+		super();
+	}
+}

+ 17 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/model/LongReference.java

@@ -0,0 +1,17 @@
+/**
+ * 
+ */
+package org.springblade.datasource.model;
+
+import lombok.Data;
+
+/**
+ * @author wookvn
+ *  
+ * 主键值返回引用对象
+ */
+@Data
+public class LongReference {
+
+	private Long value;
+}

+ 77 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/model/TableColumnDto.java

@@ -0,0 +1,77 @@
+/**
+ * 
+ */
+package org.springblade.datasource.model;
+
+import lombok.Data;
+import org.springblade.datasource.enums.DetailColumnTypeEnum;
+import org.springblade.datasource.enums.ViewColumnTypeEnum;
+
+import java.io.Serializable;
+
+/**
+ * @author wookvn
+ *
+ */
+@Data
+public class TableColumnDto implements Serializable {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 字段名称
+	 */
+	private String columnName;
+
+	/**
+	 * 字段注释
+	 */
+	private String columnComments;
+
+	/**
+	 * 字段类型
+	 */
+	private String dataType;
+
+	/**
+	 * 字段大小(对于 numeric 和 decimal 类型,列的精度)
+	 */
+	private Integer columnSize;
+	
+	/**
+	 * 小数部分位数
+	 */
+	private Integer decimalDigits;
+	
+	/**
+	 * 字段归类大类类型
+	 */
+	private ViewColumnTypeEnum columnType;
+	
+	/**
+	 * 字段归类细化类型
+	 */
+	private DetailColumnTypeEnum detailColumnType;
+	
+	/**
+	 * 是否允许为NULL(1-是/0-否)
+	 */
+	private Integer nullAbleStatus;
+	
+    /**
+     * 是否主键(1-是/0-否)
+     */
+    private Integer primaryKeyStatus;
+    
+    /**
+     * 是否自增
+     */
+    private Integer autoIncrementStatus = 0;
+
+	//冗余字段,目前仅用于业务处理
+	private String tableName;
+	private String tableAlias;
+}

+ 39 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/model/TableViewDto.java

@@ -0,0 +1,39 @@
+/**
+ * 
+ */
+package org.springblade.datasource.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @author wookvn
+ *
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TableViewDto implements Serializable {
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 视图或表名称
+	 */
+	private String tableViewName;
+
+	/**
+	 * 表注释
+	 */
+	private String tableComments;
+
+	/**
+	 * 数据源id
+	 */
+	private Integer datasourceId;
+}

+ 87 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/support/BladexDataSourceProvider.java

@@ -0,0 +1,87 @@
+/**
+ * 
+ */
+package org.springblade.datasource.support;
+
+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.AbstractJdbcDataSourceProvider;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springblade.datasource.model.DatasourceDto;
+import org.springblade.datasource.util.DatasourceUtil;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * @author wookvn
+ *
+ */
+@Slf4j
+public class BladexDataSourceProvider extends AbstractJdbcDataSourceProvider {
+	
+	private final DynamicDataSourceProperties dynamicDataSourceProperties;
+	
+	public BladexDataSourceProvider(DefaultDataSourceCreator defaultDataSourceCreator, DynamicDataSourceProperties dynamicDataSourceProperties, String url, String username, String password) {
+		super(defaultDataSourceCreator, url, username, password);
+		this.dynamicDataSourceProperties = dynamicDataSourceProperties;
+	}
+	
+	@Override
+	protected Map<String, DataSourceProperty> executeStmt(Statement statement) throws SQLException {
+		log.info("开始初始化动态数据源");
+		Map<String, DataSourceProperty> dsMap = new HashMap<String, DataSourceProperty>();
+		ResultSet rs = statement.executeQuery("select * from report_datasource where is_deleted = 0");
+		List<CompletableFuture<Boolean>> futureList = new ArrayList<CompletableFuture<Boolean>>();
+		DruidConfig druid = dynamicDataSourceProperties.getDruid();
+		while(rs.next()) {
+			String poolName = rs.getString("pool_name"),
+				   driverClassName = rs.getString("driver_class_name"),
+				   url = rs.getString("url"),
+				   dsUser = rs.getString("ds_user"),
+				   dsPassword = rs.getString("ds_password"),
+				   dsDbname = rs.getString("ds_db"),
+				   customConnectProperties = rs.getString("custom_connect_properties");
+			int dsType = rs.getInt("ds_type"),
+			    id     = rs.getInt("id");
+			futureList.add(CompletableFuture.supplyAsync(() -> {
+				DataSourceProperty dataSourceProperty = new DataSourceProperty();
+				dataSourceProperty.setPoolName(poolName);
+				dataSourceProperty.setDriverClassName(driverClassName);
+				dataSourceProperty.setUrl(url);
+				dataSourceProperty.setUsername(dsUser);
+				dataSourceProperty.setPassword(dsPassword);
+				dataSourceProperty.setLazy(true);
+				//校验连接成功,允许初始化添加到动态数据源
+				DatasourceDto reportDs = new DatasourceDto();
+				reportDs.setDsUser(dataSourceProperty.getUsername());
+				reportDs.setDsPassword(dataSourceProperty.getPassword());
+				reportDs.setUrl(dataSourceProperty.getUrl());
+				reportDs.setDsTypeSyl(DsTypeEnum.resolve(dsType));
+				reportDs.setCustomConnectProperties(customConnectProperties);
+				if(DatasourceUtil.testDs(reportDs) == null) { //特殊处理一下数据源
+					//设置jdbc驱动连接属性
+					dataSourceProperty.setDruid(DatasourceUtil.customConnectionConfig(druid, reportDs));
+					log.info(">>>>INIT_DS_SUCCESS|id={},type={},db={},validationQuery={}", id, reportDs.getDsTypeSyl().name(), dsDbname, reportDs.getDsTypeSyl().getValidationQuery());
+					dsMap.put(poolName, dataSourceProperty);
+					return true;
+				}else {
+					log.warn("####INIT_DS_FAILURE|id={},db={},dsType={}", id, dsDbname, reportDs.getDsTypeSyl());
+					return false;
+				}
+			}));
+		}
+		CompletableFuture.allOf(futureList.stream().toArray(CompletableFuture[]::new)).join();
+		log.info("数据源初始化完成");
+		return dsMap;
+	}
+}

+ 94 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/support/DynamicDataSourceSupport.java

@@ -0,0 +1,94 @@
+/**
+ * 
+ */
+package org.springblade.datasource.support;
+
+import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
+import com.baomidou.dynamic.datasource.creator.druid.DruidDataSourceCreator;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.datasource.model.DatasourceDto;
+import org.springblade.datasource.util.DatasourceUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author wookvn
+ *
+ */
+@Slf4j
+@Component
+public class DynamicDataSourceSupport {
+
+	@Autowired
+	private DynamicRoutingDataSource dynamicRoutingDataSource;
+
+	@Autowired
+	private DruidDataSourceCreator dataSourceCreator;
+	
+	@Autowired
+	private DynamicDataSourceProperties dynamicDataSourceProperties;
+
+	/**
+	 * 添加数据源
+	 * 
+	 * @param ds
+	 * @return
+	 */
+	public boolean addDs(DatasourceDto ds) {
+		try {
+			if (DatasourceUtil.testDs(ds) == null) {
+				DataSourceProperty dataSourceProperty = new DataSourceProperty();
+				dataSourceProperty.setPoolName(ds.getPoolName());
+				dataSourceProperty.setUrl(ds.getUrl());
+				dataSourceProperty.setUsername(ds.getDsUser());
+				dataSourceProperty.setPassword(ds.getDsPassword());
+				dataSourceProperty.setDriverClassName(ds.getDriverClassName());
+				//设置数据源连接属性
+				dataSourceProperty.setDruid(DatasourceUtil.customConnectionConfig(dynamicDataSourceProperties.getDruid(), ds));
+				DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
+				dynamicRoutingDataSource.addDataSource(ds.getPoolName(), dataSource);
+				return true;
+			}
+		} catch (Exception e) {
+			log.error(e.getMessage(), e);
+			throw new RuntimeException("数据源连接失败");
+		}
+		return false;
+	}
+
+	/**
+	 * 移除数据源
+	 * 
+	 * @param poolName
+	 * @return
+	 */
+	public boolean removeDs(String poolName) throws Exception {
+		dynamicRoutingDataSource.removeDataSource(poolName);
+		return true;
+	}
+
+	/**
+	 * 获取所有数据源
+	 * 
+	 * @return List<poolName>
+	 */
+	public List<String> getAllDs() {
+		List<String> dsList = new ArrayList<String>();
+		Map<String, DataSource> dataSources = dynamicRoutingDataSource.getDataSources();
+		if (dataSources != null && !dataSources.isEmpty()) {
+			for (Map.Entry<String, DataSource> entry : dataSources.entrySet()) {
+				dsList.add(entry.getKey());
+			}
+		}
+		return dsList;
+	}
+
+
+}

+ 105 - 0
platomix-gmetry-datasource/src/main/java/org/springblade/datasource/util/DatasourceUtil.java

@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018-2028, AoKunSang All rights reserved.
+ * 我问青山何时老,青山问我几时闲,
+ * 不是闲人闲不得,能闲必非等闲人。
+ */
+package org.springblade.datasource.util;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.dynamic.datasource.creator.druid.DruidConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.datasource.enums.DsTypeEnum;
+import org.springblade.datasource.model.DatasourceDto;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * 数据源操作类
+ *
+ * @author wookvn
+ * @datetime 2025-01-13 17:26:30
+ */
+@Slf4j
+public class DatasourceUtil {
+
+    /**
+     * 测试数据源
+     *
+     * @param ds
+     * @return
+     */
+    public static String testDs(DatasourceDto ds) {
+        try (Connection connection = DatasourceUtil.createConnection(ds);
+             Statement statement = connection.createStatement();){
+            statement.executeQuery(ds.getDsTypeSyl().getValidationQuery());
+            return null;
+        } catch (Exception e) {
+            log.error("测试数据源连接失败:" + e.getMessage(), e);
+            return e.getMessage();
+        }
+    }
+
+    /**
+     * 创建连接
+     * @param ds
+     * @return
+     * @throws SQLException
+     */
+    public static Connection createConnection(DatasourceDto ds) throws Exception {
+        Properties props = new Properties();
+        props.put("user", ds.getDsUser());
+        props.put("password", ds.getDsPassword());
+        //用于显示字段注释
+        props.put("remarks", "true");
+//		props.put("useInformationSchema", "true");
+        props.put("remarksReporting", "true");
+        props.put("nullCatalogMeansCurrent", "true");
+        //获取每个数据库的超时时间
+        Map<String, String> timeoutMap = ds.getDsTypeSyl().jdbcConnectionPropTimeout();
+        if(timeoutMap == null) {
+            throw new RuntimeException(String.format("数据库[%s]未设置超时时间,请先设置", ds.getDsTypeSyl().name()));
+        }
+        props.putAll(timeoutMap);
+        if(ds.getDsTypeSyl() == DsTypeEnum.xugu) {
+            Class.forName("com.xugu.cloudjdbc.Driver");
+        }
+        return DriverManager.getConnection(ds.getUrl(), props);
+    }
+
+    /**
+     * 初始化jdbc连接配置
+     * @param druidConfig
+     * @param reportDs
+     * @return
+     */
+    public static DruidConfig customConnectionConfig(DruidConfig druidConfig, DatasourceDto reportDs) {
+        //先获取yml中通用的数据源配置
+        DruidConfig cloneDruidConfig = BeanUtil.copyProperties(druidConfig, DruidConfig.class);
+        Properties connectionProperties = new Properties();
+        //先获取数据源默认jdbc连接配置
+        Map<String, String> jdbcConnectionPropDefault = reportDs.getDsTypeSyl().jdbcConnectionPropDefault();
+        if(jdbcConnectionPropDefault != null) {
+            connectionProperties.putAll(jdbcConnectionPropDefault);
+        }
+        //设置自定义jdbc连接配置
+        if(StrUtil.isNotBlank(reportDs.getCustomConnectProperties())) {
+            JSONObject jsonObject = JSON.parseObject(reportDs.getCustomConnectProperties());
+            if(jsonObject != null) {
+                connectionProperties.putAll(jsonObject);
+            }
+        }
+        //设置jdbc驱动连接属性
+        cloneDruidConfig.setConnectionProperties(connectionProperties);
+        //设置数据源的校验查询语句
+        cloneDruidConfig.setValidationQuery(reportDs.getDsTypeSyl().getValidationQuery());
+        return cloneDruidConfig;
+    }
+}

+ 2 - 0
platomix-gmetry-datasource/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.springblade.datasource.config.GmetryDatasourceAutoConfiguration

+ 1 - 0
pom.xml

@@ -12,5 +12,6 @@
   	<module>platomix-gmetry-message</module>
   	<module>platomix-docker</module>
       <module>platomix-gmetry-auth</module>
+      <module>platomix-gmetry-datasource</module>
   </modules>
 </project>