mirror of
https://gitee.com/orangeform/orange-admin.git
synced 2026-01-17 10:36:31 +08:00
commit:升级到vue3,更新最近工作流技术栈,支持sa-token
This commit is contained in:
54
OrangeFormsOpen-MybatisFlex/common/common-dbutil/pom.xml
Normal file
54
OrangeFormsOpen-MybatisFlex/common/common-dbutil/pom.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?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">
|
||||
<parent>
|
||||
<artifactId>common</artifactId>
|
||||
<groupId>com.orangeforms</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>common-dbutil</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<name>common-dbutil</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.orangeforms</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.22</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.oracle.database.jdbc</groupId>
|
||||
<artifactId>ojdbc6</artifactId>
|
||||
<version>11.2.0.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.dameng</groupId>
|
||||
<artifactId>DmJdbcDriver18</artifactId>
|
||||
<version>8.1.2.141</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.opengauss</groupId>
|
||||
<artifactId>opengauss-jdbc</artifactId>
|
||||
<version>5.0.0-og</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ru.yandex.clickhouse</groupId>
|
||||
<artifactId>clickhouse-jdbc</artifactId>
|
||||
<version>0.3.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.orangeforms.common.dbutil.constant;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 自定义日期过滤值类型。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public final class CustomDateValueType {
|
||||
/**
|
||||
* 本日。
|
||||
*/
|
||||
public static final String CURRENT_DAY = "1";
|
||||
/**
|
||||
* 本周。
|
||||
*/
|
||||
public static final String CURRENT_WEEK = "2";
|
||||
/**
|
||||
* 本月。
|
||||
*/
|
||||
public static final String CURRENT_MONTH = "3";
|
||||
/**
|
||||
* 本季度。
|
||||
*/
|
||||
public static final String CURRENT_QUARTER = "4";
|
||||
/**
|
||||
* 今年。
|
||||
*/
|
||||
public static final String CURRENT_YEAR = "5";
|
||||
/**
|
||||
* 昨天。
|
||||
*/
|
||||
public static final String LAST_DAY = "11";
|
||||
/**
|
||||
* 上周。
|
||||
*/
|
||||
public static final String LAST_WEEK = "12";
|
||||
/**
|
||||
* 上月。
|
||||
*/
|
||||
public static final String LAST_MONTH = "13";
|
||||
/**
|
||||
* 上季度。
|
||||
*/
|
||||
public static final String LAST_QUARTER = "14";
|
||||
/**
|
||||
* 去年。
|
||||
*/
|
||||
public static final String LAST_YEAR = "15";
|
||||
|
||||
private static final Map<Object, String> DICT_MAP = new HashMap<>(2);
|
||||
static {
|
||||
DICT_MAP.put(CURRENT_DAY, "本日");
|
||||
DICT_MAP.put(CURRENT_WEEK, "本周");
|
||||
DICT_MAP.put(CURRENT_MONTH, "本月");
|
||||
DICT_MAP.put(CURRENT_QUARTER, "本季度");
|
||||
DICT_MAP.put(CURRENT_YEAR, "今年");
|
||||
DICT_MAP.put(LAST_DAY, "昨日");
|
||||
DICT_MAP.put(LAST_WEEK, "上周");
|
||||
DICT_MAP.put(LAST_MONTH, "上月");
|
||||
DICT_MAP.put(LAST_QUARTER, "上季度");
|
||||
DICT_MAP.put(LAST_YEAR, "去年");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断参数是否为当前常量字典的合法值。
|
||||
*
|
||||
* @param value 待验证的参数值。
|
||||
* @return 合法返回true,否则false。
|
||||
*/
|
||||
public static boolean isValid(String value) {
|
||||
return value != null && DICT_MAP.containsKey(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private CustomDateValueType() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.orangeforms.common.dbutil.constant;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据库连接类型常量对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public final class DblinkType {
|
||||
|
||||
/**
|
||||
* MySQL。
|
||||
*/
|
||||
public static final int MYSQL = 0;
|
||||
/**
|
||||
* PostgreSQL。
|
||||
*/
|
||||
public static final int POSTGRESQL = 1;
|
||||
/**
|
||||
* Oracle。
|
||||
*/
|
||||
public static final int ORACLE = 2;
|
||||
/**
|
||||
* Dameng。
|
||||
*/
|
||||
public static final int DAMENG = 3;
|
||||
/**
|
||||
* 人大金仓。
|
||||
*/
|
||||
public static final int KINGBASE = 4;
|
||||
/**
|
||||
* OpenGauss。
|
||||
*/
|
||||
public static final int OPENGAUSS = 5;
|
||||
/**
|
||||
* ClickHouse。
|
||||
*/
|
||||
public static final int CLICKHOUSE = 10;
|
||||
/**
|
||||
* Doris。
|
||||
*/
|
||||
public static final int DORIS = 11;
|
||||
|
||||
private static final Map<Object, String> DICT_MAP = new HashMap<>(3);
|
||||
static {
|
||||
DICT_MAP.put(MYSQL, "MySQL");
|
||||
DICT_MAP.put(POSTGRESQL, "PostgreSQL");
|
||||
DICT_MAP.put(ORACLE, "Oracle");
|
||||
DICT_MAP.put(DAMENG, "Dameng");
|
||||
DICT_MAP.put(KINGBASE, "人大金仓");
|
||||
DICT_MAP.put(OPENGAUSS, "OpenGauss");
|
||||
DICT_MAP.put(CLICKHOUSE, "ClickHouse");
|
||||
DICT_MAP.put(DORIS, "Doris");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断参数是否为当前常量字典的合法值。
|
||||
*
|
||||
* @param value 待验证的参数值。
|
||||
* @return 合法返回true,否则false。
|
||||
*/
|
||||
public static boolean isValid(Integer value) {
|
||||
return value != null && DICT_MAP.containsKey(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private DblinkType() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.orangeforms.common.dbutil.object;
|
||||
|
||||
import com.orangeforms.common.core.constant.FieldFilterType;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 数据集过滤对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class DatasetFilter extends ArrayList<DatasetFilter.FilterInfo> {
|
||||
|
||||
@Data
|
||||
public static class FilterInfo {
|
||||
/**
|
||||
* 过滤的数据集Id。
|
||||
*/
|
||||
private Long datasetId;
|
||||
/**
|
||||
* 过滤参数名称。
|
||||
*/
|
||||
private String paramName;
|
||||
/**
|
||||
* 过滤参数值是单值时。使用该字段值。
|
||||
*/
|
||||
private Object paramValue;
|
||||
/**
|
||||
* 过滤参数值是集合时,使用该字段值。
|
||||
*/
|
||||
private Collection<Serializable> paramValueList;
|
||||
/**
|
||||
* 过滤类型。参考常量类 FieldFilterType。
|
||||
*/
|
||||
private Integer filterType = FieldFilterType.EQUAL;
|
||||
/**
|
||||
* 是否为日期值的过滤。
|
||||
*/
|
||||
private Boolean dateValueFilter = false;
|
||||
/**
|
||||
* 日期精确到。year/month/week/day
|
||||
*/
|
||||
private String dateRange;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.orangeforms.common.dbutil.object;
|
||||
|
||||
import com.orangeforms.common.core.object.MyOrderParam;
|
||||
import com.orangeforms.common.core.object.MyPageParam;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据集查询的各种参数。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class DatasetParam {
|
||||
|
||||
/**
|
||||
* SELECT选择的字段名列表。
|
||||
*/
|
||||
private List<String> selectColumnNameList;
|
||||
/**
|
||||
* 数据集过滤参数。
|
||||
*/
|
||||
private DatasetFilter filter;
|
||||
/**
|
||||
* SQL结果集的参数。
|
||||
*/
|
||||
private DatasetFilter sqlFilter;
|
||||
/**
|
||||
* 分页参数。
|
||||
*/
|
||||
private MyPageParam pageParam;
|
||||
/**
|
||||
* 分组参数。
|
||||
*/
|
||||
private MyOrderParam orderParam;
|
||||
/**
|
||||
* 排序字符串。
|
||||
*/
|
||||
private String orderBy;
|
||||
/**
|
||||
* 该值目前仅用于SQL类型的结果集。
|
||||
* 如果该值为true,SQL结果集中定义的参数都会被替换为 (1 = 1) 的恒成立过滤。
|
||||
* 比如 select * from zz_sys_user where user_status = ${status},
|
||||
* 该值为true的时会被替换为 select * from zz_sys_user where 1 = 1。
|
||||
*/
|
||||
private Boolean disableSqlDatasetFilter = false;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.orangeforms.common.dbutil.object;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 报表通用的查询结果集对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class GenericResultSet<M, T> {
|
||||
|
||||
/**
|
||||
* 查询结果集的字段meta数据列表。
|
||||
*/
|
||||
private List<M> columnMetaList;
|
||||
|
||||
/**
|
||||
* 查询数据集。如果当前结果集为分页查询,将只包含分页数据。
|
||||
*/
|
||||
private List<T> dataList;
|
||||
|
||||
/**
|
||||
* 查询数据总数。如果当前结果集为分页查询,该值为分页前的数据总数,否则为0。
|
||||
*/
|
||||
private Long totalCount = 0L;
|
||||
|
||||
public GenericResultSet(List<M> columnMetaList, List<T> dataList) {
|
||||
this.columnMetaList = columnMetaList;
|
||||
this.dataList = dataList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.orangeforms.common.dbutil.object;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 直接从数据库获取的查询结果集对象。通常内部使用。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class SqlResultSet<T> extends GenericResultSet<SqlTableColumn, T> {
|
||||
|
||||
public SqlResultSet(List<SqlTableColumn> columnMetaList, List<T> dataList) {
|
||||
super(columnMetaList, dataList);
|
||||
}
|
||||
|
||||
public static <D> boolean isEmpty(SqlResultSet<D> rs) {
|
||||
return rs == null || CollUtil.isEmpty(rs.getDataList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.orangeforms.common.dbutil.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据库中的表对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class SqlTable {
|
||||
|
||||
/**
|
||||
* 表名称。
|
||||
*/
|
||||
private String tableName;
|
||||
|
||||
/**
|
||||
* 表注释。
|
||||
*/
|
||||
private String tableComment;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 关联的字段列表。
|
||||
*/
|
||||
private List<SqlTableColumn> columnList;
|
||||
|
||||
/**
|
||||
* 数据库链接Id。
|
||||
*/
|
||||
private Long dblinkId;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.orangeforms.common.dbutil.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 数据库中的表字段对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class SqlTableColumn {
|
||||
|
||||
/**
|
||||
* 表字段名。
|
||||
*/
|
||||
private String columnName;
|
||||
|
||||
/**
|
||||
* 字段注释。
|
||||
*/
|
||||
private String columnComment;
|
||||
|
||||
/**
|
||||
* 表字段类型。
|
||||
*/
|
||||
private String columnType;
|
||||
|
||||
/**
|
||||
* 表字段全类型。
|
||||
*/
|
||||
private String fullColumnType;
|
||||
|
||||
/**
|
||||
* 是否自动增长。
|
||||
*/
|
||||
private Boolean autoIncrement;
|
||||
|
||||
/**
|
||||
* 是否为主键。
|
||||
*/
|
||||
private Boolean primaryKey;
|
||||
|
||||
/**
|
||||
* 是否可以为空值。
|
||||
*/
|
||||
private Boolean nullable;
|
||||
|
||||
/**
|
||||
* 字段顺序。
|
||||
*/
|
||||
private Integer columnShowOrder;
|
||||
|
||||
/**
|
||||
* 附加信息。
|
||||
*/
|
||||
private String extra;
|
||||
|
||||
/**
|
||||
* 数值型字段精度。
|
||||
*/
|
||||
private Integer numericPrecision;
|
||||
|
||||
/**
|
||||
* 数值型字段刻度。
|
||||
*/
|
||||
private Integer numericScale;
|
||||
|
||||
/**
|
||||
* 字符型字段精度。
|
||||
*/
|
||||
private Long stringPrecision;
|
||||
|
||||
/**
|
||||
* 缺省值。
|
||||
*/
|
||||
private Object columnDefault;
|
||||
|
||||
/**
|
||||
* 数据库链接类型。该值为冗余字段,只是为了提升运行时效率。
|
||||
*/
|
||||
private int dblinkType;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.orangeforms.common.dbutil.provider;
|
||||
|
||||
/**
|
||||
* 数据源操作的提供者接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface DataSourceProvider {
|
||||
|
||||
/**
|
||||
* 返回数据库链接类型,具体值可参考DblinkType常量类。
|
||||
* @return 返回数据库链接类型
|
||||
*/
|
||||
int getDblinkType();
|
||||
|
||||
/**
|
||||
* 返回Jdbc的配置对象。
|
||||
*
|
||||
* @param configuration Jdbc 的配置数据,JSON格式。
|
||||
* @return Jdbc的配置对象。
|
||||
*/
|
||||
JdbcConfig getJdbcConfig(String configuration);
|
||||
|
||||
/**
|
||||
* 获取当前数据库表meta列表数据的SQL语句。
|
||||
*
|
||||
* @param searchString 表名的模糊匹配字符串。如果为空,则没有前缀规律。
|
||||
* @return 查询数据库表meta列表数据的SQL语句。
|
||||
*/
|
||||
String getTableMetaListSql(String searchString);
|
||||
|
||||
/**
|
||||
* 获取当前数据库表meta数据的SQL语句。
|
||||
*
|
||||
* @return 查询数据库表meta数据的SQL语句。
|
||||
*/
|
||||
String getTableMetaSql();
|
||||
|
||||
/**
|
||||
* 获取当前数据库指定表字段meta列表数据的SQL语句。
|
||||
*
|
||||
* @return 查询指定表字段meta列表数据的SQL语句。
|
||||
*/
|
||||
String getTableColumnMetaListSql();
|
||||
|
||||
/**
|
||||
* 获取测试数据库连接的查询SQL。
|
||||
*
|
||||
* @return 测试数据库连接的查询SQL
|
||||
*/
|
||||
default String getTestQuery() {
|
||||
return "SELECT 'x'";
|
||||
}
|
||||
|
||||
/**
|
||||
* 为当前的SQL参数,加上分页部分。
|
||||
*
|
||||
* @param sql SQL查询语句。
|
||||
* @param pageNum 页号,从1开始。
|
||||
* @param pageSize 每页数据量,如果为null,则取出后面所有数据。
|
||||
* @return 加上分页功能的SQL语句。
|
||||
*/
|
||||
String makePageSql(String sql, Integer pageNum, Integer pageSize);
|
||||
|
||||
/**
|
||||
* 将数据表字段类型转换为Java字段类型。
|
||||
*
|
||||
* @param columnType 数据表字段类型。
|
||||
* @param numericPrecision 数值精度。
|
||||
* @param numericScale 数值刻度。
|
||||
* @return 转换后的类型。
|
||||
*/
|
||||
String convertColumnTypeToJavaType(String columnType, Integer numericPrecision, Integer numericScale);
|
||||
|
||||
/**
|
||||
* Having从句中,统计字段参与过滤时,是否可以直接使用别名。
|
||||
*
|
||||
* @return 返回true,支持"HAVING sumOfColumn > 0",返回false,则为"HAVING sum(count) > 0"。
|
||||
*/
|
||||
default boolean havingClauseUsingAlias() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* SELECT的字段别名,是否需要加双引号,对于有些数据库,如果不加双引号,就会被数据库进行强制性的规则转义。
|
||||
*
|
||||
* @return 返回true,SELECT grade_id "gradeId",否则 SELECT grade_id gradeId
|
||||
*/
|
||||
default boolean aliasWithQuotes() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日期类型过滤条件语句。
|
||||
*
|
||||
* @param columnName 字段名。
|
||||
* @param operator 操作符。
|
||||
* @return 过滤从句。
|
||||
*/
|
||||
default String makeDateTimeFilterSql(String columnName, String operator) {
|
||||
StringBuilder s = new StringBuilder(128);
|
||||
if (columnName == null) {
|
||||
columnName = "";
|
||||
}
|
||||
return s.append(columnName).append(" ").append(operator).append(" ?").toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.orangeforms.common.dbutil.provider;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* JDBC配置。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class JdbcConfig {
|
||||
|
||||
/**
|
||||
* 驱动名。由子类提供。
|
||||
*/
|
||||
private String driver;
|
||||
/**
|
||||
* 连接池验证查询的语句。
|
||||
*/
|
||||
private String validationQuery = "SELECT 'x'";
|
||||
/**
|
||||
* Jdbc连接串,需要子类提供实现。
|
||||
*/
|
||||
private String jdbcConnectionString;
|
||||
/**
|
||||
* 主机名。
|
||||
*/
|
||||
private String host;
|
||||
/**
|
||||
* 端口号。
|
||||
*/
|
||||
private Integer port;
|
||||
/**
|
||||
* 用户名。
|
||||
*/
|
||||
private String username;
|
||||
/**
|
||||
* 密码。
|
||||
*/
|
||||
private String password;
|
||||
/**
|
||||
* 数据库名。
|
||||
*/
|
||||
private String database;
|
||||
/**
|
||||
* 模式名。
|
||||
*/
|
||||
private String schema;
|
||||
/**
|
||||
* 连接池初始大小。
|
||||
*/
|
||||
private int initialPoolSize = 5;
|
||||
/**
|
||||
* 连接池最小连接数。
|
||||
*/
|
||||
private int minPoolSize = 5;
|
||||
/**
|
||||
* 连接池最大连接数。
|
||||
*/
|
||||
private int maxPoolSize = 50;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.orangeforms.common.dbutil.provider;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* MySQL JDBC配置。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class MySqlConfig extends JdbcConfig {
|
||||
|
||||
/**
|
||||
* JDBC 驱动名。
|
||||
*/
|
||||
private String driver = "com.mysql.cj.jdbc.Driver";
|
||||
/**
|
||||
* 数据库JDBC连接串的扩展部分。
|
||||
*/
|
||||
private String extraParams = "?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai";
|
||||
|
||||
/**
|
||||
* 获取拼好后的JDBC连接串。
|
||||
*
|
||||
* @return 拼好后的JDBC连接串。
|
||||
*/
|
||||
@Override
|
||||
public String getJdbcConnectionString() {
|
||||
StringBuilder sb = new StringBuilder(256);
|
||||
sb.append("jdbc:mysql://")
|
||||
.append(getHost())
|
||||
.append(":")
|
||||
.append(getPort())
|
||||
.append("/")
|
||||
.append(getDatabase())
|
||||
.append(extraParams);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.orangeforms.common.dbutil.provider;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.orangeforms.common.core.constant.ObjectFieldType;
|
||||
import com.orangeforms.common.dbutil.constant.DblinkType;
|
||||
|
||||
/**
|
||||
* MySQL数据源的提供者实现类。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public class MySqlProvider implements DataSourceProvider {
|
||||
|
||||
@Override
|
||||
public int getDblinkType() {
|
||||
return DblinkType.MYSQL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcConfig getJdbcConfig(String configuration) {
|
||||
return JSON.parseObject(configuration, MySqlConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableMetaListSql(String searchString) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append(this.getTableMetaListSql());
|
||||
if (StrUtil.isNotBlank(searchString)) {
|
||||
sql.append(" AND table_name LIKE ?");
|
||||
}
|
||||
return sql.append(" ORDER BY table_name").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableMetaSql() {
|
||||
return this.getTableMetaListSql() + " AND table_name = ?";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableColumnMetaListSql() {
|
||||
return "SELECT "
|
||||
+ " column_name columnName, "
|
||||
+ " data_type columnType, "
|
||||
+ " column_type fullColumnType, "
|
||||
+ " column_comment columnComment, "
|
||||
+ " CASE WHEN column_key = 'PRI' THEN 1 ELSE 0 END AS primaryKey, "
|
||||
+ " is_nullable nullable, "
|
||||
+ " ordinal_position columnShowOrder, "
|
||||
+ " extra extra, "
|
||||
+ " CHARACTER_MAXIMUM_LENGTH stringPrecision, "
|
||||
+ " numeric_precision numericPrecision, "
|
||||
+ " COLUMN_DEFAULT columnDefault "
|
||||
+ "FROM "
|
||||
+ " information_schema.columns "
|
||||
+ "WHERE "
|
||||
+ " table_name = ?"
|
||||
+ " AND table_schema = (SELECT database()) "
|
||||
+ "ORDER BY ordinal_position";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String makePageSql(String sql, Integer pageNum, Integer pageSize) {
|
||||
if (pageSize == null) {
|
||||
pageSize = 10;
|
||||
}
|
||||
int offset = pageNum > 0 ? (pageNum - 1) * pageSize : 0;
|
||||
return sql + " LIMIT " + offset + "," + pageSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertColumnTypeToJavaType(String columnType, Integer numericPrecision, Integer numericScale) {
|
||||
if (StrUtil.equalsAnyIgnoreCase(columnType,
|
||||
"varchar", "char", "text", "longtext", "mediumtext", "tinytext", "enum", "json")) {
|
||||
return ObjectFieldType.STRING;
|
||||
}
|
||||
if (StrUtil.equalsAnyIgnoreCase(columnType, "int", "mediumint", "smallint", "tinyint")) {
|
||||
return ObjectFieldType.INTEGER;
|
||||
}
|
||||
if (StrUtil.equalsIgnoreCase(columnType, "bit")) {
|
||||
return ObjectFieldType.BOOLEAN;
|
||||
}
|
||||
if (StrUtil.equalsIgnoreCase(columnType, "bigint")) {
|
||||
return ObjectFieldType.LONG;
|
||||
}
|
||||
if (StrUtil.equalsIgnoreCase(columnType, "decimal")) {
|
||||
return ObjectFieldType.BIG_DECIMAL;
|
||||
}
|
||||
if (StrUtil.equalsAnyIgnoreCase(columnType, "float", "double")) {
|
||||
return ObjectFieldType.DOUBLE;
|
||||
}
|
||||
if (StrUtil.equalsAnyIgnoreCase(columnType, "date", "datetime", "timestamp", "time")) {
|
||||
return ObjectFieldType.DATE;
|
||||
}
|
||||
if (StrUtil.equalsAnyIgnoreCase(columnType, "longblob", "blob")) {
|
||||
return ObjectFieldType.BYTE_ARRAY;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getTableMetaListSql() {
|
||||
return "SELECT "
|
||||
+ " table_name tableName, "
|
||||
+ " table_comment tableComment, "
|
||||
+ " create_time createTime "
|
||||
+ "FROM "
|
||||
+ " information_schema.tables "
|
||||
+ "WHERE "
|
||||
+ " table_schema = DATABASE() ";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,838 @@
|
||||
package com.orangeforms.common.dbutil.util;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.pool.DruidDataSourceFactory;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.orangeforms.common.core.constant.FieldFilterType;
|
||||
import com.orangeforms.common.core.exception.InvalidDblinkTypeException;
|
||||
import com.orangeforms.common.core.exception.MyRuntimeException;
|
||||
import com.orangeforms.common.core.object.MyPageParam;
|
||||
import com.orangeforms.common.core.object.Tuple2;
|
||||
import com.orangeforms.common.core.util.MyDateUtil;
|
||||
import com.orangeforms.common.core.util.MyModelUtil;
|
||||
import com.orangeforms.common.dbutil.constant.DblinkType;
|
||||
import com.orangeforms.common.dbutil.provider.*;
|
||||
import com.orangeforms.common.dbutil.constant.CustomDateValueType;
|
||||
import com.orangeforms.common.dbutil.object.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.statement.select.PlainSelect;
|
||||
import net.sf.jsqlparser.statement.select.Select;
|
||||
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
|
||||
import net.sf.jsqlparser.statement.select.SelectItem;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* 动态加载的数据源工具类。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class DataSourceUtil {
|
||||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Map<Long, DataSource> datasourceMap = MapUtil.newHashMap();
|
||||
private static final Map<Integer, DataSourceProvider> PROVIDER_MAP = new HashMap<>(5);
|
||||
protected final Map<Long, DataSourceProvider> dblinkProviderMap = new ConcurrentHashMap<>(4);
|
||||
|
||||
private static final String SQL_SELECT = " SELECT ";
|
||||
private static final String SQL_SELECT_FROM = " SELECT * FROM (";
|
||||
private static final String SQL_AS_TMP = " ) tmp ";
|
||||
private static final String SQL_ORDER_BY = " ORDER BY ";
|
||||
private static final String SQL_AND = " AND ";
|
||||
private static final String SQL_WHERE = " WHERE ";
|
||||
private static final String LOG_PREPARING_FORMAT = "==> Preparing: {}";
|
||||
private static final String LOG_PARMS_FORMAT = "==> Parameters: {}";
|
||||
private static final String LOG_TOTAL_FORMAT = "<== Total: {}";
|
||||
|
||||
static {
|
||||
PROVIDER_MAP.put(DblinkType.MYSQL, new MySqlProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* 由子类实现,根据dblinkId获取数据库链接类型的方法。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @return 数据库链接类型。
|
||||
*/
|
||||
protected abstract int getDblinkTypeByDblinkId(Long dblinkId);
|
||||
|
||||
/**
|
||||
* 由子类实现,根据dblinkId获取数据库链接配置信息的方法。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @return 数据库链接配置信息。
|
||||
*/
|
||||
protected abstract String getDblinkConfigurationByDblinkId(Long dblinkId);
|
||||
|
||||
/**
|
||||
* 获取指定数据库类型的Provider实现类。
|
||||
*
|
||||
* @param dblinkType 数据库类型。
|
||||
* @return 指定数据库类型的Provider实现类。
|
||||
*/
|
||||
public DataSourceProvider getProvider(Integer dblinkType) {
|
||||
return PROVIDER_MAP.get(dblinkType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定数据库链接的Provider实现类。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @return 指定数据库类型的Provider实现类。
|
||||
*/
|
||||
public DataSourceProvider getProvider(Long dblinkId) {
|
||||
int dblinkType = this.getDblinkTypeByDblinkId(dblinkId);
|
||||
DataSourceProvider provider = PROVIDER_MAP.get(dblinkType);
|
||||
if (provider == null) {
|
||||
throw new InvalidDblinkTypeException(dblinkType);
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试数据库链接。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
*/
|
||||
public void testConnection(Long dblinkId) throws Exception {
|
||||
DataSourceProvider provider = this.getProvider(dblinkId);
|
||||
this.query(dblinkId, provider.getTestQuery());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过JDBC方式测试链接。
|
||||
*
|
||||
* @param databaseType 数据库类型。参考DblinkType常量值。
|
||||
* @param host 主机名。
|
||||
* @param port 端口号。
|
||||
* @param schemaName 模式名。
|
||||
* @param databaseName 数据库名。
|
||||
* @param username 用户名。
|
||||
* @param password 密码。
|
||||
*/
|
||||
public static void testConnection(
|
||||
int databaseType,
|
||||
String host,
|
||||
Integer port,
|
||||
String schemaName,
|
||||
String databaseName,
|
||||
String username,
|
||||
String password) {
|
||||
StringBuilder urlBuilder = new StringBuilder(256);
|
||||
String hostAndPort = host + ":" + port;
|
||||
urlBuilder.append("jdbc:mysql://")
|
||||
.append(hostAndPort)
|
||||
.append("/")
|
||||
.append(databaseName)
|
||||
.append("?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai");
|
||||
try {
|
||||
Connection conn = DriverManager.getConnection(urlBuilder.toString(), username, password);
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new MyRuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Dblink对象获取关联的数据源。如果不存在会创建该数据库连接池的数据源,
|
||||
* 并保存到Map中缓存,下次调用时可直接返回。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @return 关联的数据库连接池的数据源。
|
||||
*/
|
||||
public DataSource getDataSource(Long dblinkId) throws Exception {
|
||||
DataSource dataSource = datasourceMap.get(dblinkId);
|
||||
if (dataSource != null) {
|
||||
return dataSource;
|
||||
}
|
||||
int dblinkType = this.getDblinkTypeByDblinkId(dblinkId);
|
||||
DataSourceProvider provider = PROVIDER_MAP.get(dblinkType);
|
||||
if (provider == null) {
|
||||
throw new InvalidDblinkTypeException(dblinkType);
|
||||
}
|
||||
DruidDataSource druidDataSource = null;
|
||||
lock.lock();
|
||||
try {
|
||||
dataSource = datasourceMap.get(dblinkId);
|
||||
if (dataSource != null) {
|
||||
return dataSource;
|
||||
}
|
||||
JdbcConfig jdbcConfig = provider.getJdbcConfig(this.getDblinkConfigurationByDblinkId(dblinkId));
|
||||
Properties properties = new Properties();
|
||||
druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
|
||||
druidDataSource.setUrl(jdbcConfig.getJdbcConnectionString());
|
||||
druidDataSource.setDriverClassName(jdbcConfig.getDriver());
|
||||
druidDataSource.setValidationQuery(jdbcConfig.getValidationQuery());
|
||||
druidDataSource.setUsername(jdbcConfig.getUsername());
|
||||
druidDataSource.setPassword(jdbcConfig.getPassword());
|
||||
druidDataSource.setInitialSize(jdbcConfig.getInitialPoolSize());
|
||||
druidDataSource.setMinIdle(jdbcConfig.getMinPoolSize());
|
||||
druidDataSource.setMaxActive(jdbcConfig.getMaxPoolSize());
|
||||
druidDataSource.setConnectionErrorRetryAttempts(2);
|
||||
druidDataSource.setTimeBetweenConnectErrorMillis(500);
|
||||
druidDataSource.setBreakAfterAcquireFailure(true);
|
||||
druidDataSource.init();
|
||||
datasourceMap.put(dblinkId, druidDataSource);
|
||||
return druidDataSource;
|
||||
} catch (Exception e) {
|
||||
if (druidDataSource != null) {
|
||||
druidDataSource.close();
|
||||
}
|
||||
log.error("Failed to create DruidDatasource", e);
|
||||
throw e;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭指定数据库链接Id关联的数据源,同时从缓存中移除该数据源对象。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
*/
|
||||
public void removeDataSource(Long dblinkId) {
|
||||
lock.lock();
|
||||
try {
|
||||
DataSource dataSource = datasourceMap.get(dblinkId);
|
||||
if (dataSource == null) {
|
||||
return;
|
||||
}
|
||||
((DruidDataSource) dataSource).close();
|
||||
datasourceMap.remove(dblinkId);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定数据源的数据库连接对象。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @return 数据库连接对象。
|
||||
*/
|
||||
public Connection getConnection(Long dblinkId) throws Exception {
|
||||
DataSource dataSource = this.getDataSource(dblinkId);
|
||||
return dataSource == null ? null : dataSource.getConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定数据库链接的数据表列表。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @param searchString 表名的模糊匹配字符串。如果为空,则没有前缀规律。
|
||||
* @return 数据表对象列表。
|
||||
*/
|
||||
public List<SqlTable> getTableList(Long dblinkId, String searchString) {
|
||||
DataSourceProvider provider = this.getProvider(dblinkId);
|
||||
List<Object> paramList = null;
|
||||
if (StrUtil.isNotBlank(searchString)) {
|
||||
paramList = new LinkedList<>();
|
||||
paramList.add("%" + searchString + "%");
|
||||
}
|
||||
String querySql = provider.getTableMetaListSql(searchString);
|
||||
try {
|
||||
return this.query(dblinkId, querySql, paramList, SqlTable.class);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to call getTableList", e);
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定数据库链接的数据表对象。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @param tableName 表名称。
|
||||
* @return 数据表对象。
|
||||
*/
|
||||
public SqlTable getTable(Long dblinkId, String tableName) {
|
||||
DataSourceProvider provider = this.getProvider(dblinkId);
|
||||
String querySql = provider.getTableMetaSql();
|
||||
List<Object> paramList = new LinkedList<>();
|
||||
paramList.add(tableName);
|
||||
try {
|
||||
return this.queryOne(dblinkId, querySql, paramList, SqlTable.class);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to call getTable", e);
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定数据库链接下数据表的字段列表。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @param tableName 表名称。
|
||||
* @return 数据表的字段列表。
|
||||
*/
|
||||
public List<SqlTableColumn> getTableColumnList(Long dblinkId, String tableName) {
|
||||
try {
|
||||
DataSource dataSource = this.getDataSource(dblinkId);
|
||||
try (Connection conn = dataSource.getConnection()) {
|
||||
return this.getTableColumnList(dblinkId, conn, tableName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to call getTableColumnList", e);
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定数据库链接下数据表的字段列表。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @param conn 数据库连接对象。
|
||||
* @param tableName 表名称。
|
||||
* @return 数据表的字段列表。
|
||||
*/
|
||||
public List<SqlTableColumn> getTableColumnList(Long dblinkId, Connection conn, String tableName) {
|
||||
DataSourceProvider provider = this.getProvider(dblinkId);
|
||||
String querySql = provider.getTableColumnMetaListSql();
|
||||
List<Object> paramList = new LinkedList<>();
|
||||
paramList.add(tableName);
|
||||
try {
|
||||
List<Map<String, Object>> dataList = this.query(conn, querySql, paramList);
|
||||
return this.toTypedDataList(dataList, SqlTableColumn.class);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to call getTableColumnList", e);
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定表的数据。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @param tableName 表名。
|
||||
* @param datasetParam 数据集查询参数对象。
|
||||
* @return 表的数据结果。
|
||||
*/
|
||||
public SqlResultSet<Map<String, Object>> getTableDataList(
|
||||
Long dblinkId, String tableName, DatasetParam datasetParam) throws Exception {
|
||||
SqlTable table = this.getTable(dblinkId, tableName);
|
||||
if (table == null) {
|
||||
return null;
|
||||
}
|
||||
DataSourceProvider provider = this.getProvider(dblinkId);
|
||||
if (datasetParam == null) {
|
||||
datasetParam = new DatasetParam();
|
||||
}
|
||||
String sql = "SELECT * FROM " + tableName;
|
||||
if (CollUtil.isNotEmpty(datasetParam.getSelectColumnNameList())) {
|
||||
sql = SQL_SELECT + StrUtil.join(",", datasetParam.getSelectColumnNameList()) + " FROM " + tableName;
|
||||
}
|
||||
Tuple2<String, List<Object>> filterTuple = this.buildWhereClauseByFilters(dblinkId, datasetParam.getFilter());
|
||||
sql += filterTuple.getFirst();
|
||||
List<Object> paramList = filterTuple.getSecond();
|
||||
String sqlCount = null;
|
||||
MyPageParam pageParam = datasetParam.getPageParam();
|
||||
if (pageParam != null) {
|
||||
net.sf.jsqlparser.statement.Statement statement = CCJSqlParserUtil.parse(sql);
|
||||
Select select = (Select) statement;
|
||||
PlainSelect selectBody = (PlainSelect) select.getSelectBody();
|
||||
List<SelectItem> countSelectItems = new LinkedList<>();
|
||||
countSelectItems.add(new SelectExpressionItem(new Column("COUNT(1) AS CNT")));
|
||||
selectBody.setSelectItems(countSelectItems);
|
||||
sqlCount = select.toString();
|
||||
sql = provider.makePageSql(sql, pageParam.getPageNum(), pageParam.getPageSize());
|
||||
}
|
||||
return this.getDataListInternnally(dblinkId, provider, sqlCount, sql, datasetParam, paramList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定数据库链接上执行查询语句,并返回指定映射对象类型的单条数据对象。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @param query 待执行的SQL语句。
|
||||
* @param paramList 参数列表。
|
||||
* @param clazz 返回的映射对象Class类型。
|
||||
* @return 查询的结果对象。
|
||||
*/
|
||||
public <T> T queryOne(Long dblinkId, String query, List<Object> paramList, Class<T> clazz) throws Exception {
|
||||
List<T> dataList = this.query(dblinkId, query, paramList, clazz);
|
||||
return CollUtil.isEmpty(dataList) ? null : dataList.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定数据库链接上执行查询语句,并返回指定映射对象类型的数据列表。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @param query 待执行的SQL语句。
|
||||
* @param paramList 参数列表。
|
||||
* @param clazz 返回的映射对象Class类型。
|
||||
* @return 查询的结果集。
|
||||
*/
|
||||
public <T> List<T> query(Long dblinkId, String query, List<Object> paramList, Class<T> clazz) throws Exception {
|
||||
List<Map<String, Object>> dataList = this.query(dblinkId, query, paramList);
|
||||
return this.toTypedDataList(dataList, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定数据库链接上执行查询语句。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @param query 待执行的SQL语句。
|
||||
* @return 查询的结果集。
|
||||
*/
|
||||
public List<Map<String, Object>> query(Long dblinkId, String query) throws Exception {
|
||||
DataSource dataSource = this.getDataSource(dblinkId);
|
||||
try (Connection conn = dataSource.getConnection()) {
|
||||
return this.query(conn, query);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定数据库链接上执行查询语句。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @param query 待执行的SQL语句。
|
||||
* @param paramList 参数列表。
|
||||
* @return 查询的结果集。
|
||||
*/
|
||||
public List<Map<String, Object>> query(Long dblinkId, String query, List<Object> paramList) throws Exception {
|
||||
DataSource dataSource = this.getDataSource(dblinkId);
|
||||
try (Connection conn = dataSource.getConnection()) {
|
||||
return this.query(conn, query, paramList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算过滤从句和过滤参数。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @param filter 过滤参数列表。
|
||||
* @return 返回的Tuple对象的第一个参数是WHERE从句,第二个参数是过滤从句用到的参数列表。
|
||||
*/
|
||||
public Tuple2<String, List<Object>> buildWhereClauseByFilters(Long dblinkId, DatasetFilter filter) {
|
||||
filter = this.normalizeFilter(filter);
|
||||
if (CollUtil.isEmpty(filter)) {
|
||||
return new Tuple2<>("", null);
|
||||
}
|
||||
DataSourceProvider provider = this.getProvider(dblinkId);
|
||||
StringBuilder where = new StringBuilder();
|
||||
int i = 0;
|
||||
List<Object> paramList = new LinkedList<>();
|
||||
for (DatasetFilter.FilterInfo filterInfo : filter) {
|
||||
if (i++ == 0) {
|
||||
where.append(SQL_WHERE);
|
||||
} else {
|
||||
where.append(SQL_AND);
|
||||
}
|
||||
this.doBuildWhereClauseByFilter(filterInfo, provider, where, paramList);
|
||||
}
|
||||
return new Tuple2<>(where.toString(), paramList);
|
||||
}
|
||||
|
||||
private void doBuildWhereClauseByFilter(
|
||||
DatasetFilter.FilterInfo filterInfo,
|
||||
DataSourceProvider provider,
|
||||
StringBuilder where,
|
||||
List<Object> paramList) {
|
||||
where.append(filterInfo.getParamName());
|
||||
if (filterInfo.getFilterType().equals(FieldFilterType.EQUAL)) {
|
||||
this.doBuildWhereClauseByEqualFilter(filterInfo, provider, where, paramList);
|
||||
} else if (filterInfo.getFilterType().equals(FieldFilterType.NOT_EQUAL)) {
|
||||
where.append(" <> ?");
|
||||
paramList.add(filterInfo.getParamValue());
|
||||
} else if (filterInfo.getFilterType().equals(FieldFilterType.GE)) {
|
||||
this.doBuildWhereClauseByGeFilter(filterInfo, provider, where, paramList);
|
||||
} else if (filterInfo.getFilterType().equals(FieldFilterType.GT)) {
|
||||
this.doBuildWhereClauseByGtFilter(filterInfo, provider, where, paramList);
|
||||
} else if (filterInfo.getFilterType().equals(FieldFilterType.LE)) {
|
||||
this.doBuildWhereClauseByLeFilter(filterInfo, provider, where, paramList);
|
||||
} else if (filterInfo.getFilterType().equals(FieldFilterType.LT)) {
|
||||
this.doBuildWhereClauseByLtFilter(filterInfo, provider, where, paramList);
|
||||
} else if (filterInfo.getFilterType().equals(FieldFilterType.BETWEEN)) {
|
||||
this.doBuildWhereClauseByBetweenFilter(filterInfo, provider, where, paramList);
|
||||
} else if (filterInfo.getFilterType().equals(FieldFilterType.LIKE)) {
|
||||
where.append(" LIKE ?");
|
||||
paramList.add("%" + filterInfo.getParamValue() + "%");
|
||||
} else if (filterInfo.getFilterType().equals(FieldFilterType.IN)) {
|
||||
where.append(" IN (");
|
||||
where.append(StrUtil.repeatAndJoin("?", filterInfo.getParamValueList().size(), ","));
|
||||
where.append(")");
|
||||
paramList.addAll(filterInfo.getParamValueList());
|
||||
} else if (filterInfo.getFilterType().equals(FieldFilterType.NOT_IN)) {
|
||||
where.append(" NOT IN (");
|
||||
where.append(StrUtil.repeatAndJoin("?", filterInfo.getParamValueList().size(), ","));
|
||||
where.append(")");
|
||||
paramList.addAll(filterInfo.getParamValueList());
|
||||
} else if (filterInfo.getFilterType().equals(FieldFilterType.IS_NOT_NULL)) {
|
||||
where.append(" IS NOT NULL");
|
||||
} else if (filterInfo.getFilterType().equals(FieldFilterType.IS_NULL)) {
|
||||
where.append(" IS NULL");
|
||||
}
|
||||
}
|
||||
|
||||
private void doBuildWhereClauseByEqualFilter(
|
||||
DatasetFilter.FilterInfo filter,
|
||||
DataSourceProvider provider,
|
||||
StringBuilder where,
|
||||
List<Object> paramList) {
|
||||
if (BooleanUtil.isTrue(filter.getDateValueFilter())) {
|
||||
String beginDateTime = this.getBeginDateTime(filter.getParamValue().toString(), filter.getDateRange());
|
||||
String endDateTime = this.getEndDateTime(filter.getParamValue().toString(), filter.getDateRange());
|
||||
where.append(provider.makeDateTimeFilterSql(null, ">="));
|
||||
where.append(SQL_AND);
|
||||
where.append(provider.makeDateTimeFilterSql(filter.getParamName(), "<="));
|
||||
paramList.add(beginDateTime);
|
||||
paramList.add(endDateTime);
|
||||
} else {
|
||||
where.append(" = ?");
|
||||
paramList.add(filter.getParamValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void doBuildWhereClauseByGeFilter(
|
||||
DatasetFilter.FilterInfo filter,
|
||||
DataSourceProvider provider,
|
||||
StringBuilder where,
|
||||
List<Object> paramList) {
|
||||
if (BooleanUtil.isTrue(filter.getDateValueFilter())) {
|
||||
where.append(provider.makeDateTimeFilterSql(null, ">="));
|
||||
paramList.add(this.getBeginDateTime(filter.getParamValue().toString(), filter.getDateRange()));
|
||||
} else {
|
||||
paramList.add(filter.getParamValue());
|
||||
where.append(" >= ?");
|
||||
}
|
||||
}
|
||||
|
||||
private void doBuildWhereClauseByGtFilter(
|
||||
DatasetFilter.FilterInfo filter,
|
||||
DataSourceProvider provider,
|
||||
StringBuilder where,
|
||||
List<Object> paramList) {
|
||||
if (BooleanUtil.isTrue(filter.getDateValueFilter())) {
|
||||
where.append(provider.makeDateTimeFilterSql(null, ">"));
|
||||
paramList.add(this.getEndDateTime(filter.getParamValue().toString(), filter.getDateRange()));
|
||||
} else {
|
||||
where.append(" > ?");
|
||||
paramList.add(filter.getParamValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void doBuildWhereClauseByLeFilter(
|
||||
DatasetFilter.FilterInfo filter,
|
||||
DataSourceProvider provider,
|
||||
StringBuilder where,
|
||||
List<Object> paramList) {
|
||||
if (BooleanUtil.isTrue(filter.getDateValueFilter())) {
|
||||
where.append(provider.makeDateTimeFilterSql(null, "<="));
|
||||
paramList.add(this.getEndDateTime(filter.getParamValue().toString(), filter.getDateRange()));
|
||||
} else {
|
||||
where.append(" <= ?");
|
||||
paramList.add(filter.getParamValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void doBuildWhereClauseByLtFilter(
|
||||
DatasetFilter.FilterInfo filter,
|
||||
DataSourceProvider provider,
|
||||
StringBuilder where,
|
||||
List<Object> paramList) {
|
||||
if (BooleanUtil.isTrue(filter.getDateValueFilter())) {
|
||||
where.append(provider.makeDateTimeFilterSql(null, "<"));
|
||||
paramList.add(this.getBeginDateTime(filter.getParamValue().toString(), filter.getDateRange()));
|
||||
} else {
|
||||
where.append(" < ?");
|
||||
paramList.add(filter.getParamValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void doBuildWhereClauseByBetweenFilter(
|
||||
DatasetFilter.FilterInfo filter,
|
||||
DataSourceProvider provider,
|
||||
StringBuilder where,
|
||||
List<Object> paramList) {
|
||||
if (CollUtil.isEmpty(filter.getParamValueList())) {
|
||||
return;
|
||||
}
|
||||
if (BooleanUtil.isTrue(filter.getDateValueFilter())) {
|
||||
Object[] filterArray = filter.getParamValueList().toArray();
|
||||
where.append(provider.makeDateTimeFilterSql(null, ">="));
|
||||
paramList.add(this.getBeginDateTime(filterArray[0].toString(), filter.getDateRange()));
|
||||
where.append(SQL_AND);
|
||||
where.append(filter.getParamName());
|
||||
where.append(provider.makeDateTimeFilterSql(null, "<="));
|
||||
paramList.add(this.getEndDateTime(filterArray[1].toString(), filter.getDateRange()));
|
||||
} else {
|
||||
where.append(" BETWEEN ? AND ?");
|
||||
paramList.add(filter.getParamValueList());
|
||||
}
|
||||
}
|
||||
|
||||
private SqlResultSet<Map<String, Object>> getDataListInternnally(
|
||||
Long dblinkId,
|
||||
DataSourceProvider provider,
|
||||
String sqlCount,
|
||||
String sql,
|
||||
DatasetParam datasetParam,
|
||||
List<Object> paramList) throws Exception {
|
||||
Long totalCount = 0L;
|
||||
SqlResultSet<Map<String, Object>> resultSet = null;
|
||||
try (Connection connection = this.getConnection(dblinkId)) {
|
||||
boolean ignoreQueryData = false;
|
||||
if (sqlCount != null) {
|
||||
Map<String, Object> data = this.query(connection, sqlCount, paramList).get(0);
|
||||
String key = data.entrySet().iterator().next().getKey();
|
||||
totalCount = (Long) data.get(key);
|
||||
if (totalCount == 0L) {
|
||||
ignoreQueryData = true;
|
||||
}
|
||||
}
|
||||
if (!ignoreQueryData) {
|
||||
if (datasetParam.getOrderBy() != null) {
|
||||
sql += SQL_ORDER_BY + datasetParam.getOrderBy();
|
||||
}
|
||||
resultSet = this.queryWithMeta(connection, sql, paramList);
|
||||
resultSet.setTotalCount(totalCount);
|
||||
}
|
||||
}
|
||||
return resultSet == null ? new SqlResultSet<>() : resultSet;
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> query(Connection conn, String query) throws SQLException {
|
||||
try (Statement stat = conn.createStatement();
|
||||
ResultSet rs = stat.executeQuery(query)) {
|
||||
log.info(LOG_PREPARING_FORMAT, query);
|
||||
List<Map<String, Object>> resultList = this.fetchResult(rs);
|
||||
log.info(LOG_TOTAL_FORMAT, resultList.size());
|
||||
return resultList;
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> query(Connection conn, String query, List<Object> paramList) throws SQLException {
|
||||
if (CollUtil.isEmpty(paramList)) {
|
||||
return this.query(conn, query);
|
||||
}
|
||||
ResultSet rs = null;
|
||||
try (PreparedStatement stat = conn.prepareStatement(query)) {
|
||||
for (int i = 0; i < paramList.size(); i++) {
|
||||
stat.setObject(i + 1, paramList.get(i));
|
||||
}
|
||||
rs = stat.executeQuery();
|
||||
log.info(LOG_PREPARING_FORMAT, query);
|
||||
List<Map<String, Object>> resultList = this.fetchResult(rs);
|
||||
log.info(LOG_TOTAL_FORMAT, resultList.size());
|
||||
return resultList;
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw e;
|
||||
} finally {
|
||||
if (rs != null) {
|
||||
try {
|
||||
rs.close();
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to call rs.close", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SqlResultSet<Map<String, Object>> queryWithMeta(
|
||||
Connection connection, String query, List<Object> paramList) throws SQLException {
|
||||
if (CollUtil.isEmpty(paramList)) {
|
||||
try (Statement stat = connection.createStatement();
|
||||
ResultSet rs = stat.executeQuery(query)) {
|
||||
log.info(LOG_PREPARING_FORMAT, query);
|
||||
SqlResultSet<Map<String, Object>> resultSet = this.fetchResultWithMeta(rs);
|
||||
log.info(LOG_TOTAL_FORMAT, resultSet.getDataList() == null ? 0 : resultSet.getDataList().size());
|
||||
return resultSet;
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
ResultSet rs = null;
|
||||
try (PreparedStatement stat = connection.prepareStatement(query)) {
|
||||
for (int i = 0; i < paramList.size(); i++) {
|
||||
stat.setObject(i + 1, paramList.get(i));
|
||||
}
|
||||
rs = stat.executeQuery();
|
||||
log.info(LOG_PREPARING_FORMAT, query);
|
||||
SqlResultSet<Map<String, Object>> resultSet = this.fetchResultWithMeta(rs);
|
||||
log.info(LOG_TOTAL_FORMAT, resultSet.getDataList() == null ? 0 : resultSet.getDataList().size());
|
||||
return resultSet;
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw e;
|
||||
} finally {
|
||||
if (rs != null) {
|
||||
try {
|
||||
rs.close();
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to call rs.close", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> fetchResult(ResultSet rs) throws SQLException {
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
List<Map<String, Object>> resultList = new LinkedList<>();
|
||||
while (rs.next()) {
|
||||
JSONObject rowData = new JSONObject();
|
||||
for (int i = 0; i < columnCount; i++) {
|
||||
rowData.put(metaData.getColumnLabel(i + 1), rs.getObject(i + 1));
|
||||
}
|
||||
resultList.add(rowData);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
private SqlResultSet<Map<String, Object>> fetchResultWithMeta(ResultSet rs) throws SQLException {
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
List<SqlTableColumn> columnMetaList = new LinkedList<>();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
for (int i = 0; i < columnCount; i++) {
|
||||
SqlTableColumn tableColumn = new SqlTableColumn();
|
||||
String columnLabel = metaData.getColumnLabel(i + 1);
|
||||
tableColumn.setColumnName(columnLabel);
|
||||
tableColumn.setColumnType(metaData.getColumnTypeName(i + 1));
|
||||
columnMetaList.add(tableColumn);
|
||||
}
|
||||
List<Map<String, Object>> resultList = new LinkedList<>();
|
||||
while (rs.next()) {
|
||||
JSONObject rowData = new JSONObject();
|
||||
for (int i = 0; i < columnCount; i++) {
|
||||
rowData.put(metaData.getColumnLabel(i + 1), rs.getObject(i + 1));
|
||||
}
|
||||
resultList.add(rowData);
|
||||
}
|
||||
return new SqlResultSet<>(columnMetaList, resultList);
|
||||
}
|
||||
|
||||
private <T> List<T> toTypedDataList(List<Map<String, Object>> dataList, Class<T> clazz) {
|
||||
return MyModelUtil.mapToBeanList(dataList, clazz);
|
||||
}
|
||||
|
||||
private String getBeginDateTime(String dateValueType, String dateRange) {
|
||||
DateTime now = DateTime.now();
|
||||
switch (dateValueType) {
|
||||
case CustomDateValueType.CURRENT_DAY:
|
||||
return MyDateUtil.getBeginTimeOfDayWithShort(now);
|
||||
case CustomDateValueType.CURRENT_WEEK:
|
||||
return MyDateUtil.getBeginDateTimeOfWeek(now);
|
||||
case CustomDateValueType.CURRENT_MONTH:
|
||||
return MyDateUtil.getBeginDateTimeOfMonth(now);
|
||||
case CustomDateValueType.CURRENT_YEAR:
|
||||
return MyDateUtil.getBeginDateTimeOfYear(now);
|
||||
case CustomDateValueType.CURRENT_QUARTER:
|
||||
return MyDateUtil.getBeginDateTimeOfQuarter(now);
|
||||
case CustomDateValueType.LAST_DAY:
|
||||
return MyDateUtil.getBeginTimeOfDay(now.minusDays(1));
|
||||
case CustomDateValueType.LAST_WEEK:
|
||||
return MyDateUtil.getBeginDateTimeOfWeek(now.minusWeeks(1));
|
||||
case CustomDateValueType.LAST_MONTH:
|
||||
return MyDateUtil.getBeginDateTimeOfMonth(now.minusMonths(1));
|
||||
case CustomDateValueType.LAST_YEAR:
|
||||
return MyDateUtil.getBeginDateTimeOfYear(now.minusYears(1));
|
||||
case CustomDateValueType.LAST_QUARTER:
|
||||
return MyDateUtil.getBeginDateTimeOfQuarter(now.minusMonths(3));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// 执行到这里,基本就是自定义日期数据了
|
||||
if (StrUtil.isBlank(dateRange)) {
|
||||
return dateValueType;
|
||||
}
|
||||
DateTime dateValue = MyDateUtil.toDateTimeWithoutMs(dateValueType);
|
||||
switch (dateRange) {
|
||||
case "year":
|
||||
return MyDateUtil.getBeginDateTimeOfYear(dateValue);
|
||||
case "month":
|
||||
return MyDateUtil.getBeginDateTimeOfMonth(dateValue);
|
||||
case "week":
|
||||
return MyDateUtil.getBeginDateTimeOfWeek(dateValue);
|
||||
case "date":
|
||||
return MyDateUtil.getBeginTimeOfDayWithShort(dateValue);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return dateValueType;
|
||||
}
|
||||
|
||||
private String getEndDateTime(String dateValueType, String dateRange) {
|
||||
DateTime now = DateTime.now();
|
||||
switch (dateValueType) {
|
||||
case CustomDateValueType.CURRENT_DAY:
|
||||
return MyDateUtil.getEndTimeOfDayWithShort(now);
|
||||
case CustomDateValueType.CURRENT_WEEK:
|
||||
return MyDateUtil.getEndDateTimeOfWeek(now);
|
||||
case CustomDateValueType.CURRENT_MONTH:
|
||||
return MyDateUtil.getEndDateTimeOfMonth(now);
|
||||
case CustomDateValueType.CURRENT_YEAR:
|
||||
return MyDateUtil.getEndDateTimeOfYear(now);
|
||||
case CustomDateValueType.CURRENT_QUARTER:
|
||||
return MyDateUtil.getEndDateTimeOfQuarter(now);
|
||||
case CustomDateValueType.LAST_DAY:
|
||||
return MyDateUtil.getEndTimeOfDay(now.minusDays(1));
|
||||
case CustomDateValueType.LAST_WEEK:
|
||||
return MyDateUtil.getEndDateTimeOfWeek(now.minusWeeks(1));
|
||||
case CustomDateValueType.LAST_MONTH:
|
||||
return MyDateUtil.getEndDateTimeOfMonth(now.minusMonths(1));
|
||||
case CustomDateValueType.LAST_YEAR:
|
||||
return MyDateUtil.getEndDateTimeOfYear(now.minusYears(1));
|
||||
case CustomDateValueType.LAST_QUARTER:
|
||||
return MyDateUtil.getEndDateTimeOfQuarter(now.minusMonths(3));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// 执行到这里,基本就是自定义日期数据了
|
||||
if (StrUtil.isBlank(dateRange)) {
|
||||
return dateValueType;
|
||||
}
|
||||
DateTime dateValue = MyDateUtil.toDateTimeWithoutMs(dateValueType);
|
||||
switch (dateRange) {
|
||||
case "year":
|
||||
return MyDateUtil.getEndDateTimeOfYear(dateValue);
|
||||
case "month":
|
||||
return MyDateUtil.getEndDateTimeOfMonth(dateValue);
|
||||
case "week":
|
||||
return MyDateUtil.getEndDateTimeOfWeek(dateValue);
|
||||
case "date":
|
||||
return MyDateUtil.getEndTimeOfDayWithShort(dateValue);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return dateValueType;
|
||||
}
|
||||
|
||||
private DatasetFilter normalizeFilter(DatasetFilter filter) {
|
||||
if (CollUtil.isEmpty(filter)) {
|
||||
return filter;
|
||||
}
|
||||
DatasetFilter normalizedFilter = new DatasetFilter();
|
||||
for (DatasetFilter.FilterInfo filterInfo : filter) {
|
||||
if (filterInfo.getFilterType().equals(FieldFilterType.IS_NULL)
|
||||
|| filterInfo.getFilterType().equals(FieldFilterType.IS_NOT_NULL)
|
||||
|| filterInfo.getParamValue() != null
|
||||
|| filterInfo.getParamValueList() != null) {
|
||||
normalizedFilter.add(filterInfo);
|
||||
}
|
||||
}
|
||||
return normalizedFilter;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user