diff --git a/CHANGELOG.md b/CHANGELOG.md index a7917c07f..9275986f4 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.8.0.M5 (2022-04-28) +# 5.8.0.M5 (2022-05-05) ### ❌不兼容特性 * 【extra 】 升级jakarta.validation-api到3.x,包名变更导致不能向下兼容 @@ -12,6 +12,9 @@ ### 🐣新特性 * 【core 】 Singleton增加部分方法(pr#609@Gitee) * 【core 】 BeanUtil增加beanToMap重载(pr#2292@Github) +* 【core 】 Assert增加对应的equals及notEquals方法(pr#612@Gitee) +* 【core 】 Assert增加对应的equals及notEquals方法(pr#612@Gitee) +* 【core 】 DigestUtil增加sha512方法(issue#2298@Github) ### 🐞Bug修复 * 【db 】 修复RedisDS无法设置maxWaitMillis问题(issue#I54TZ9@Gitee) diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Assert.java b/hutool-core/src/main/java/cn/hutool/core/lang/Assert.java index a33b2a4ed..ec0b69b27 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/Assert.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/Assert.java @@ -3,6 +3,7 @@ package cn.hutool.core.lang; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import java.util.Map; @@ -1003,6 +1004,99 @@ public class Assert { return value; } + /** + * 断言两个对象是否不相等,如果两个对象相等 抛出IllegalArgumentException 异常 + *
+	 *   Assert.notEquals(obj1,obj2);
+	 * 
+ * + * @param obj1 对象1 + * @param obj2 对象2 + * @throws IllegalArgumentException obj1 must be not equals obj2 + */ + public static void notEquals(Object obj1, Object obj2) { + notEquals(obj1, obj2, "({}) must be not equals ({})", obj1, obj2); + } + + /** + * 断言两个对象是否不相等,如果两个对象相等 抛出IllegalArgumentException 异常 + *
+	 *   Assert.notEquals(obj1,obj2,"obj1 must be not equals obj2");
+	 * 
+ * + * @param obj1 对象1 + * @param obj2 对象2 + * @param errorMsgTemplate 异常信息模板,类似于"aa{}bb{}cc" + * @param params 异常信息参数,用于替换"{}"占位符 + * @throws IllegalArgumentException obj1 must be not equals obj2 + */ + public static void notEquals(Object obj1, Object obj2, String errorMsgTemplate, Object... params) throws IllegalArgumentException { + notEquals(obj1, obj2, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params))); + } + + /** + * 断言两个对象是否不相等,如果两个对象相等,抛出指定类型异常,并使用指定的函数获取错误信息返回 + * + * @param obj1 对象1 + * @param obj2 对象2 + * @param errorSupplier 错误抛出异常附带的消息生产接口 + * @param 异常类型 + * @throws X obj1 must be not equals obj2 + */ + public static void notEquals(Object obj1, Object obj2, Supplier errorSupplier) throws X { + if (ObjectUtil.equals(obj1, obj2)) { + throw errorSupplier.get(); + } + } + // ----------------------------------------------------------------------------------------------------------- Check not equals + + /** + * 断言两个对象是否相等,如果两个对象不相等 抛出IllegalArgumentException 异常 + *
+	 *   Assert.isEquals(obj1,obj2);
+	 * 
+ * + * @param obj1 对象1 + * @param obj2 对象2 + * @throws IllegalArgumentException obj1 must be equals obj2 + */ + public static void equals(Object obj1, Object obj2) { + equals(obj1, obj2, "({}) must be equals ({})", obj1, obj2); + } + + /** + * 断言两个对象是否相等,如果两个对象不相等 抛出IllegalArgumentException 异常 + *
+	 *   Assert.isEquals(obj1,obj2,"obj1 must be equals obj2");
+	 * 
+ * + * @param obj1 对象1 + * @param obj2 对象2 + * @param errorMsgTemplate 异常信息模板,类似于"aa{}bb{}cc" + * @param params 异常信息参数,用于替换"{}"占位符 + * @throws IllegalArgumentException obj1 must be equals obj2 + */ + public static void equals(Object obj1, Object obj2, String errorMsgTemplate, Object... params) throws IllegalArgumentException { + equals(obj1, obj2, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params))); + } + + /** + * 断言两个对象是否相等,如果两个对象不相等,抛出指定类型异常,并使用指定的函数获取错误信息返回 + * + * @param obj1 对象1 + * @param obj2 对象2 + * @param errorSupplier 错误抛出异常附带的消息生产接口 + * @param 异常类型 + * @throws X obj1 must be equals obj2 + */ + public static void equals(Object obj1, Object obj2, Supplier errorSupplier) throws X { + if (ObjectUtil.notEqual(obj1, obj2)) { + throw errorSupplier.get(); + } + } + + // ----------------------------------------------------------------------------------------------------------- Check is equals + // -------------------------------------------------------------------------------------------------------------------------------------------- Private method start /** diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java b/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java index 139741a3e..eddc1476f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java @@ -41,7 +41,7 @@ import java.util.stream.Stream; /** * 复制jdk16中的Optional,以及自己进行了一点调整和新增,比jdk8中的Optional多了几个实用的函数
- * 详细见:https://gitee.com/dromara/hutool/pulls/426 + * 详细见:https://gitee.com/dromara/hutool/pulls/426 * * @param 包裹里元素的类型 * @author VampireAchao @@ -60,8 +60,7 @@ public class Opt { * @return Opt */ public static Opt empty() { - @SuppressWarnings("unchecked") - Opt t = (Opt) EMPTY; + @SuppressWarnings("unchecked") final Opt t = (Opt) EMPTY; return t; } @@ -322,7 +321,7 @@ public class Opt { return empty(); } else { @SuppressWarnings("unchecked") - Opt r = (Opt) mapper.apply(value); + final Opt r = (Opt) mapper.apply(value); return Objects.requireNonNull(r); } } @@ -400,8 +399,7 @@ public class Opt { if (isPresent()) { return this; } else { - @SuppressWarnings("unchecked") - Opt r = (Opt) supplier.get(); + @SuppressWarnings("unchecked") final Opt r = (Opt) supplier.get(); return Objects.requireNonNull(r); } } @@ -544,7 +542,7 @@ public class Opt { return false; } - Opt other = (Opt) obj; + final Opt other = (Opt) obj; return Objects.equals(value, other.value); } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ObjectUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ObjectUtil.java index 8fe082b43..00c3454de 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ObjectUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ObjectUtil.java @@ -104,7 +104,7 @@ public class ObjectUtil { int count; if (obj instanceof Iterator) { - Iterator iter = (Iterator) obj; + final Iterator iter = (Iterator) obj; count = 0; while (iter.hasNext()) { count++; @@ -113,7 +113,7 @@ public class ObjectUtil { return count; } if (obj instanceof Enumeration) { - Enumeration enumeration = (Enumeration) obj; + final Enumeration enumeration = (Enumeration) obj; count = 0; while (enumeration.hasMoreElements()) { count++; @@ -161,9 +161,9 @@ public class ObjectUtil { } if (obj instanceof Iterator) { - Iterator iter = (Iterator) obj; + final Iterator iter = (Iterator) obj; while (iter.hasNext()) { - Object o = iter.next(); + final Object o = iter.next(); if (equal(o, element)) { return true; } @@ -171,9 +171,9 @@ public class ObjectUtil { return false; } if (obj instanceof Enumeration) { - Enumeration enumeration = (Enumeration) obj; + final Enumeration enumeration = (Enumeration) obj; while (enumeration.hasMoreElements()) { - Object o = enumeration.nextElement(); + final Object o = enumeration.nextElement(); if (equal(o, element)) { return true; } @@ -181,9 +181,9 @@ public class ObjectUtil { return false; } if (obj.getClass().isArray() == true) { - int len = Array.getLength(obj); + final int len = Array.getLength(obj); for (int i = 0; i < len; i++) { - Object o = Array.get(obj, i); + final Object o = Array.get(obj, i); if (equal(o, element)) { return true; } diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java index bdabd60d8..3984bf599 100755 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java @@ -1064,6 +1064,17 @@ public class DateUtilTest { Assert.assertFalse(DateUtil.isOverlap(startTime,endTime,realStartTime1,realEndTime1)); } + @Test + public void isOverlapTest2() { + DateTime oneStartTime = DateUtil.parseDate("2021-02-01"); + DateTime oneEndTime = DateUtil.parseDate("2022-06-30"); + + DateTime oneStartTime2 = DateUtil.parseDate("2019-04-05"); + DateTime oneEndTime2 = DateUtil.parseDate("2021-04-05"); + + Assert.assertTrue(DateUtil.isOverlap(oneStartTime, oneEndTime, oneStartTime2, oneEndTime2)); + } + @Test public void isInTest(){ String sourceStr = "2022-04-19 00:00:00"; diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/AssertTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/AssertTest.java index e20ef6e96..7ddde8d47 100755 --- a/hutool-core/src/test/java/cn/hutool/core/lang/AssertTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/AssertTest.java @@ -1,9 +1,10 @@ package cn.hutool.core.lang; +import cn.hutool.core.util.StrUtil; import org.junit.Test; public class AssertTest { - + @Test public void isNullTest(){ String a = null; @@ -33,6 +34,30 @@ public class AssertTest { public void isTrueTest3() { int i = -1; //noinspection ConstantConditions - Assert.isTrue(i > 0, ()-> new IndexOutOfBoundsException("relation message to return")); + Assert.isTrue(i > 0, () -> new IndexOutOfBoundsException("relation message to return")); } + + @Test + public void equalsTest() { + //String a="ab"; + //final String b = new String("abc"); + String a = null; + final String b = null; + Assert.equals(a, b); + Assert.equals(a, b, "{}不等于{}", a, b); + Assert.equals(a, b, () -> new RuntimeException(StrUtil.format("{}和{}不相等", a, b))); + } + + @Test + public void notEqualsTest() { + //String c="19"; + //final String d = new String("19"); + String c = null; + final String d = "null"; + //Assert.notEquals(c,d); + //Assert.notEquals(c,d,"{}等于{}",c,d); + Assert.notEquals(c, d, () -> new RuntimeException(StrUtil.format("{}和{}相等", c, d))); + + } + } diff --git a/hutool-core/src/test/java/cn/hutool/core/net/RFC3986Test.java b/hutool-core/src/test/java/cn/hutool/core/net/RFC3986Test.java index 781b78001..e549e9a9f 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/RFC3986Test.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/RFC3986Test.java @@ -1,9 +1,13 @@ package cn.hutool.core.net; +import cn.hutool.core.codec.PercentCodec; import cn.hutool.core.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + public class RFC3986Test { @Test @@ -26,4 +30,12 @@ public class RFC3986Test { String encode = RFC3986.QUERY_PARAM_VALUE.encode("a=%25", CharsetUtil.CHARSET_UTF_8, '%'); Assert.assertEquals("a=%25", encode); } + + @Test + public void encodeAllTest() throws UnsupportedEncodingException { + String toVerifyText = "行吧行吧 cargo:1.0,\"Deta-ils:[{"; + final String encode = PercentCodec.of(RFC3986.UNRESERVED).setEncodeSpaceAsPlus(true).encode(toVerifyText, CharsetUtil.CHARSET_UTF_8); + final String encodeJdk = URLEncoder.encode(toVerifyText, "UTF-8"); + Assert.assertEquals(encode, encodeJdk); + } } diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/digest/DigestUtil.java b/hutool-crypto/src/main/java/cn/hutool/crypto/digest/DigestUtil.java index fc6fd61ce..e6c04e305 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/digest/DigestUtil.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/digest/DigestUtil.java @@ -487,4 +487,110 @@ public class DigestUtil { public static boolean bcryptCheck(String password, String hashed) { return BCrypt.checkpw(password, hashed); } + + // ------------------------------------------------------------------------------------------- SHA-512 + + /** + * 计算SHA-512摘要值 + * + * @param data 被摘要数据 + * @return SHA-512摘要 + */ + public static byte[] sha512(final byte[] data) { + return new Digester(DigestAlgorithm.SHA512).digest(data); + } + + /** + * 计算SHA-512摘要值 + * + * @param data 被摘要数据 + * @param charset 编码 + * @return SHA-512摘要 + * @since 3.0.8 + */ + public static byte[] sha512(final String data, final String charset) { + return new Digester(DigestAlgorithm.SHA512).digest(data, charset); + } + + /** + * 计算sha512摘要值,使用UTF-8编码 + * + * @param data 被摘要数据 + * @return MD5摘要 + */ + public static byte[] sha512(final String data) { + return sha512(data, CharsetUtil.UTF_8); + } + + /** + * 计算SHA-512摘要值 + * + * @param data 被摘要数据 + * @return SHA-512摘要 + */ + public static byte[] sha512(final InputStream data) { + return new Digester(DigestAlgorithm.SHA512).digest(data); + } + + /** + * 计算SHA-512摘要值 + * + * @param file 被摘要文件 + * @return SHA-512摘要 + */ + public static byte[] sha512(final File file) { + return new Digester(DigestAlgorithm.SHA512).digest(file); + } + + /** + * 计算SHA-1摘要值,并转为16进制字符串 + * + * @param data 被摘要数据 + * @return SHA-512摘要的16进制表示 + */ + public static String sha512Hex(final byte[] data) { + return new Digester(DigestAlgorithm.SHA512).digestHex(data); + } + + /** + * 计算SHA-512摘要值,并转为16进制字符串 + * + * @param data 被摘要数据 + * @param charset 编码 + * @return SHA-512摘要的16进制表示 + */ + public static String sha512Hex(final String data, final String charset) { + return new Digester(DigestAlgorithm.SHA512).digestHex(data, charset); + } + + /** + * 计算SHA-512摘要值,并转为16进制字符串 + * + * @param data 被摘要数据 + * @return SHA-512摘要的16进制表示 + */ + public static String sha512Hex(final String data) { + return sha512Hex(data, CharsetUtil.UTF_8); + } + + /** + * 计算SHA-512摘要值,并转为16进制字符串 + * + * @param data 被摘要数据 + * @return SHA-512摘要的16进制表示 + */ + public static String sha512Hex(final InputStream data) { + return new Digester(DigestAlgorithm.SHA512).digestHex(data); + } + + /** + * 计算SHA-512摘要值,并转为16进制字符串 + * + * @param file 被摘要文件 + * @return SHA-512摘要的16进制表示 + */ + public static String sha512Hex(final File file) { + return new Digester(DigestAlgorithm.SHA512).digestHex(file); + } + } 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 69846b191..deb34e878 100755 --- a/hutool-db/src/main/java/cn/hutool/db/meta/MetaUtil.java +++ b/hutool-db/src/main/java/cn/hutool/db/meta/MetaUtil.java @@ -82,13 +82,13 @@ public class MetaUtil { conn = ds.getConnection(); // catalog和schema获取失败默认使用null代替 - String catalog = getCatalog(conn); + final String catalog = getCatalog(conn); if (null == schema) { schema = getSchema(conn); } final DatabaseMetaData metaData = conn.getMetaData(); - try (ResultSet rs = metaData.getTables(catalog, schema, tableName, Convert.toStrArray(types))) { + try (final ResultSet rs = metaData.getTables(catalog, schema, tableName, Convert.toStrArray(types))) { if (null != rs) { String table; while (rs.next()) { @@ -116,9 +116,9 @@ public class MetaUtil { */ public static String[] getColumnNames(ResultSet rs) throws DbRuntimeException { try { - ResultSetMetaData rsmd = rs.getMetaData(); - int columnCount = rsmd.getColumnCount(); - String[] labelNames = new String[columnCount]; + final ResultSetMetaData rsmd = rs.getMetaData(); + final int columnCount = rsmd.getColumnCount(); + final String[] labelNames = new String[columnCount]; for (int i = 0; i < labelNames.length; i++) { labelNames[i] = rsmd.getColumnLabel(i + 1); } @@ -137,17 +137,17 @@ public class MetaUtil { * @throws DbRuntimeException SQL执行异常 */ public static String[] getColumnNames(DataSource ds, String tableName) { - List columnNames = new ArrayList<>(); + final List columnNames = new ArrayList<>(); Connection conn = null; try { conn = ds.getConnection(); // catalog和schema获取失败默认使用null代替 - String catalog = getCatalog(conn); - String schema = getSchema(conn); + final String catalog = getCatalog(conn); + final String schema = getSchema(conn); final DatabaseMetaData metaData = conn.getMetaData(); - try (ResultSet rs = metaData.getColumns(catalog, schema, tableName, null)) { + try (final ResultSet rs = metaData.getColumns(catalog, schema, tableName, null)) { if (null != rs) { while (rs.next()) { columnNames.add(rs.getString("COLUMN_NAME")); @@ -225,7 +225,7 @@ public class MetaUtil { final DatabaseMetaData metaData = conn.getMetaData(); // 获得表元数据(表注释) - try (ResultSet rs = metaData.getTables(catalog, schema, tableName, new String[]{TableType.TABLE.value()})) { + try (final ResultSet rs = metaData.getTables(catalog, schema, tableName, new String[]{TableType.TABLE.value()})) { if (null != rs) { if (rs.next()) { table.setComment(rs.getString("REMARKS")); @@ -235,7 +235,7 @@ public class MetaUtil { } // 获得主键 - try (ResultSet rs = metaData.getPrimaryKeys(catalog, schema, tableName)) { + try (final ResultSet rs = metaData.getPrimaryKeys(catalog, schema, tableName)) { if (null != rs) { while (rs.next()) { table.addPk(rs.getString("COLUMN_NAME")); @@ -244,7 +244,7 @@ public class MetaUtil { } // 获得列 - try (ResultSet rs = metaData.getColumns(catalog, schema, tableName, null)) { + try (final ResultSet rs = metaData.getColumns(catalog, schema, tableName, null)) { if (null != rs) { while (rs.next()) { table.setColumn(Column.create(table, rs)); @@ -253,7 +253,7 @@ public class MetaUtil { } // 获得索引信息(since 5.7.23) - try (ResultSet rs = metaData.getIndexInfo(catalog, schema, tableName, false, false)) { + try (final ResultSet rs = metaData.getIndexInfo(catalog, schema, tableName, false, false)) { final Map indexInfoMap = new LinkedHashMap<>(); if (null != rs) { while (rs.next()) { diff --git a/hutool-db/src/test/java/cn/hutool/db/meta/MetaUtilTest.java b/hutool-db/src/test/java/cn/hutool/db/meta/MetaUtilTest.java index 0abd88676..d9ece6a58 100644 --- a/hutool-db/src/test/java/cn/hutool/db/meta/MetaUtilTest.java +++ b/hutool-db/src/test/java/cn/hutool/db/meta/MetaUtilTest.java @@ -2,6 +2,7 @@ package cn.hutool.db.meta; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.db.DbRuntimeException; import cn.hutool.db.ds.DSFactory; import org.junit.Assert; import org.junit.Test; @@ -20,25 +21,34 @@ public class MetaUtilTest { @Test public void getTablesTest() { - List tables = MetaUtil.getTables(ds); + final List tables = MetaUtil.getTables(ds); Assert.assertEquals("user", tables.get(0)); } @Test public void getTableMetaTest() { - Table table = MetaUtil.getTableMeta(ds, "user"); + final Table table = MetaUtil.getTableMeta(ds, "user"); Assert.assertEquals(CollectionUtil.newHashSet("id"), table.getPkNames()); } @Test public void getColumnNamesTest() { - String[] names = MetaUtil.getColumnNames(ds, "user"); + final String[] names = MetaUtil.getColumnNames(ds, "user"); Assert.assertArrayEquals(StrUtil.splitToArray("id,name,age,birthday,gender", ','), names); } @Test public void getTableIndexInfoTest() { - Table table = MetaUtil.getTableMeta(ds, "user_1"); + final Table table = MetaUtil.getTableMeta(ds, "user_1"); + Assert.assertEquals(table.getIndexInfoList().size(), 2); + } + + /** + * 表不存在抛出异常。 + */ + @Test(expected = DbRuntimeException.class) + public void getTableNotExistTest() { + final Table table = MetaUtil.getTableMeta(ds, "user_not_exist"); Assert.assertEquals(table.getIndexInfoList().size(), 2); } } diff --git a/hutool-dfa/src/main/java/cn/hutool/dfa/SensitiveUtil.java b/hutool-dfa/src/main/java/cn/hutool/dfa/SensitiveUtil.java index bcf81a784..ba8507cff 100755 --- a/hutool-dfa/src/main/java/cn/hutool/dfa/SensitiveUtil.java +++ b/hutool-dfa/src/main/java/cn/hutool/dfa/SensitiveUtil.java @@ -194,7 +194,7 @@ public final class SensitiveUtil { * @return 敏感词过滤处理后的bean对象 */ public static T sensitiveFilter(T bean, boolean isGreedMatch, SensitiveProcessor sensitiveProcessor) { - String jsonText = JSONUtil.toJsonStr(bean); + final String jsonText = JSONUtil.toJsonStr(bean); @SuppressWarnings("unchecked") final Class c = (Class) bean.getClass(); return JSONUtil.toBean(sensitiveFilter(jsonText, isGreedMatch, sensitiveProcessor), c); } @@ -224,7 +224,7 @@ public final class SensitiveUtil { } //敏感词过滤场景下,不需要密集匹配 - List foundWordList = getFoundAllSensitive(text, true, isGreedMatch); + final List foundWordList = getFoundAllSensitive(text, true, isGreedMatch); if (CollUtil.isEmpty(foundWordList)) { return text; } @@ -233,10 +233,10 @@ public final class SensitiveUtil { final Map foundWordMap = new HashMap<>(foundWordList.size(), 1); foundWordList.forEach(foundWord -> foundWordMap.put(foundWord.getStartIndex(), foundWord)); - int length = text.length(); - StringBuilder textStringBuilder = new StringBuilder(); + final int length = text.length(); + final StringBuilder textStringBuilder = new StringBuilder(); for (int i = 0; i < length; i++) { - FoundWord fw = foundWordMap.get(i); + final FoundWord fw = foundWordMap.get(i); if (fw != null) { textStringBuilder.append(sensitiveProcessor.process(fw)); i = fw.getEndIndex(); diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java index f4747bae3..8c4f4d4cf 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java @@ -105,7 +105,7 @@ public class CellUtil { cellType = cell.getCellType(); } - Object value; + final Object value; switch (cellType) { case NUMERIC: value = new NumericCellValue(cell).getValue(); @@ -199,14 +199,14 @@ public class CellUtil { * * @param row Excel表的行 * @param cellIndex 列号 - * @return {@link Row} + * @return {@link Cell} * @since 5.5.0 */ public static Cell getCell(Row row, int cellIndex) { if (null == row) { return null; } - Cell cell = row.getCell(cellIndex); + final Cell cell = row.getCell(cellIndex); if (null == cell) { return new NullCell(row, cellIndex); } @@ -218,7 +218,7 @@ public class CellUtil { * * @param row Excel表的行 * @param cellIndex 列号 - * @return {@link Row} + * @return {@link Cell} * @since 4.0.2 */ public static Cell getOrCreateCell(Row row, int cellIndex) { @@ -262,21 +262,84 @@ public class CellUtil { * @param sheet {@link Sheet} * @param x 列号,从0开始 * @param y 行号,从0开始 - * @return 是否是合并单元格 + * @return 是否是合并单元格,如果提供的sheet为{@code null},返回{@code false} */ public static boolean isMergedRegion(Sheet sheet, int x, int y) { - final int sheetMergeCount = sheet.getNumMergedRegions(); - CellRangeAddress ca; - for (int i = 0; i < sheetMergeCount; i++) { - ca = sheet.getMergedRegion(i); - if (y >= ca.getFirstRow() && y <= ca.getLastRow() - && x >= ca.getFirstColumn() && x <= ca.getLastColumn()) { - return true; + if (sheet != null) { + final int sheetMergeCount = sheet.getNumMergedRegions(); + CellRangeAddress ca; + for (int i = 0; i < sheetMergeCount; i++) { + ca = sheet.getMergedRegion(i); + if (y >= ca.getFirstRow() && y <= ca.getLastRow() + && x >= ca.getFirstColumn() && x <= ca.getLastColumn()) { + return true; + } } } return false; } + /** + * 获取合并单元格{@link CellRangeAddress},如果不是返回null + * + * @param sheet {@link Sheet} + * @param locationRef 单元格地址标识符,例如A11,B5 + * @return {@link CellRangeAddress} + * @since 5.8.0 + */ + public static CellRangeAddress getCellRangeAddress(Sheet sheet, String locationRef) { + final CellLocation cellLocation = ExcelUtil.toLocation(locationRef); + return getCellRangeAddress(sheet, cellLocation.getX(), cellLocation.getY()); + } + + /** + * 获取合并单元格{@link CellRangeAddress},如果不是返回null + * + * @param cell {@link Cell} + * @return {@link CellRangeAddress} + * @since 5.8.0 + */ + public static CellRangeAddress getCellRangeAddress(Cell cell) { + return getCellRangeAddress(cell.getSheet(), cell.getColumnIndex(), cell.getRowIndex()); + } + + /** + * 获取合并单元格{@link CellRangeAddress},如果不是返回null + * + * @param sheet {@link Sheet} + * @param x 列号,从0开始 + * @param y 行号,从0开始 + * @return {@link CellRangeAddress} + * @since 5.8.0 + */ + public static CellRangeAddress getCellRangeAddress(Sheet sheet, int x, int y) { + if (sheet != null) { + final int sheetMergeCount = sheet.getNumMergedRegions(); + CellRangeAddress ca; + for (int i = 0; i < sheetMergeCount; i++) { + ca = sheet.getMergedRegion(i); + if (y >= ca.getFirstRow() && y <= ca.getLastRow() + && x >= ca.getFirstColumn() && x <= ca.getLastColumn()) { + return ca; + } + } + } + return null; + } + + /** + * 设置合并单元格样式,如果不是则不设置 + * + * @param cell {@link Cell} + * @param cellStyle {@link CellStyle} + */ + public static void setMergedRegionStyle(Cell cell, CellStyle cellStyle) { + final CellRangeAddress cellRangeAddress = getCellRangeAddress(cell); + if (cellRangeAddress != null) { + setMergeCellStyle(cellStyle, cellRangeAddress, cell.getSheet()); + } + } + /** * 合并单元格,可以根据设置的值来合并行和列 * @@ -310,16 +373,7 @@ public class CellUtil { lastColumn // last column (0-based) ); - if (null != cellStyle) { - RegionUtil.setBorderTop(cellStyle.getBorderTop(), cellRangeAddress, sheet); - RegionUtil.setBorderRight(cellStyle.getBorderRight(), cellRangeAddress, sheet); - RegionUtil.setBorderBottom(cellStyle.getBorderBottom(), cellRangeAddress, sheet); - RegionUtil.setBorderLeft(cellStyle.getBorderLeft(), cellRangeAddress, sheet); - RegionUtil.setTopBorderColor(cellStyle.getTopBorderColor(),cellRangeAddress,sheet); - RegionUtil.setRightBorderColor(cellStyle.getRightBorderColor(),cellRangeAddress,sheet); - RegionUtil.setLeftBorderColor(cellStyle.getLeftBorderColor(),cellRangeAddress,sheet); - RegionUtil.setBottomBorderColor(cellStyle.getBottomBorderColor(),cellRangeAddress,sheet); - } + setMergeCellStyle(cellStyle, cellRangeAddress, sheet); return sheet.addMergedRegion(cellRangeAddress); } @@ -406,7 +460,7 @@ public class CellUtil { anchor.setRow1(cell.getRowIndex()); anchor.setRow2(cell.getRowIndex() + 2); } - Comment comment = drawing.createCellComment(anchor); + final Comment comment = drawing.createCellComment(anchor); comment.setString(factory.createRichTextString(commentText)); comment.setAuthor(StrUtil.nullToEmpty(commentAuthor)); cell.setCellComment(comment); @@ -435,5 +489,25 @@ public class CellUtil { } return null; } + + /** + * 根据{@link CellStyle}设置合并单元格边框样式 + * + * @param cellStyle {@link CellStyle} + * @param cellRangeAddress {@link CellRangeAddress} + * @param sheet {@link Sheet} + */ + private static void setMergeCellStyle(CellStyle cellStyle, CellRangeAddress cellRangeAddress, Sheet sheet) { + if (null != cellStyle) { + RegionUtil.setBorderTop(cellStyle.getBorderTop(), cellRangeAddress, sheet); + RegionUtil.setBorderRight(cellStyle.getBorderRight(), cellRangeAddress, sheet); + RegionUtil.setBorderBottom(cellStyle.getBorderBottom(), cellRangeAddress, sheet); + RegionUtil.setBorderLeft(cellStyle.getBorderLeft(), cellRangeAddress, sheet); + RegionUtil.setTopBorderColor(cellStyle.getTopBorderColor(), cellRangeAddress, sheet); + RegionUtil.setRightBorderColor(cellStyle.getRightBorderColor(), cellRangeAddress, sheet); + RegionUtil.setLeftBorderColor(cellStyle.getLeftBorderColor(), cellRangeAddress, sheet); + RegionUtil.setBottomBorderColor(cellStyle.getBottomBorderColor(), cellRangeAddress, sheet); + } + } // -------------------------------------------------------------------------------------------------------------- Private method end } diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/setters/package-info.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/setters/package-info.java new file mode 100644 index 000000000..b0d905b77 --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/setters/package-info.java @@ -0,0 +1,6 @@ +/** + * Excel中单元格设置相关类,一些{@link cn.hutool.poi.excel.cell.CellSetter}的实现类 + * + * @author looly + */ +package cn.hutool.poi.excel.cell.setters;