diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e9aed2ac..04b523e3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ * 【core 】 扩充Console功能,支持可变参数(issue#1077@Github) * 【crypto 】 增加ECKeyUtil(issue#I1UOF5@Gitee) * 【core 】 增加TransXXX(issue#I1TU1Y@Gitee) +* 【core 】 增加Generator +* 【db 】 Column增加是否主键、保留位数等字段 ### Bug修复 * 【core 】 修复Dict.of错误(issue#I1UUO5@Gitee) diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java index e61a062d2..6b3db398a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java @@ -1005,20 +1005,14 @@ public class FileUtil extends PathUtil { } /** - * 修改文件或目录的文件名,不变更路径,只是简单修改文件名
- * 重命名有两种模式:
- * 1、isRetainExt为true时,保留原扩展名: + * 修改文件或目录的文件名,不变更路径,只是简单修改文件名,不保留扩展名。
* *
-	 * FileUtil.rename(file, "aaa", true) xx/xx.png =》xx/aaa.png
-	 * 
- * - *
-	 * FileUtil.rename(file, "aaa.jpg", false) xx/xx.png =》xx/aaa.jpg
+	 * FileUtil.rename(file, "aaa.png", true) xx/xx.png =》xx/aaa.png
 	 * 
* * @param file 被修改的文件 - * @param newName 新的文件名,包括扩展名 + * @param newName 新的文件名,如需扩展名,需自行在此参数加上,原文件名的扩展名不会被保留 * @param isOverride 是否覆盖目标文件 * @return 目标文件 * @since 5.3.6 @@ -1035,6 +1029,7 @@ public class FileUtil extends PathUtil { *
 	 * FileUtil.rename(file, "aaa", true) xx/xx.png =》xx/aaa.png
 	 * 
+ * *

* 2、isRetainExt为false时,不保留原扩展名,需要在newName中 * diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/generator/Generator.java b/hutool-core/src/main/java/cn/hutool/core/lang/generator/Generator.java new file mode 100644 index 000000000..ce05812de --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/generator/Generator.java @@ -0,0 +1,18 @@ +package cn.hutool.core.lang.generator; + +/** + * 生成器泛型接口
+ * 通过实现此接口可以自定义生成对象的策略 + * + * @param 生成对象类型 + * @since 5.4.3 + */ +public interface Generator { + + /** + * 生成新的对象 + * + * @return 新的对象 + */ + T next(); +} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/generator/ObjectGenerator.java b/hutool-core/src/main/java/cn/hutool/core/lang/generator/ObjectGenerator.java new file mode 100644 index 000000000..4af05e354 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/generator/ObjectGenerator.java @@ -0,0 +1,28 @@ +package cn.hutool.core.lang.generator; + +import cn.hutool.core.util.ReflectUtil; + +/** + * 对象生成器,通过指定对象的Class类型,调用next方法时生成新的对象。 + * + * @param 对象类型 + * @author looly + * @since 5.4.3 + */ +public class ObjectGenerator implements Generator { + + private final Class clazz; + + /** + * 构造 + * @param clazz 对象类型 + */ + public ObjectGenerator(Class clazz) { + this.clazz = clazz; + } + + @Override + public T next() { + return ReflectUtil.newInstanceIfPossible(this.clazz); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/generator/ObjectIdGenerator.java b/hutool-core/src/main/java/cn/hutool/core/lang/generator/ObjectIdGenerator.java new file mode 100644 index 000000000..27c6c9b5f --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/generator/ObjectIdGenerator.java @@ -0,0 +1,16 @@ +package cn.hutool.core.lang.generator; + +import cn.hutool.core.lang.ObjectId; + +/** + * ObjectId生成器 + * + * @author looly + * @since 5.4.3 + */ +public class ObjectIdGenerator implements Generator { + @Override + public String next() { + return ObjectId.next(); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/generator/SnowflakeGenerator.java b/hutool-core/src/main/java/cn/hutool/core/lang/generator/SnowflakeGenerator.java new file mode 100644 index 000000000..b4260fa58 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/generator/SnowflakeGenerator.java @@ -0,0 +1,38 @@ +package cn.hutool.core.lang.generator; + +import cn.hutool.core.lang.Snowflake; + +/** + * Snowflake生成器
+ * 注意,默认此生成器必须单例使用,否则会有重复
+ * 默认构造的终端ID和数据中心ID都为0,不适用于分布式环境。 + * + * @author looly + * @since 5.4.3 + */ +public class SnowflakeGenerator implements Generator { + + private final Snowflake snowflake; + + /** + * 构造 + */ + public SnowflakeGenerator() { + this(0, 0); + } + + /** + * 构造 + * + * @param workerId 终端ID + * @param dataCenterId 数据中心ID + */ + public SnowflakeGenerator(long workerId, long dataCenterId) { + snowflake = new Snowflake(workerId, dataCenterId); + } + + @Override + public Long next() { + return this.snowflake.nextId(); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/generator/UUIDGenerator.java b/hutool-core/src/main/java/cn/hutool/core/lang/generator/UUIDGenerator.java new file mode 100644 index 000000000..301b5c0a0 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/generator/UUIDGenerator.java @@ -0,0 +1,16 @@ +package cn.hutool.core.lang.generator; + +import cn.hutool.core.util.IdUtil; + +/** + * UUID生成器 + * + * @author looly + * @since 5.4.3 + */ +public class UUIDGenerator implements Generator { + @Override + public String next() { + return IdUtil.fastUUID(); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/generator/package-info.java b/hutool-core/src/main/java/cn/hutool/core/lang/generator/package-info.java new file mode 100644 index 000000000..59c06ffb5 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/generator/package-info.java @@ -0,0 +1,7 @@ +/** + * 提供生成器接口及相关封装 + * + * @author looly + * + */ +package cn.hutool.core.lang.generator; \ No newline at end of file diff --git a/hutool-core/src/test/java/cn/hutool/core/date/BetweenFormaterTest.java b/hutool-core/src/test/java/cn/hutool/core/date/BetweenFormaterTest.java index 9b43ec3fe..5374d596f 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/BetweenFormaterTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/BetweenFormaterTest.java @@ -1,10 +1,9 @@ package cn.hutool.core.date; +import cn.hutool.core.date.BetweenFormater.Level; import org.junit.Assert; import org.junit.Test; -import cn.hutool.core.date.BetweenFormater.Level; - public class BetweenFormaterTest { @Test diff --git a/hutool-db/src/main/java/cn/hutool/db/dialect/impl/AnsiSqlDialect.java b/hutool-db/src/main/java/cn/hutool/db/dialect/impl/AnsiSqlDialect.java index 1cfb65f25..055120621 100644 --- a/hutool-db/src/main/java/cn/hutool/db/dialect/impl/AnsiSqlDialect.java +++ b/hutool-db/src/main/java/cn/hutool/db/dialect/impl/AnsiSqlDialect.java @@ -1,6 +1,6 @@ package cn.hutool.db.dialect.impl; -import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; @@ -10,7 +10,11 @@ import cn.hutool.db.Page; import cn.hutool.db.StatementUtil; import cn.hutool.db.dialect.Dialect; import cn.hutool.db.dialect.DialectName; -import cn.hutool.db.sql.*; +import cn.hutool.db.sql.Condition; +import cn.hutool.db.sql.LogicalOperator; +import cn.hutool.db.sql.Query; +import cn.hutool.db.sql.SqlBuilder; +import cn.hutool.db.sql.Wrapper; import java.sql.Connection; import java.sql.PreparedStatement; @@ -129,7 +133,7 @@ public class AnsiSqlDialect implements Dialect { @Override public PreparedStatement psForCount(Connection conn, Query query) throws SQLException { - query.setFields(CollectionUtil.newArrayList("count(1)")); + query.setFields(ListUtil.toList("count(1)")); return psForFind(conn, query); } diff --git a/hutool-db/src/main/java/cn/hutool/db/meta/Column.java b/hutool-db/src/main/java/cn/hutool/db/meta/Column.java index eb4285a04..a7edbb18c 100644 --- a/hutool-db/src/main/java/cn/hutool/db/meta/Column.java +++ b/hutool-db/src/main/java/cn/hutool/db/meta/Column.java @@ -1,51 +1,88 @@ package cn.hutool.db.meta; +import cn.hutool.core.util.BooleanUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.db.DbRuntimeException; + import java.io.Serializable; import java.sql.ResultSet; import java.sql.SQLException; -import cn.hutool.core.util.StrUtil; -import cn.hutool.db.DbRuntimeException; - /** * 数据库表的列信息 - * - * @author loolly * + * @author loolly */ public class Column implements Serializable, Cloneable { private static final long serialVersionUID = 577527740359719367L; // ----------------------------------------------------- Fields start - /** 表名 */ + /** + * 表名 + */ private String tableName; - /** 列名 */ + /** + * 列名 + */ private String name; - /** 类型,对应java.sql.Types中的类型 */ + /** + * 类型,对应java.sql.Types中的类型 + */ private int type; - /** 类型名称 */ + /** + * 类型名称 + */ private String typeName; - /** 大小或数据长度 */ + /** + * 大小或数据长度 + */ private int size; - /** 是否为可空 */ + private Integer digit; + /** + * 是否为可空 + */ private boolean isNullable; - /** 注释 */ + /** + * 注释 + */ private String comment; + /** + * 是否自增 + */ + private boolean autoIncrement; + /** + * 是否为主键 + */ + private boolean isPk; // ----------------------------------------------------- Fields end /** * 创建列对象 - * - * @param tableName 表名 + * + * @param tableName 表名 * @param columnMetaRs 列元信息的ResultSet * @return 列对象 + * @deprecated 请使用 {@link #create(Table, ResultSet)} */ public static Column create(String tableName, ResultSet columnMetaRs) { return new Column(tableName, columnMetaRs); } + /** + * 创建列对象 + * + * @param columnMetaRs 列元信息的ResultSet + * @param table 表信息 + * @return 列对象 + * @since 5.4.3 + */ + public static Column create(Table table, ResultSet columnMetaRs) { + return new Column(table, columnMetaRs); + } + // ----------------------------------------------------- Constructor start + /** * 构造 */ @@ -54,10 +91,12 @@ public class Column implements Serializable, Cloneable { /** * 构造 - * - * @param tableName 表名 + * + * @param tableName 表名 * @param columnMetaRs Meta信息的ResultSet + * @deprecated 请使用 {@link #Column(Table, ResultSet)} */ + @Deprecated public Column(String tableName, ResultSet columnMetaRs) { try { init(tableName, columnMetaRs); @@ -65,30 +104,78 @@ public class Column implements Serializable, Cloneable { throw new DbRuntimeException(StrUtil.format("Get table [{}] meta info error!", tableName)); } } + + /** + * 构造 + * + * @param table 表信息 + * @param columnMetaRs Meta信息的ResultSet + * @since 5.4.3 + */ + public Column(Table table, ResultSet columnMetaRs) { + try { + init(table, columnMetaRs); + } catch (SQLException e) { + throw new DbRuntimeException(StrUtil.format("Get table [{}] meta info error!", tableName)); + } + } // ----------------------------------------------------- Constructor end /** * 初始化 - * - * @param tableName 表名 + * + * @param tableName 表名 + * @param columnMetaRs 列的meta ResultSet + * @throws SQLException SQL执行异常 + * @deprecated 请使用 {@link #init(Table, ResultSet)} + */ + @Deprecated + public void init(String tableName, ResultSet columnMetaRs) throws SQLException { + init(Table.create(tableName), columnMetaRs); + } + + /** + * 初始化 + * + * @param table 表信息 * @param columnMetaRs 列的meta ResultSet * @throws SQLException SQL执行异常 */ - public void init(String tableName, ResultSet columnMetaRs) throws SQLException { - this.tableName = tableName; + public void init(Table table, ResultSet columnMetaRs) throws SQLException { + this.tableName = table.getTableName(); this.name = columnMetaRs.getString("COLUMN_NAME"); + this.isPk = table.isPk(this.name); + this.type = columnMetaRs.getInt("DATA_TYPE"); this.typeName = columnMetaRs.getString("TYPE_NAME"); this.size = columnMetaRs.getInt("COLUMN_SIZE"); this.isNullable = columnMetaRs.getBoolean("NULLABLE"); this.comment = columnMetaRs.getString("REMARKS"); + + // 保留小数位数 + try { + this.digit = columnMetaRs.getInt("DECIMAL_DIGITS"); + } catch (SQLException ignore) { + //某些驱动可能不支持,跳过 + } + + // 是否自增 + try { + String auto = columnMetaRs.getString("IS_AUTOINCREMENT"); + if (BooleanUtil.toBoolean(auto)) { + this.autoIncrement = true; + } + } catch (SQLException ignore) { + //某些驱动可能不支持,跳过 + } } // ----------------------------------------------------- Getters and Setters start + /** * 获取表名 - * + * * @return 表名 */ public String getTableName() { @@ -97,7 +184,7 @@ public class Column implements Serializable, Cloneable { /** * 设置表名 - * + * * @param tableName 表名 * @return this */ @@ -108,7 +195,7 @@ public class Column implements Serializable, Cloneable { /** * 获取列名 - * + * * @return 列名 */ public String getName() { @@ -117,7 +204,7 @@ public class Column implements Serializable, Cloneable { /** * 设置列名 - * + * * @param name 列名 * @return this */ @@ -128,17 +215,17 @@ public class Column implements Serializable, Cloneable { /** * 获取字段类型的枚举 - * + * * @return 阻断类型枚举 * @since 4.5.8 */ public JdbcType getTypeEnum() { return JdbcType.valueOf(this.type); } - + /** * 获取类型,对应{@link java.sql.Types}中的类型 - * + * * @return 类型 */ public int getType() { @@ -147,7 +234,7 @@ public class Column implements Serializable, Cloneable { /** * 设置类型,对应java.sql.Types中的类型 - * + * * @param type 类型 * @return this */ @@ -155,19 +242,19 @@ public class Column implements Serializable, Cloneable { this.type = type; return this; } - + /** * 获取类型名称 - * + * * @return 类型名称 */ public String getTypeName() { return typeName; } - + /** * 设置类型名称 - * + * * @param typeName 类型名称 * @return this */ @@ -178,7 +265,7 @@ public class Column implements Serializable, Cloneable { /** * 获取大小或数据长度 - * + * * @return 大小或数据长度 */ public int getSize() { @@ -187,7 +274,7 @@ public class Column implements Serializable, Cloneable { /** * 设置大小或数据长度 - * + * * @param size 大小或数据长度 * @return this */ @@ -196,9 +283,29 @@ public class Column implements Serializable, Cloneable { return this; } + /** + * 获取小数位数 + * + * @return 大小或数据长度 + */ + public int getDigit() { + return digit; + } + + /** + * 设置小数位数 + * + * @param digit 小数位数 + * @return this + */ + public Column setDigit(int digit) { + this.digit = digit; + return this; + } + /** * 是否为可空 - * + * * @return 是否为可空 */ public boolean isNullable() { @@ -207,7 +314,7 @@ public class Column implements Serializable, Cloneable { /** * 设置是否为可空 - * + * * @param isNullable 是否为可空 * @return this */ @@ -218,7 +325,7 @@ public class Column implements Serializable, Cloneable { /** * 获取注释 - * + * * @return 注释 */ public String getComment() { @@ -227,7 +334,7 @@ public class Column implements Serializable, Cloneable { /** * 设置注释 - * + * * @param comment 注释 * @return this */ @@ -235,6 +342,50 @@ public class Column implements Serializable, Cloneable { this.comment = comment; return this; } + + /** + * 是否自增 + * + * @return 是否自增 + * @since 5.4.3 + */ + public boolean isAutoIncrement() { + return autoIncrement; + } + + /** + * 设置是否自增 + * + * @param autoIncrement 是否自增 + * @return this + * @since 5.4.3 + */ + public Column setAutoIncrement(boolean autoIncrement) { + this.autoIncrement = autoIncrement; + return this; + } + + /** + * 是否主键 + * + * @return 是否主键 + * @since 5.4.3 + */ + public boolean isPk() { + return isPk; + } + + /** + * 设置是否主键 + * + * @param isPk 是否主键 + * @return this + * @since 5.4.3 + */ + public Column setPk(boolean isPk) { + this.isPk = isPk; + return this; + } // ----------------------------------------------------- Getters and Setters end @Override diff --git a/hutool-db/src/main/java/cn/hutool/db/meta/MetaUtil.java b/hutool-db/src/main/java/cn/hutool/db/meta/MetaUtil.java index 414caac5d..839692761 100644 --- a/hutool-db/src/main/java/cn/hutool/db/meta/MetaUtil.java +++ b/hutool-db/src/main/java/cn/hutool/db/meta/MetaUtil.java @@ -186,8 +186,10 @@ public class MetaUtil { conn = ds.getConnection(); // catalog和schema获取失败默认使用null代替 - String catalog = getCataLog(conn); - String schema = getSchema(conn); + final String catalog = getCataLog(conn); + table.setCatalog(catalog); + final String schema = getSchema(conn); + table.setSchema(schema); final DatabaseMetaData metaData = conn.getMetaData(); @@ -213,7 +215,7 @@ public class MetaUtil { try (ResultSet rs = metaData.getColumns(catalog, schema, tableName, null)) { if (null != rs) { while (rs.next()) { - table.setColumn(Column.create(tableName, rs)); + table.setColumn(Column.create(table, rs)); } } } diff --git a/hutool-db/src/main/java/cn/hutool/db/meta/Table.java b/hutool-db/src/main/java/cn/hutool/db/meta/Table.java index 62a12f5e0..86a4975f7 100644 --- a/hutool-db/src/main/java/cn/hutool/db/meta/Table.java +++ b/hutool-db/src/main/java/cn/hutool/db/meta/Table.java @@ -9,18 +9,31 @@ import java.util.Set; /** * 数据库表信息 - * - * @author loolly * + * @author loolly */ public class Table implements Serializable, Cloneable { private static final long serialVersionUID = -810699625961392983L; - /** 表名 */ + /** + * table所在的schema + */ + private String schema; + /** + * tables所在的catalog + */ + private String catalog; + /** + * 表名 + */ private String tableName; - /** 注释 */ + /** + * 注释 + */ private String comment; - /** 主键字段名列表 */ + /** + * 主键字段名列表 + */ private Set pkNames = new LinkedHashSet<>(); private final Map columns = new LinkedHashMap<>(); @@ -29,9 +42,10 @@ public class Table implements Serializable, Cloneable { } // ----------------------------------------------------- Constructor start + /** * 构造 - * + * * @param tableName 表名 */ public Table(String tableName) { @@ -40,9 +54,54 @@ public class Table implements Serializable, Cloneable { // ----------------------------------------------------- Constructor end // ----------------------------------------------------- Getters and Setters start + + /** + * 获取 schema + * + * @return schema + * @since 5.4.3 + */ + public String getSchema() { + return schema; + } + + /** + * 设置schema + * + * @param schema schema + * @return this + * @since 5.4.3 + */ + public Table setSchema(String schema) { + this.schema = schema; + return this; + } + + /** + * 获取catalog + * + * @return catalog + * @since 5.4.3 + */ + public String getCatalog() { + return catalog; + } + + /** + * 设置catalog + * + * @param catalog catalog + * @return this + * @since 5.4.3 + */ + public Table setCatalog(String catalog) { + this.catalog = catalog; + return this; + } + /** * 获取表名 - * + * * @return 表名 */ public String getTableName() { @@ -51,7 +110,7 @@ public class Table implements Serializable, Cloneable { /** * 设置表名 - * + * * @param tableName 表名 */ public void setTableName(String tableName) { @@ -60,7 +119,7 @@ public class Table implements Serializable, Cloneable { /** * 获取注释 - * + * * @return 注释 */ public String getComment() { @@ -69,7 +128,7 @@ public class Table implements Serializable, Cloneable { /** * 设置注释 - * + * * @param comment 注释 * @return this */ @@ -80,16 +139,27 @@ public class Table implements Serializable, Cloneable { /** * 获取主键列表 - * + * * @return 主键列表 */ public Set getPkNames() { return pkNames; } + /** + * 给定列名是否为主键 + * + * @param columnName 列名 + * @return 是否为主键 + * @since 5.4.3 + */ + public boolean isPk(String columnName){ + return getPkNames().contains(columnName); + } + /** * 设置主键列表 - * + * * @param pkNames 主键列表 */ public void setPkNames(Set pkNames) { @@ -99,7 +169,7 @@ public class Table implements Serializable, Cloneable { /** * 设置列对象 - * + * * @param column 列对象 * @return 自己 */ @@ -110,7 +180,7 @@ public class Table implements Serializable, Cloneable { /** * 获取某列信息 - * + * * @param name 列名 * @return 列对象 * @since 4.2.2 @@ -121,7 +191,7 @@ public class Table implements Serializable, Cloneable { /** * 获取所有字段元信息 - * + * * @return 字段元信息集合 * @since 4.5.8 */ @@ -131,7 +201,7 @@ public class Table implements Serializable, Cloneable { /** * 添加主键 - * + * * @param pkColumnName 主键的列名 * @return 自己 */