diff --git a/CHANGELOG.md b/CHANGELOG.md index dec1188f3..306661a7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,35 @@ ------------------------------------------------------------------------------------------------------------- +# 5.5.5 (2020-12-27) + +### 新特性 +* 【core 】 URLUtil.normalize新增重载(pr#233@Gitee) +* 【core 】 PathUtil增加isSub和toAbsNormal方法 +* 【db 】 RedisDS实现序列化接口(pr#1323@Github) +* 【poi 】 StyleUtil增加getFormat方法(pr#235@Gitee) +* 【poi 】 增加ExcelDateUtil更多日期格式支持(issue#1316@Github) +* 【core 】 NumberUtil.toBigDecimal支持各类数字格式,如1,234.56等(issue#1334@Github) +* 【core 】 NumberUtil增加parseXXX方法(issue#1334@Github) +* 【poi 】 Excel07SaxReader支持通过sheetName读取(issue#I2AOSE@Gitee) + +### Bug修复 +* 【core 】 FileUtil.isSub相对路径判断问题(pr#1315@Github) +* 【core 】 TreeUtil增加空判定(issue#I2ACCW@Gitee) +* 【db 】 解决Hive获取表名失败问题(issue#I2AGLU@Gitee) +* 【core 】 修复DateUtil.parse未使用严格模式导致结果不正常的问题(issue#1332@Github) +* 【core 】 修复RuntimeUtil.getUsableMemory非static问题(issue#I2AQ2M@Gitee) +* 【core 】 修复ArrayUtil.equals方法严格判断问题(issue#I2AO8B@Gitee) +* 【poi 】 修复SheetRidReader在获取rid时读取错误问题(issue#I2AOQW@Gitee) +* 【core 】 修复强依赖了POI的问题(issue#1336@Github) + +------------------------------------------------------------------------------------------------------------- # 5.5.4 (2020-12-16) ### 新特性 ### Bug修复 * 【core 】 修复IoUtil.readBytes的问题 - ------------------------------------------------------------------------------------------------------------- # 5.5.3 (2020-12-11) diff --git a/README-EN.md b/README-EN.md index de675a27d..d71319098 100644 --- a/README-EN.md +++ b/README-EN.md @@ -125,19 +125,19 @@ Each module can be introduced individually, or all modules can be introduced by cn.hutool hutool-all - 5.5.4 + 5.5.5 ``` ### Gradle ``` -compile 'cn.hutool:hutool-all:5.5.4' +compile 'cn.hutool:hutool-all:5.5.5' ``` ## Download -- [Maven1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.5.4/) -- [Maven2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.5.4/) +- [Maven1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.5.5/) +- [Maven2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.5.5/) > note: > Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available. diff --git a/README.md b/README.md index 5663dd161..6bbf71396 100644 --- a/README.md +++ b/README.md @@ -123,21 +123,21 @@ Hutool的存在就是为了减少代码搜索成本,避免网络上参差不 cn.hutool hutool-all - 5.5.4 + 5.5.5 ``` ### Gradle ``` -compile 'cn.hutool:hutool-all:5.5.4' +compile 'cn.hutool:hutool-all:5.5.5' ``` ### 非Maven项目 点击以下任一链接,下载`hutool-all-X.X.X.jar`即可: -- [Maven中央库1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.5.4/) -- [Maven中央库2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.5.4/) +- [Maven中央库1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.5.5/) +- [Maven中央库2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.5.5/) > 注意 > Hutool 5.x支持JDK8+,对Android平台没有测试,不能保证所有工具类或工具方法可用。 diff --git a/bin/version.txt b/bin/version.txt index c8f1d098d..e69889c7f 100755 --- a/bin/version.txt +++ b/bin/version.txt @@ -1 +1 @@ -5.5.4 +5.5.5 diff --git a/docs/js/version.js b/docs/js/version.js index 44b8b9b87..bb06014fa 100644 --- a/docs/js/version.js +++ b/docs/js/version.js @@ -1 +1 @@ -var version = '5.5.4' \ No newline at end of file +var version = '5.5.5' \ No newline at end of file diff --git a/hutool-all/pom.xml b/hutool-all/pom.xml index 537d1e97f..9d55c5313 100644 --- a/hutool-all/pom.xml +++ b/hutool-all/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-all diff --git a/hutool-aop/pom.xml b/hutool-aop/pom.xml index 5f0a36be5..660b76fb8 100644 --- a/hutool-aop/pom.xml +++ b/hutool-aop/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-aop diff --git a/hutool-bloomFilter/pom.xml b/hutool-bloomFilter/pom.xml index cac489419..4781d5462 100644 --- a/hutool-bloomFilter/pom.xml +++ b/hutool-bloomFilter/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-bloomFilter diff --git a/hutool-bom/pom.xml b/hutool-bom/pom.xml index 969b22b13..48f6ab0c5 100644 --- a/hutool-bom/pom.xml +++ b/hutool-bom/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-bom diff --git a/hutool-cache/pom.xml b/hutool-cache/pom.xml index e1ee87553..999d811c8 100644 --- a/hutool-cache/pom.xml +++ b/hutool-cache/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-cache diff --git a/hutool-captcha/pom.xml b/hutool-captcha/pom.xml index 1e1d08f19..7eb0a03f2 100644 --- a/hutool-captcha/pom.xml +++ b/hutool-captcha/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-captcha diff --git a/hutool-core/pom.xml b/hutool-core/pom.xml index deccd861e..38c9adefc 100644 --- a/hutool-core/pom.xml +++ b/hutool-core/pom.xml @@ -5,19 +5,11 @@ 4.0.0 jar - - - org.apache.poi - poi - 4.1.2 - compile - - cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-core diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Base64Encoder.java b/hutool-core/src/main/java/cn/hutool/core/codec/Base64Encoder.java index 33c2b700b..1df7cefd8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/Base64Encoder.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/Base64Encoder.java @@ -1,10 +1,10 @@ package cn.hutool.core.codec; -import java.nio.charset.Charset; - import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; +import java.nio.charset.Charset; + /** * Base64编码 * @@ -128,11 +128,11 @@ public class Base64Encoder { /** * 编码为Base64
- * 如果isMultiLine为true,则每76个字符一个换行符,否则在一行显示 + * 如果isMultiLine为{@code true},则每76个字符一个换行符,否则在一行显示 * * @param arr 被编码的数组 * @param isMultiLine 在76个char之后是CRLF还是EOF - * @param isUrlSafe 是否使用URL安全字符,一般为false + * @param isUrlSafe 是否使用URL安全字符,一般为{@code false} * @return 编码后的bytes */ public static byte[] encode(byte[] arr, boolean isMultiLine, boolean isUrlSafe) { diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java index 7d41bbb4c..e1b2f0c03 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java @@ -21,16 +21,16 @@ import java.util.function.Function; * 数字转换器
* 支持类型为:
* * * @author Looly @@ -80,7 +80,11 @@ public class NumberConverter extends AbstractConverter { return BooleanUtil.toByteObj((Boolean) value); } final String valueStr = toStrFunc.apply(value); - return StrUtil.isBlank(valueStr) ? null : Byte.valueOf(valueStr); + try{ + return StrUtil.isBlank(valueStr) ? null : Byte.valueOf(valueStr); + } catch (NumberFormatException e){ + return NumberUtil.parseNumber(valueStr).byteValue(); + } } else if (Short.class == targetType) { if (value instanceof Number) { return ((Number) value).shortValue(); @@ -88,7 +92,11 @@ public class NumberConverter extends AbstractConverter { return BooleanUtil.toShortObj((Boolean) value); } final String valueStr = toStrFunc.apply((value)); - return StrUtil.isBlank(valueStr) ? null : Short.valueOf(valueStr); + try{ + return StrUtil.isBlank(valueStr) ? null : Short.valueOf(valueStr); + } catch (NumberFormatException e){ + return NumberUtil.parseNumber(valueStr).shortValue(); + } } else if (Integer.class == targetType) { if (value instanceof Number) { return ((Number) value).intValue(); @@ -146,8 +154,7 @@ public class NumberConverter extends AbstractConverter { return BooleanUtil.toFloatObj((Boolean) value); } final String valueStr = toStrFunc.apply((value)); - return StrUtil.isBlank(valueStr) ? null : Float.valueOf(valueStr); - + return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseFloat(valueStr); } else if (Double.class == targetType) { if (value instanceof Number) { return ((Number) value).doubleValue(); @@ -155,7 +162,7 @@ public class NumberConverter extends AbstractConverter { return BooleanUtil.toDoubleObj((Boolean) value); } final String valueStr = toStrFunc.apply((value)); - return StrUtil.isBlank(valueStr) ? null : Double.valueOf(valueStr); + return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseDouble(valueStr); } else if (DoubleAdder.class == targetType) { //jdk8 新增 final Number number = convert(value, Long.class, toStrFunc); diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java b/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java index be693e020..fb27f592d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java @@ -219,7 +219,7 @@ public class DateTime extends Date { * @see DatePattern */ public DateTime(CharSequence dateStr, String format) { - this(dateStr, new SimpleDateFormat(format)); + this(dateStr, DateUtil.newSimpleFormat(format)); } /** @@ -895,9 +895,7 @@ public class DateTime extends Date { */ public String toString(TimeZone timeZone) { if (null != timeZone) { - final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN); - simpleDateFormat.setTimeZone(timeZone); - return toString(simpleDateFormat); + return toString(DateUtil.newSimpleFormat(DatePattern.NORM_DATETIME_PATTERN, null, timeZone)); } return toString(DatePattern.NORM_DATETIME_FORMAT); } @@ -910,9 +908,7 @@ public class DateTime extends Date { */ public String toDateStr() { if (null != this.timeZone) { - final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatePattern.NORM_DATE_PATTERN); - simpleDateFormat.setTimeZone(this.timeZone); - return toString(simpleDateFormat); + return toString(DateUtil.newSimpleFormat(DatePattern.NORM_DATE_PATTERN, null, timeZone)); } return toString(DatePattern.NORM_DATE_FORMAT); } @@ -925,9 +921,7 @@ public class DateTime extends Date { */ public String toTimeStr() { if (null != this.timeZone) { - final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatePattern.NORM_TIME_PATTERN); - simpleDateFormat.setTimeZone(this.timeZone); - return toString(simpleDateFormat); + return toString(DateUtil.newSimpleFormat(DatePattern.NORM_TIME_PATTERN, null, timeZone)); } return toString(DatePattern.NORM_TIME_FORMAT); } @@ -940,9 +934,7 @@ public class DateTime extends Date { */ public String toString(String format) { if (null != this.timeZone) { - final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); - simpleDateFormat.setTimeZone(this.timeZone); - return toString(simpleDateFormat); + return toString(DateUtil.newSimpleFormat(format, null, timeZone)); } return toString(FastDateFormat.getInstance(format)); } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java index c08f46b7d..c4efd201f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java @@ -14,14 +14,18 @@ import cn.hutool.core.util.StrUtil; import java.text.DateFormat; import java.text.SimpleDateFormat; - import java.time.Instant; import java.time.LocalDateTime; import java.time.Year; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAccessor; - -import java.util.*; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; @@ -506,14 +510,11 @@ public class DateUtil extends CalendarUtil { return null; } - final SimpleDateFormat sdf = new SimpleDateFormat(format); + TimeZone timeZone = null; if (date instanceof DateTime) { - final TimeZone timeZone = ((DateTime) date).getTimeZone(); - if (null != timeZone) { - sdf.setTimeZone(timeZone); - } + timeZone = ((DateTime) date).getTimeZone(); } - return format(date, sdf); + return format(date, newSimpleFormat(format, null, timeZone)); } /** @@ -717,7 +718,7 @@ public class DateUtil extends CalendarUtil { * @since 4.5.18 */ public static DateTime parse(CharSequence dateStr, String format, Locale locale) { - return new DateTime(dateStr, new SimpleDateFormat(format, locale)); + return new DateTime(dateStr, DateUtil.newSimpleFormat(format, locale, null)); } /** @@ -1917,7 +1918,7 @@ public class DateUtil extends CalendarUtil { /** * 获得指定月份的总天数 * - * @param month 年份 + * @param month 年份 * @param isLeapYear 是否闰年 * @return 天 * @since 5.4.2 @@ -1926,6 +1927,40 @@ public class DateUtil extends CalendarUtil { return java.time.Month.of(month).length(isLeapYear); } + /** + * 创建{@link SimpleDateFormat},注意此对象非线程安全!
+ * 此对象默认为严格格式模式,即parse时如果格式不正确会报错。 + * + * @param pattern 表达式 + * @return {@link SimpleDateFormat} + * @since 5.5.5 + */ + public static SimpleDateFormat newSimpleFormat(String pattern) { + return newSimpleFormat(pattern, null, null); + } + + /** + * 创建{@link SimpleDateFormat},注意此对象非线程安全!
+ * 此对象默认为严格格式模式,即parse时如果格式不正确会报错。 + * + * @param pattern 表达式 + * @param locale {@link Locale},{@code null}表示默认 + * @param timeZone {@link TimeZone},{@code null}表示默认 + * @return {@link SimpleDateFormat} + * @since 5.5.5 + */ + public static SimpleDateFormat newSimpleFormat(String pattern, Locale locale, TimeZone timeZone) { + if (null == locale) { + locale = Locale.getDefault(Locale.Category.FORMAT); + } + final SimpleDateFormat format = new SimpleDateFormat(pattern, locale); + if (null != timeZone) { + format.setTimeZone(timeZone); + } + format.setLenient(false); + return format; + } + // ------------------------------------------------------------------------ Private method start /** diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java b/hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java index a3491393d..a9f7d5390 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java @@ -1,5 +1,8 @@ package cn.hutool.core.date.format; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.Tuple; + import java.text.DateFormat; import java.text.Format; import java.text.SimpleDateFormat; @@ -8,9 +11,6 @@ import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import cn.hutool.core.lang.Assert; -import cn.hutool.core.lang.Tuple; - /** * 日期格式化器缓存
* Thanks to Apache Commons Lang 3.5 @@ -43,7 +43,7 @@ abstract class FormatCache { * @param timeZone 时区,默认当前时区 * @param locale 地区,默认使用当前地区 * @return 格式化器 - * @throws IllegalArgumentException pattern 无效或null + * @throws IllegalArgumentException pattern 无效或{@code null} */ public F getInstance(final String pattern, TimeZone timeZone, Locale locale) { Assert.notBlank(pattern, "pattern must not be blank") ; @@ -74,7 +74,7 @@ abstract class FormatCache { * @param timeZone 时区,默认当前时区 * @param locale 地区,默认使用当前地区 * @return 格式化器 - * @throws IllegalArgumentException pattern 无效或null + * @throws IllegalArgumentException pattern 无效或{@code null} */ abstract protected F createInstance(String pattern, TimeZone timeZone, Locale locale); 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 2eccd286e..d0b59ab37 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 @@ -3194,7 +3194,7 @@ public class FileUtil extends PathUtil { public static boolean isSub(File parent, File sub) { Assert.notNull(parent); Assert.notNull(sub); - return sub.toPath().startsWith(parent.toPath()); + return isSub(parent.toPath(), sub.toPath()); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java index cd737c9be..1c877e6ef 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java @@ -515,4 +515,43 @@ public class PathUtil { final LinkOption[] options = isFollowLinks ? new LinkOption[0] : new LinkOption[]{LinkOption.NOFOLLOW_LINKS}; return Files.exists(path, options); } + + /** + * 判断给定的目录是否为给定文件或文件夹的子目录 + * + * @param parent 父目录 + * @param sub 子目录 + * @return 子目录是否为父目录的子目录 + * @since 5.5.5 + */ + public static boolean isSub(Path parent, Path sub) { + return toAbsNormal(sub).startsWith(toAbsNormal(parent)); + } + + /** + * 将Path路径转换为标准的绝对路径 + * + * @param path 文件或目录Path + * @return 转换后的Path + * @since 5.5.5 + */ + public static Path toAbsNormal(Path path){ + Assert.notNull(path); + return path.toAbsolutePath().normalize(); + } + + /** + * 获得文件的MimeType + * + * @param file 文件 + * @return MimeType + * @since 5.5.5 + */ + public static String getMimeType(Path file) { + try { + return Files.probeContentType(file); + } catch (IOException e) { + throw new IORuntimeException(e); + } + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java index 8a4d9e0e4..1babcc1fb 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java @@ -74,7 +74,7 @@ public class TreeUtil { List> finalTreeList = CollUtil.newArrayList(); for (Tree node : treeList) { - if (parentId.equals(node.getParentId())) { + if (ObjectUtil.equals(parentId,node.getParentId())) { finalTreeList.add(node); innerBuild(treeList, node, 0, treeNodeConfig.getDeep()); } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java index ccf42f12b..db6d7345d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java @@ -523,7 +523,7 @@ public class ArrayUtil extends PrimitiveArrayUtil { } /** - * 克隆数组,如果非数组返回null + * 克隆数组,如果非数组返回{@code null} * * @param 数组元素类型 * @param obj 数组对象 @@ -1667,11 +1667,6 @@ public class ArrayUtil extends PrimitiveArrayUtil { Assert.isTrue(isArray(array1), "First is not a Array !"); Assert.isTrue(isArray(array2), "Second is not a Array !"); - // 数组类型一致性判断 - if (array1.getClass() != array2.getClass()) { - return false; - } - if (array1 instanceof long[]) { return Arrays.equals((long[]) array1, (long[]) array2); } else if (array1 instanceof int[]) { diff --git a/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java index aa8896bf1..11f6e94e9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java @@ -2044,6 +2044,11 @@ public class NumberUtil { * @since 4.0.9 */ public static BigDecimal toBigDecimal(String number) { + try{ + number = parseNumber(number).toString(); + } catch (Exception ignore){ + // 忽略解析错误 + } return StrUtil.isBlank(number) ? BigDecimal.ZERO : new BigDecimal(number); } @@ -2287,7 +2292,7 @@ public class NumberUtil { * *
 	 * 1、0x开头的视为16进制数字
-	 * 2、0开头的视为8进制数字
+	 * 2、0开头的忽略开头的0
 	 * 3、其它情况按照10进制转换
 	 * 4、空串返回0
 	 * 5、.123形式返回0(按照小于0的小数对待)
@@ -2304,18 +2309,16 @@ public class NumberUtil {
 			return 0;
 		}
 
-		// 对于带小数转换为整数采取去掉小数的策略
-		number = StrUtil.subBefore(number, CharUtil.DOT, false);
-		if (StrUtil.isEmpty(number)) {
-			return 0;
-		}
-
 		if (StrUtil.startWithIgnoreCase(number, "0x")) {
 			// 0x04表示16进制数
 			return Integer.parseInt(number.substring(2), 16);
 		}
 
-		return Integer.parseInt(removeNumberFlag(number));
+		try{
+			return Integer.parseInt(number);
+		} catch (NumberFormatException e){
+			return parseNumber(number).intValue();
+		}
 	}
 
 	/**
@@ -2323,9 +2326,11 @@ public class NumberUtil {
 	 *
 	 * 
 	 * 1、0x开头的视为16进制数字
-	 * 2、0开头的视为8进制数字
+	 * 2、0开头的忽略开头的0
 	 * 3、空串返回0
 	 * 4、其它情况按照10进制转换
+	 * 5、.123形式返回0(按照小于0的小数对待)
+	 * 6、123.56截取小数点之前的数字,忽略小数部分
 	 * 
* * @param number 数字,支持0x开头、0开头和普通十进制 @@ -2334,13 +2339,7 @@ public class NumberUtil { */ public static long parseLong(String number) { if (StrUtil.isBlank(number)) { - return 0; - } - - // 对于带小数转换为整数采取去掉小数的策略 - number = StrUtil.subBefore(number, CharUtil.DOT, false); - if (StrUtil.isEmpty(number)) { - return 0; + return 0L; } if (number.startsWith("0x")) { @@ -2348,7 +2347,63 @@ public class NumberUtil { return Long.parseLong(number.substring(2), 16); } - return Long.parseLong(removeNumberFlag(number)); + try{ + return Long.parseLong(number); + } catch (NumberFormatException e){ + return parseNumber(number).longValue(); + } + } + + /** + * 解析转换数字字符串为long型数字,规则如下: + * + *
+	 * 1、0开头的忽略开头的0
+	 * 2、空串返回0
+	 * 3、其它情况按照10进制转换
+	 * 4、.123形式返回0.123(按照小于0的小数对待)
+	 * 
+ * + * @param number 数字,支持0x开头、0开头和普通十进制 + * @return long + * @since 5.5.5 + */ + public static float parseFloat(String number) { + if (StrUtil.isBlank(number)) { + return 0f; + } + + try{ + return Float.parseFloat(number); + } catch (NumberFormatException e){ + return parseNumber(number).floatValue(); + } + } + + /** + * 解析转换数字字符串为long型数字,规则如下: + * + *
+	 * 1、0开头的忽略开头的0
+	 * 2、空串返回0
+	 * 3、其它情况按照10进制转换
+	 * 4、.123形式返回0.123(按照小于0的小数对待)
+	 * 
+ * + * @param number 数字,支持0x开头、0开头和普通十进制 + * @return long + * @since 5.5.5 + */ + public static double parseDouble(String number) { + if (StrUtil.isBlank(number)) { + return 0D; + } + + try{ + return Double.parseDouble(number); + } catch (NumberFormatException e){ + return parseNumber(number).doubleValue(); + } } /** @@ -2357,13 +2412,15 @@ public class NumberUtil { * @param numberStr Number字符串 * @return Number对象 * @since 4.1.15 + * @throws NumberFormatException 包装了{@link ParseException},当给定的数字字符串无法解析时抛出 */ - public static Number parseNumber(String numberStr) { - numberStr = removeNumberFlag(numberStr); + public static Number parseNumber(String numberStr) throws NumberFormatException{ try { return NumberFormat.getInstance().parse(numberStr); } catch (ParseException e) { - throw new UtilException(e); + final NumberFormatException nfe = new NumberFormatException(e.getMessage()); + nfe.initCause(e); + throw nfe; } } @@ -2509,25 +2566,5 @@ public class NumberUtil { return selectNum * mathNode(selectNum - 1); } } - - /** - * 去掉数字尾部的数字标识,例如12D,44.0F,22L中的最后一个字母 - * - * @param number 数字字符串 - * @return 去掉标识的字符串 - */ - private static String removeNumberFlag(String number) { - // 去掉千位分隔符 - if (StrUtil.contains(number, CharUtil.COMMA)) { - number = StrUtil.removeAll(number, CharUtil.COMMA); - } - // 去掉类型标识的结尾 - final int lastPos = number.length() - 1; - final char lastCharUpper = Character.toUpperCase(number.charAt(lastPos)); - if ('D' == lastCharUpper || 'L' == lastCharUpper || 'F' == lastCharUpper) { - number = StrUtil.subPre(number, lastPos); - } - return number; - } // ------------------------------------------------------------------------------------------- Private method end } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/RuntimeUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/RuntimeUtil.java index f4d4f4c16..405825ba1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/RuntimeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/RuntimeUtil.java @@ -298,7 +298,7 @@ public class RuntimeUtil { * * @return 最大可用内存 */ - public final long getUsableMemory() { + public static long getUsableMemory() { return getMaxMemory() - getTotalMemory() + getFreeMemory(); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java index 4ba026e38..0026d5353 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java @@ -14,14 +14,7 @@ import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.JarURLConnection; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLStreamHandler; +import java.net.*; import java.nio.charset.Charset; import java.util.Map; import java.util.jar.JarFile; @@ -669,9 +662,11 @@ public class URLUtil { /** * 标准化URL字符串,包括: * - *
-	 * 1. 多个/替换为一个
-	 * 
+ *
    + *
  1. 自动补齐“http://”头
  2. + *
  3. 去除开头的\或者/
  4. + *
  5. 替换\为/
  6. + *
* * @param url URL字符串 * @return 标准化后的URL字符串 @@ -683,9 +678,11 @@ public class URLUtil { /** * 标准化URL字符串,包括: * - *
-	 * 1. 多个/替换为一个
-	 * 
+ *
    + *
  1. 自动补齐“http://”头
  2. + *
  3. 去除开头的\或者/
  4. + *
  5. 替换\为/
  6. + *
* * @param url URL字符串 * @param isEncodePath 是否对URL中path部分的中文和特殊字符做转义(不包括 http:, /和域名部分) @@ -693,6 +690,26 @@ public class URLUtil { * @since 4.4.1 */ public static String normalize(String url, boolean isEncodePath) { + return normalize(url, isEncodePath, false); + } + + /** + * 标准化URL字符串,包括: + * + *
    + *
  1. 自动补齐“http://”头
  2. + *
  3. 去除开头的\或者/
  4. + *
  5. 替换\为/
  6. + *
  7. 如果replaceSlash为true,则替换多个/为一个
  8. + *
+ * + * @param url URL字符串 + * @param isEncodePath 是否对URL中path部分的中文和特殊字符做转义(不包括 http:, /和域名部分) + * @param replaceSlash 是否替换url body中的 // + * @return 标准化后的URL字符串 + * @since 5.5.5 + */ + public static String normalize(String url, boolean isEncodePath, boolean replaceSlash) { if (StrUtil.isBlank(url)) { return url; } @@ -718,10 +735,12 @@ public class URLUtil { // 去除开头的\或者/ //noinspection ConstantConditions body = body.replaceAll("^[\\\\/]+", StrUtil.EMPTY); - // 替换多个\或/为单个/ + // 替换\为/ body = body.replace("\\", "/"); - //issue#I25MZL,双斜杠在URL中是允许存在的,不做替换 - //.replaceAll("//+", "/"); + if (replaceSlash) { + //issue#I25MZL@Gitee,双斜杠在URL中是允许存在的,默认不做替换 + body = body.replaceAll("//+", "/"); + } } final int pathSepIndex = StrUtil.indexOf(body, '/'); diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/NumberConverterTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/NumberConverterTest.java new file mode 100644 index 000000000..28632f2de --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/convert/NumberConverterTest.java @@ -0,0 +1,22 @@ +package cn.hutool.core.convert; + +import cn.hutool.core.convert.impl.NumberConverter; +import org.junit.Assert; +import org.junit.Test; + +public class NumberConverterTest { + + @Test + public void toDoubleTest(){ + final NumberConverter numberConverter = new NumberConverter(Double.class); + final Number convert = numberConverter.convert("1,234.55", null); + Assert.assertEquals(1234.55D, convert); + } + + @Test + public void toIntegerTest(){ + final NumberConverter numberConverter = new NumberConverter(Integer.class); + final Number convert = numberConverter.convert("1,234.55", null); + Assert.assertEquals(1234, convert); + } +} 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 0500d3827..f709f644d 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java @@ -831,4 +831,11 @@ public class DateUtilTest { final DateTime parse = DateUtil.parse(dt); Assert.assertEquals("2020-06-03 12:32:12", parse.toString()); } + + @Test(expected = DateException.class) + public void parseNotFitTest(){ + //https://github.com/looly/hutool/issues/1332 + // 在日期格式不匹配的时候,测试是否正常报错 + final DateTime parse = DateUtil.parse("2020-12-23", DatePattern.PURE_DATE_PATTERN); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java index 43de63973..2980d0890 100644 --- a/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java @@ -384,4 +384,11 @@ public class FileUtilTest { File file2 = new File("d:/test2/aaa"); Assert.assertFalse(FileUtil.isSub(file, file2)); } + + @Test + public void isSubRelativeTest() { + File file = new File(".."); + File file2 = new File("."); + Assert.assertTrue(FileUtil.isSub(file, file2)); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java index b547d7e96..684ab56c0 100644 --- a/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java @@ -1,5 +1,6 @@ package cn.hutool.core.io.file; +import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; @@ -33,4 +34,10 @@ public class PathUtilTest { public void moveTest(){ PathUtil.move(Paths.get("d:/lombok.jar"), Paths.get("d:/test/"), false); } + + @Test + public void getMimeTypeTest(){ + final String mimeType = PathUtil.getMimeType(Paths.get("d:/test/test.jpg")); + Assert.assertEquals("image/jpeg", mimeType); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java index cbd632a0f..a6546efcd 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java @@ -189,6 +189,12 @@ public class NumberUtilTest { BigDecimal bigDecimal = NumberUtil.toBigDecimal(a); Assert.assertEquals("3.14", bigDecimal.toString()); + + bigDecimal = NumberUtil.toBigDecimal("1,234.55"); + Assert.assertEquals("1234.55", bigDecimal.toString()); + + bigDecimal = NumberUtil.toBigDecimal("1,234.56D"); + Assert.assertEquals("1234.56", bigDecimal.toString()); } @Test @@ -205,21 +211,33 @@ public class NumberUtilTest { @Test public void parseIntTest() { - int v1 = NumberUtil.parseInt("0xFF"); - Assert.assertEquals(255, v1); - int v2 = NumberUtil.parseInt("010"); - Assert.assertEquals(10, v2); - int v3 = NumberUtil.parseInt("10"); - Assert.assertEquals(10, v3); - int v4 = NumberUtil.parseInt(" "); - Assert.assertEquals(0, v4); - int v5 = NumberUtil.parseInt("10F"); - Assert.assertEquals(10, v5); - int v6 = NumberUtil.parseInt("22.4D"); - Assert.assertEquals(22, v6); + int number = NumberUtil.parseInt("0xFF"); + Assert.assertEquals(255, number); - int v7 = NumberUtil.parseInt("0"); - Assert.assertEquals(0, v7); + // 0开头 + number = NumberUtil.parseInt("010"); + Assert.assertEquals(10, number); + + number = NumberUtil.parseInt("10"); + Assert.assertEquals(10, number); + + number = NumberUtil.parseInt(" "); + Assert.assertEquals(0, number); + + number = NumberUtil.parseInt("10F"); + Assert.assertEquals(10, number); + + number = NumberUtil.parseInt("22.4D"); + Assert.assertEquals(22, number); + + number = NumberUtil.parseInt("22.6D"); + Assert.assertEquals(22, number); + + number = NumberUtil.parseInt("0"); + Assert.assertEquals(0, number); + + number = NumberUtil.parseInt(".123"); + Assert.assertEquals(0, number); } @Test @@ -236,22 +254,40 @@ public class NumberUtilTest { // 千位分隔符去掉 int v1 = NumberUtil.parseNumber("1,482.00").intValue(); Assert.assertEquals(1482, v1); + + Number v2 = NumberUtil.parseNumber("1,482.00D"); + Assert.assertEquals(1482L, v2); } @Test public void parseLongTest() { - long v1 = NumberUtil.parseLong("0xFF"); - Assert.assertEquals(255L, v1); - long v2 = NumberUtil.parseLong("010"); - Assert.assertEquals(10L, v2); - long v3 = NumberUtil.parseLong("10"); - Assert.assertEquals(10L, v3); - long v4 = NumberUtil.parseLong(" "); - Assert.assertEquals(0L, v4); - long v5 = NumberUtil.parseLong("10F"); - Assert.assertEquals(10L, v5); - long v6 = NumberUtil.parseLong("22.4D"); - Assert.assertEquals(22L, v6); + long number = NumberUtil.parseLong("0xFF"); + Assert.assertEquals(255, number); + + // 0开头 + number = NumberUtil.parseLong("010"); + Assert.assertEquals(10, number); + + number = NumberUtil.parseLong("10"); + Assert.assertEquals(10, number); + + number = NumberUtil.parseLong(" "); + Assert.assertEquals(0, number); + + number = NumberUtil.parseLong("10F"); + Assert.assertEquals(10, number); + + number = NumberUtil.parseLong("22.4D"); + Assert.assertEquals(22, number); + + number = NumberUtil.parseLong("22.6D"); + Assert.assertEquals(22, number); + + number = NumberUtil.parseLong("0"); + Assert.assertEquals(0, number); + + number = NumberUtil.parseLong(".123"); + Assert.assertEquals(0, number); } @Test diff --git a/hutool-core/src/test/java/cn/hutool/core/util/RuntimeUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/RuntimeUtilTest.java index 4e45a6384..21accb091 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/RuntimeUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/RuntimeUtilTest.java @@ -1,11 +1,10 @@ package cn.hutool.core.util; +import cn.hutool.core.lang.Console; +import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; -import cn.hutool.core.lang.Console; -import cn.hutool.core.util.RuntimeUtil; - /** * 命令行单元测试 * @author looly @@ -26,4 +25,9 @@ public class RuntimeUtilTest { String str = RuntimeUtil.execForStr("cmd /c dir"); Console.log(str); } + + @Test + public void getUsableMemoryTest(){ + Assert.assertTrue(RuntimeUtil.getUsableMemory() > 0); + } } diff --git a/hutool-cron/pom.xml b/hutool-cron/pom.xml index 199014a90..8cc3acdb4 100644 --- a/hutool-cron/pom.xml +++ b/hutool-cron/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-cron diff --git a/hutool-crypto/pom.xml b/hutool-crypto/pom.xml index 7f20e5415..4b94e5c61 100644 --- a/hutool-crypto/pom.xml +++ b/hutool-crypto/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-crypto diff --git a/hutool-db/pom.xml b/hutool-db/pom.xml index 0000e4a96..7c6db64f1 100644 --- a/hutool-db/pom.xml +++ b/hutool-db/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-db @@ -21,12 +21,12 @@ 0.9.5.5 2.8.0 9.0.30 - 1.2.3 + 1.2.4 2.4.13 3.12.7 - 3.32.3.2 + 3.34.0 2.5.1 - 3.3.0 + 3.4.1 diff --git a/hutool-db/src/main/java/cn/hutool/db/handler/HandleHelper.java b/hutool-db/src/main/java/cn/hutool/db/handler/HandleHelper.java index 5fb86e344..0a3ce2a95 100644 --- a/hutool-db/src/main/java/cn/hutool/db/handler/HandleHelper.java +++ b/hutool-db/src/main/java/cn/hutool/db/handler/HandleHelper.java @@ -154,7 +154,12 @@ public class HandleHelper { row.put(meta.getColumnLabel(i), getColumnValue(rs, i, type, null)); } if (withMetaInfo) { - row.setTableName(meta.getTableName(1)); + try { + row.setTableName(meta.getTableName(1)); + } catch (SQLException ignore){ + //issue#I2AGLU@Gitee + // Hive等NoSQL中无表的概念,此处报错,跳过。 + } row.setFieldNames(row.keySet()); } return row; diff --git a/hutool-db/src/main/java/cn/hutool/db/nosql/redis/RedisDS.java b/hutool-db/src/main/java/cn/hutool/db/nosql/redis/RedisDS.java index d32603fd1..325be3487 100644 --- a/hutool-db/src/main/java/cn/hutool/db/nosql/redis/RedisDS.java +++ b/hutool-db/src/main/java/cn/hutool/db/nosql/redis/RedisDS.java @@ -9,6 +9,7 @@ import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.Protocol; import java.io.Closeable; +import java.io.Serializable; /** * Jedis数据源 @@ -16,7 +17,8 @@ import java.io.Closeable; * @author looly * @since 3.2.3 */ -public class RedisDS implements Closeable{ +public class RedisDS implements Closeable, Serializable { + private static final long serialVersionUID = -5605411972456177456L; /** 默认配置文件 */ public final static String REDIS_CONFIG_PATH = "config/redis.setting"; @@ -29,7 +31,7 @@ public class RedisDS implements Closeable{ /** * 创建RedisDS,使用默认配置文件,默认分组 * - * @return {@link RedisDS} + * @return RedisDS */ public static RedisDS create() { return new RedisDS(); @@ -39,7 +41,7 @@ public class RedisDS implements Closeable{ * 创建RedisDS,使用默认配置文件 * * @param group 配置文件中配置分组 - * @return {@link RedisDS} + * @return RedisDS */ public static RedisDS create(String group) { return new RedisDS(group); @@ -50,7 +52,7 @@ public class RedisDS implements Closeable{ * * @param setting 配置文件 * @param group 配置文件中配置分组 - * @return {@link RedisDS} + * @return RedisDS */ public static RedisDS create(Setting setting, String group) { return new RedisDS(setting, group); diff --git a/hutool-dfa/pom.xml b/hutool-dfa/pom.xml index 8aa56dbed..8355567b9 100644 --- a/hutool-dfa/pom.xml +++ b/hutool-dfa/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-dfa diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml index 462d16f71..600ad2bd6 100644 --- a/hutool-extra/pom.xml +++ b/hutool-extra/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-extra @@ -19,18 +19,18 @@ 2.2 - 3.2.4.RELEASE + 3.3.1.RELEASE 1.3.0 2.3.30 4.9.03 - 3.0.11.RELEASE + 3.0.12.RELEASE 1.6.2 0.1.55 3.4.1 3.7.2 5.1.1 4.0.1 - 2.4.0 + 2.4.1 3.3.0 @@ -406,7 +406,7 @@ org.mvel mvel2 - 2.4.10.Final + 2.4.11.Final compile true @@ -420,7 +420,7 @@ org.springframework spring-expression - 5.3.1 + 5.3.2 compile true diff --git a/hutool-extra/src/main/java/cn/hutool/extra/mail/Mail.java b/hutool-extra/src/main/java/cn/hutool/extra/mail/Mail.java index 51a875f35..124fc2068 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/mail/Mail.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/mail/Mail.java @@ -81,7 +81,7 @@ public class Mail { * 创建邮件客户端 * * @param mailAccount 邮件帐号 - * @return {@link Mail} + * @return Mail */ public static Mail create(MailAccount mailAccount) { return new Mail(mailAccount); @@ -90,7 +90,7 @@ public class Mail { /** * 创建邮件客户端,使用全局邮件帐户 * - * @return {@link Mail} + * @return Mail */ public static Mail create() { return new Mail(); diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml index 7518587a1..86ad23761 100644 --- a/hutool-http/pom.xml +++ b/hutool-http/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-http diff --git a/hutool-http/src/test/java/cn/hutool/http/HttpRequestTest.java b/hutool-http/src/test/java/cn/hutool/http/HttpRequestTest.java index 66a37197f..aabf78763 100644 --- a/hutool-http/src/test/java/cn/hutool/http/HttpRequestTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/HttpRequestTest.java @@ -9,8 +9,6 @@ import cn.hutool.json.JSONUtil; import org.junit.Ignore; import org.junit.Test; -import java.net.Authenticator; -import java.net.PasswordAuthentication; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -142,26 +140,4 @@ public class HttpRequestTest { HttpResponse execute = get.execute(); Console.log(execute.body()); } - - @Test - public void getByProxy(){ - System.setProperty("jdk.http.auth.tunneling.disabledSchemes", ""); - - // 用户名密码, 若已添加白名单则不需要添加 - final String ProxyUser = "t10757311156848"; - final String ProxyPass = "ikm5uu44"; - - Authenticator.setDefault(new Authenticator() { - public PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(ProxyUser, ProxyPass.toCharArray()); - } - }); - - final HttpResponse res = HttpRequest.get("https://httpbin.org/get") - .basicAuth(ProxyUser, ProxyPass) - .setHttpProxy("tps193.kdlapi.com", 15818).execute(); - - Console.log(res.body()); - } - } diff --git a/hutool-json/pom.xml b/hutool-json/pom.xml index 7b0401562..03f1f8a2b 100644 --- a/hutool-json/pom.xml +++ b/hutool-json/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-json diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java index 79d89eb4a..4d599d1c0 100644 --- a/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java @@ -170,5 +170,4 @@ public class JSONUtilTest { " \"test\": \"\\\\地库地库\",\n" + "}"); } -} - +} \ No newline at end of file diff --git a/hutool-log/pom.xml b/hutool-log/pom.xml index 78e10dfab..c72232813 100644 --- a/hutool-log/pom.xml +++ b/hutool-log/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-log @@ -92,7 +92,7 @@ org.tinylog tinylog-impl - 2.1.2 + 2.2.0 test diff --git a/hutool-poi/pom.xml b/hutool-poi/pom.xml index 0f06fb0bb..86e4d5225 100644 --- a/hutool-poi/pom.xml +++ b/hutool-poi/pom.xml @@ -8,7 +8,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-poi diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelDateUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelDateUtil.java new file mode 100644 index 000000000..fb6349036 --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelDateUtil.java @@ -0,0 +1,70 @@ +package cn.hutool.poi.excel; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import org.apache.poi.ss.formula.ConditionalFormattingEvaluator; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.ExcelNumberFormat; + +/** + * Excel中日期判断、读取、处理等补充工具类 + * + * @author looly + * @since 5.5.5 + */ +public class ExcelDateUtil { + + /** + * 某些特殊的自定义日期格式 + */ + private static final int[] customFormats = new int[]{28, 30, 31, 32, 33, 55, 56, 57, 58}; + + public static boolean isDateFormat(Cell cell){ + return isDateFormat(cell, null); + } + + /** + * 判断是否日期格式 + * @param cell 单元格 + * @param cfEvaluator {@link ConditionalFormattingEvaluator} + * @return 是否日期格式 + */ + public static boolean isDateFormat(Cell cell, ConditionalFormattingEvaluator cfEvaluator){ + final ExcelNumberFormat nf = ExcelNumberFormat.from(cell, cfEvaluator); + return isDateFormat(nf); + } + + /** + * 判断是否日期格式 + * @param numFmt {@link ExcelNumberFormat} + * @return 是否日期格式 + */ + public static boolean isDateFormat(ExcelNumberFormat numFmt) { + return isDateFormat(numFmt.getIdx(), numFmt.getFormat()); + } + + /** + * 判断日期格式 + * + * @param formatIndex 格式索引,一般用于内建格式 + * @param formatString 格式字符串 + * @return 是否为日期格式 + * @since 5.5.3 + */ + public static boolean isDateFormat(int formatIndex, String formatString) { + // issue#1283@Github + if (ArrayUtil.contains(customFormats, formatIndex)) { + return true; + } + + // 自定义格式判断 + if (StrUtil.isNotEmpty(formatString) && + StrUtil.containsAny(formatString, "周", "星期", "aa")) { + // aa -> 周一 + // aaa -> 星期一 + return true; + } + + return org.apache.poi.ss.usermodel.DateUtil.isADateFormat(formatIndex, formatString); + } +} 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 2b71e08aa..390e297f8 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 @@ -3,6 +3,7 @@ package cn.hutool.poi.excel.cell; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.poi.excel.ExcelDateUtil; import cn.hutool.poi.excel.ExcelUtil; import cn.hutool.poi.excel.StyleSet; import cn.hutool.poi.excel.editors.TrimEditor; @@ -102,7 +103,7 @@ public class CellUtil { if (null == cell) { return null; } - if(cell instanceof NullCell){ + if (cell instanceof NullCell) { return null == cellEditor ? null : cellEditor.edit(cell, null); } if (null == cellType) { @@ -111,7 +112,7 @@ public class CellUtil { // 尝试获取合并单元格,如果是合并单元格,则重新获取单元格类型 final Cell mergedCell = getMergedRegionCell(cell); - if(mergedCell != cell){ + if (mergedCell != cell) { cell = mergedCell; cellType = cell.getCellTypeEnum(); } @@ -235,7 +236,7 @@ public class CellUtil { } /** - *获取单元格,如果单元格不存在,返回{@link NullCell} + * 获取单元格,如果单元格不存在,返回{@link NullCell} * * @param row Excel表的行 * @param cellIndex 列号 @@ -377,7 +378,7 @@ public class CellUtil { * @since 5.1.5 */ public static Cell getMergedRegionCell(Cell cell) { - if(null == cell){ + if (null == cell) { return null; } return ObjectUtil.defaultIfNull( @@ -404,10 +405,10 @@ public class CellUtil { /** * 为特定单元格添加批注 * - * @param cell 单元格 - * @param commentText 批注内容 + * @param cell 单元格 + * @param commentText 批注内容 * @param commentAuthor 作者 - * @param anchor 批注的位置、大小等信息,null表示使用默认 + * @param anchor 批注的位置、大小等信息,null表示使用默认 * @since 5.4.8 */ public static void setComment(Cell cell, String commentText, String commentAuthor, ClientAnchor anchor) { @@ -431,16 +432,16 @@ public class CellUtil { // -------------------------------------------------------------------------------------------------------------- Private method start /** - * 获取合并单元格,非合并单元格返回null
+ * 获取合并单元格,非合并单元格返回{@code null}
* 传入的x,y坐标(列行数)可以是合并单元格范围内的任意一个单元格 * * @param sheet {@link Sheet} * @param x 列号,从0开始,可以是合并单元格范围中的任意一列 * @param y 行号,从0开始,可以是合并单元格范围中的任意一行 - * @return 合并单元格,如果非合并单元格,返回null + * @return 合并单元格,如果非合并单元格,返回{@code null} * @since 5.4.5 */ - private static Cell getCellIfMergedRegion(Sheet sheet, int x, int y){ + private static Cell getCellIfMergedRegion(Sheet sheet, int x, int y) { final int sheetMergeCount = sheet.getNumMergedRegions(); CellRangeAddress ca; for (int i = 0; i < sheetMergeCount; i++) { @@ -463,9 +464,8 @@ public class CellUtil { final CellStyle style = cell.getCellStyle(); if (null != style) { - final short formatIndex = style.getDataFormat(); // 判断是否为日期 - if (isDateType(cell, formatIndex)) { + if (ExcelDateUtil.isDateFormat(cell)) { return DateUtil.date(cell.getDateCellValue());// 使用Hutool的DateTime包装 } @@ -483,32 +483,5 @@ public class CellUtil { // 某些Excel单元格值为double计算结果,可能导致精度问题,通过转换解决精度问题。 return Double.parseDouble(NumberToTextConverter.toText(value)); } - - /** - * 是否为日期格式
- * 判断方式: - * - *
-	 * 1、指定序号
-	 * 2、org.apache.poi.ss.usermodel.DateUtil.isADateFormat方法判定
-	 * 
- * - * @param cell 单元格 - * @param formatIndex 格式序号 - * @return 是否为日期格式 - */ - private static boolean isDateType(Cell cell, int formatIndex) { - // yyyy-MM-dd----- 14 - // yyyy年m月d日---- 31 - // yyyy年m月------- 57 - // m月d日 ---------- 58 - // HH:mm----------- 20 - // h时mm分 -------- 32 - if (formatIndex == 14 || formatIndex == 31 || formatIndex == 57 || formatIndex == 58 || formatIndex == 20 || formatIndex == 32) { - return true; - } - - return org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell); - } // -------------------------------------------------------------------------------------------------------------- Private method end } diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java index dbd97dd04..38e4600eb 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java @@ -1,6 +1,7 @@ package cn.hutool.poi.excel.sax; import cn.hutool.core.io.IoUtil; +import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.poi.excel.sax.handler.RowHandler; @@ -116,12 +117,12 @@ public class Excel03SaxReader implements HSSFListener, ExcelSaxReader + *
  • 传入'rId'开头,直接去除rId前缀
  • + *
  • 传入纯数字,表示sheetIndex,直接转换为rid
  • + * + * + * @param idOrRidOrSheetName Excel中的sheet id或者rid编号或sheet名称,从0开始,rid必须加rId前缀,例如rId0,如果为-1处理所有编号的sheet + * @return sheet索引,从0开始 + * @since 5.5.5 + */ + private int getSheetIndex(String idOrRidOrSheetName) { + Assert.notBlank(idOrRidOrSheetName, "id or rid or sheetName must be not blank!"); + + // rid直接处理 + if (StrUtil.startWithIgnoreCase(idOrRidOrSheetName, RID_PREFIX)) { + return Integer.parseInt(StrUtil.removePrefixIgnoreCase(idOrRidOrSheetName, RID_PREFIX)); + } + + final int sheetIndex; + try { + return Integer.parseInt(idOrRidOrSheetName); + } catch (NumberFormatException ignore) { + throw new IllegalArgumentException("Invalid sheet id: " + idOrRidOrSheetName); + } + } // ---------------------------------------------------------------------------------------------- Private method end } diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java index c89a1bd33..1c8c60093 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java @@ -2,7 +2,6 @@ package cn.hutool.poi.excel.sax; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.poi.excel.sax.handler.RowHandler; import cn.hutool.poi.exceptions.POIException; @@ -25,8 +24,6 @@ import java.util.Iterator; */ public class Excel07SaxReader implements ExcelSaxReader { - // sheet r:Id前缀 - private static final String RID_PREFIX = "rId"; private final SheetDataSaxHandler handler; /** @@ -56,9 +53,9 @@ public class Excel07SaxReader implements ExcelSaxReader { } @Override - public Excel07SaxReader read(File file, String idOrRid) throws POIException { + public Excel07SaxReader read(File file, String idOrRidOrSheetName) throws POIException { try { - return read(OPCPackage.open(file), idOrRid); + return read(OPCPackage.open(file), idOrRidOrSheetName); } catch (InvalidFormatException e) { throw new POIException(e); } @@ -70,9 +67,9 @@ public class Excel07SaxReader implements ExcelSaxReader { } @Override - public Excel07SaxReader read(InputStream in, String idOrRid) throws POIException { + public Excel07SaxReader read(InputStream in, String idOrRidOrSheetName) throws POIException { try (final OPCPackage opcPackage = OPCPackage.open(in)) { - return read(opcPackage, idOrRid); + return read(opcPackage, idOrRidOrSheetName); } catch (IOException e) { throw new IORuntimeException(e); } catch (InvalidFormatException e) { @@ -96,13 +93,13 @@ public class Excel07SaxReader implements ExcelSaxReader { * 开始读取Excel,Sheet编号从0开始计数 * * @param opcPackage {@link OPCPackage},Excel包,读取后不关闭 - * @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet + * @param idOrRidOrSheetName Excel中的sheet id或者rid编号或sheet名,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet * @return this * @throws POIException POI异常 */ - public Excel07SaxReader read(OPCPackage opcPackage, String idOrRid) throws POIException { + public Excel07SaxReader read(OPCPackage opcPackage, String idOrRidOrSheetName) throws POIException { try { - return read(new XSSFReader(opcPackage), idOrRid); + return read(new XSSFReader(opcPackage), idOrRidOrSheetName); } catch (OpenXML4JException e) { throw new POIException(e); } catch (IOException e) { @@ -114,12 +111,12 @@ public class Excel07SaxReader implements ExcelSaxReader { * 开始读取Excel,Sheet编号从0开始计数 * * @param xssfReader {@link XSSFReader},Excel读取器 - * @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet + * @param idOrRidOrSheetName Excel中的sheet id或者rid编号或sheet名,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet * @return this * @throws POIException POI异常 * @since 5.4.4 */ - public Excel07SaxReader read(XSSFReader xssfReader, String idOrRid) throws POIException { + public Excel07SaxReader read(XSSFReader xssfReader, String idOrRidOrSheetName) throws POIException { // 获取共享样式表,样式非必须 try { this.handler.stylesTable = xssfReader.getStylesTable(); @@ -136,7 +133,7 @@ public class Excel07SaxReader implements ExcelSaxReader { throw new POIException(e); } - return readSheets(xssfReader, idOrRid); + return readSheets(xssfReader, idOrRidOrSheetName); } // ------------------------------------------------------------------------------ Read end @@ -145,22 +142,14 @@ public class Excel07SaxReader implements ExcelSaxReader { /** * 开始读取Excel,Sheet编号从0开始计数 * - * @param xssfReader {@link XSSFReader},Excel读取器 - * @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId0,如果为-1处理所有编号的sheet + * @param xssfReader {@link XSSFReader},Excel读取器 + * @param idOrRidOrSheetName Excel中的sheet id或者rid编号或sheet名,从0开始,rid必须加rId前缀,例如rId0,如果为-1处理所有编号的sheet * @return this * @throws POIException POI异常 * @since 5.4.4 */ - private Excel07SaxReader readSheets(XSSFReader xssfReader, String idOrRid) throws POIException { - // 将sheetId转换为rid - if (NumberUtil.isInteger(idOrRid)) { - final SheetRidReader ridReader = new SheetRidReader(); - final String rid = ridReader.read(xssfReader).getRidBySheetId(idOrRid); - if (StrUtil.isNotEmpty(rid)) { - idOrRid = rid; - } - } - this.handler.sheetIndex = Integer.parseInt(StrUtil.removePrefixIgnoreCase(idOrRid, RID_PREFIX)); + private Excel07SaxReader readSheets(XSSFReader xssfReader, String idOrRidOrSheetName) throws POIException { + this.handler.sheetIndex = getSheetIndex(xssfReader, idOrRidOrSheetName); InputStream sheetInputStream = null; try { if (this.handler.sheetIndex > -1) { @@ -190,5 +179,44 @@ public class Excel07SaxReader implements ExcelSaxReader { } return this; } + + /** + * 获取sheet索引,从0开始 + *
      + *
    • 传入'rId'开头,直接去除rId前缀
    • + *
    • 传入纯数字,表示sheetIndex,通过{@link SheetRidReader}转换为rId
    • + *
    • 传入其它字符串,表示sheetName,通过{@link SheetRidReader}转换为rId
    • + *
    + * + * @param xssfReader {@link XSSFReader},Excel读取器 + * @param idOrRidOrSheetName Excel中的sheet id或者rid编号或sheet名称,从0开始,rid必须加rId前缀,例如rId0,如果为-1处理所有编号的sheet + * @return sheet索引,从0开始 + * @since 5.5.5 + */ + private int getSheetIndex(XSSFReader xssfReader, String idOrRidOrSheetName) { + // rid直接处理 + if (StrUtil.startWithIgnoreCase(idOrRidOrSheetName, RID_PREFIX)) { + return Integer.parseInt(StrUtil.removePrefixIgnoreCase(idOrRidOrSheetName, RID_PREFIX)); + } + + // sheetIndex需转换为rid + final SheetRidReader ridReader = new SheetRidReader().read(xssfReader); + + final int sheetIndex; + Integer rid; + try { + sheetIndex = Integer.parseInt(idOrRidOrSheetName); + rid = ridReader.getRidBySheetIdBase0(sheetIndex); + return (null != rid) ? rid : sheetIndex; + } catch (NumberFormatException ignore) { + // 非数字,可能为sheet名称 + rid = ridReader.getRidByNameBase0(idOrRidOrSheetName); + if (null != rid) { + return rid; + } + } + + throw new IllegalArgumentException("Invalid rId or id or sheetName: " + idOrRidOrSheetName); + } // --------------------------------------------------------------------------------------- Private method end } \ No newline at end of file diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxReader.java index c6369fa24..da97140e9 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxReader.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxReader.java @@ -15,6 +15,9 @@ import java.io.InputStream; */ public interface ExcelSaxReader { + // sheet r:Id前缀 + String RID_PREFIX = "rId"; + /** * 开始读取Excel * diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java index 5f50f9c12..e92095674 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxUtil.java @@ -6,6 +6,7 @@ import cn.hutool.core.exceptions.DependencyException; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.poi.excel.ExcelDateUtil; import cn.hutool.poi.excel.sax.handler.RowHandler; import cn.hutool.poi.exceptions.POIException; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; @@ -209,16 +210,10 @@ public class ExcelSaxUtil { * @param formatString 格式字符串 * @return 是否为日期格式 * @since 5.5.3 + * @see ExcelDateUtil#isDateFormat(int, String) */ public static boolean isDateFormat(int formatIndex, String formatString) { - // https://blog.csdn.net/u014342130/article/details/50619503 - // issue#1283@Github - if (formatIndex == 28 || formatIndex == 31) { - // 28 -> m月d日 - // 31 -> yyyy年m月d日 - return true; - } - return org.apache.poi.ss.usermodel.DateUtil.isADateFormat(formatIndex, formatString); + return ExcelDateUtil.isDateFormat(formatIndex, formatString); } /** diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/SheetDataSaxHandler.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/SheetDataSaxHandler.java index c703691e9..811e1f6cc 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/SheetDataSaxHandler.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/SheetDataSaxHandler.java @@ -29,7 +29,7 @@ public class SheetDataSaxHandler extends DefaultHandler { protected StylesTable stylesTable; // excel 2007 的共享字符串表,对应sharedString.xml protected SharedStringsTable sharedStringsTable; - // sheet的索引 + // sheet的索引,从0开始 protected int sheetIndex; // 当前非空行 diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/SheetRidReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/SheetRidReader.java index abe9b7176..56c744ec9 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/SheetRidReader.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/SheetRidReader.java @@ -17,7 +17,7 @@ import java.util.Map; /** * 在Sax方式读取Excel时,读取sheet标签中sheetId和rid的对应关系,类似于: *
    - * <sheet name="Sheet6" sheetId="4" r:id="6"/>
    + * <sheet name="Sheet6" sheetId="4" r:id="rId6"/>
      * 
    *

    * 读取结果为: @@ -36,8 +36,8 @@ public class SheetRidReader extends DefaultHandler { private final static String SHEET_ID_ATTR = "sheetId"; private final static String NAME_ATTR = "name"; - private final Map ID_RID_MAP = new HashMap<>(); - private final Map NAME_RID_MAP = new HashMap<>(); + private final Map ID_RID_MAP = new HashMap<>(); + private final Map NAME_RID_MAP = new HashMap<>(); /** * 读取Wordkbook的XML中sheet标签中sheetId和rid的对应关系 @@ -61,50 +61,74 @@ public class SheetRidReader extends DefaultHandler { } /** - * 根据sheetId获取rid + * 根据sheetId获取rid,从1开始 * - * @param sheetId Sheet的ID - * @return rid + * @param sheetId Sheet的ID,从1开始 + * @return rid,从1开始 */ - public String getRidBySheetId(String sheetId) { + public Integer getRidBySheetId(int sheetId) { return ID_RID_MAP.get(sheetId); } /** - * 根据sheet name获取rid + * 根据sheetId获取rid,从0开始 + * + * @param sheetId Sheet的ID,从0开始 + * @return rid,从0开始 + * @since 5.5.5 + */ + public Integer getRidBySheetIdBase0(int sheetId) { + final Integer rid = getRidBySheetId(sheetId + 1); + if(null != rid){ + return rid - 1; + } + return null; + } + + /** + * 根据sheet name获取rid,从1开始 * * @param sheetName Sheet的name - * @return rid + * @return rid,从1开始 */ - public String getRidByName(String sheetName) { + public Integer getRidByName(String sheetName) { return NAME_RID_MAP.get(sheetName); } + /** + * 根据sheet name获取rid,从0开始 + * + * @param sheetName Sheet的name + * @return rid,从0开始 + * @since 5.5.5 + */ + public Integer getRidByNameBase0(String sheetName) { + final Integer rid = getRidByName(sheetName); + if(null != rid){ + return rid - 1; + } + return null; + } + @Override public void startElement(String uri, String localName, String qName, Attributes attributes) { if (TAG_NAME.equalsIgnoreCase(localName)) { - final int length = attributes.getLength(); - String sheetId = null; - String rid = null; - String name = null; - for (int i = 0; i < length; i++) { - switch (attributes.getLocalName(i)) { - case SHEET_ID_ATTR: - sheetId = attributes.getValue(i); - break; - case RID_ATTR: - rid = attributes.getValue(i); - break; - case NAME_ATTR: - name = attributes.getValue(i); - break; - } - if (StrUtil.isNotEmpty(sheetId)) { - ID_RID_MAP.put(sheetId, rid); - } - if (StrUtil.isNotEmpty(name)) { - NAME_RID_MAP.put(name, rid); - } + final String ridStr = attributes.getValue(SHEET_ID_ATTR); + if(StrUtil.isEmpty(ridStr)){ + return; + } + final int rid = Integer.parseInt(StrUtil.removePrefixIgnoreCase(ridStr, Excel07SaxReader.RID_PREFIX)); + + // sheet名和rid映射 + final String name = attributes.getValue(NAME_ATTR); + if (StrUtil.isNotEmpty(name)) { + NAME_RID_MAP.put(name, rid); + } + + // sheetId和rid映射 + final String sheetIdStr = attributes.getValue(SHEET_ID_ATTR); + if(StrUtil.isNotEmpty(sheetIdStr)){ + ID_RID_MAP.put(Integer.parseInt(sheetIdStr), rid); } } } diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/style/StyleUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/style/StyleUtil.java index 880764166..ab9fc3a57 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/style/StyleUtil.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/style/StyleUtil.java @@ -1,8 +1,10 @@ package cn.hutool.poi.excel.style; +import cn.hutool.core.util.StrUtil; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.DataFormat; import org.apache.poi.ss.usermodel.FillPatternType; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.HorizontalAlignment; @@ -10,20 +12,18 @@ import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.Workbook; -import cn.hutool.core.util.StrUtil; - /** * Excel样式工具类 - * + * * @author looly * @since 4.0.0 */ public class StyleUtil { - + /** * 克隆新的{@link CellStyle} - * - * @param cell 单元格 + * + * @param cell 单元格 * @param cellStyle 被复制的样式 * @return {@link CellStyle} */ @@ -33,8 +33,8 @@ public class StyleUtil { /** * 克隆新的{@link CellStyle} - * - * @param workbook 工作簿 + * + * @param workbook 工作簿 * @param cellStyle 被复制的样式 * @return {@link CellStyle} */ @@ -43,13 +43,13 @@ public class StyleUtil { newCellStyle.cloneStyleFrom(cellStyle); return newCellStyle; } - + /** * 设置cell文本对齐样式 - * + * * @param cellStyle {@link CellStyle} - * @param halign 横向位置 - * @param valign 纵向位置 + * @param halign 横向位置 + * @param valign 纵向位置 * @return {@link CellStyle} */ public static CellStyle setAlign(CellStyle cellStyle, HorizontalAlignment halign, VerticalAlignment valign) { @@ -60,8 +60,8 @@ public class StyleUtil { /** * 设置cell的四个边框粗细和颜色 - * - * @param cellStyle {@link CellStyle} + * + * @param cellStyle {@link CellStyle} * @param borderSize 边框粗细{@link BorderStyle}枚举 * @param colorIndex 颜色的short值 * @return {@link CellStyle} @@ -81,12 +81,12 @@ public class StyleUtil { return cellStyle; } - + /** * 给cell设置颜色 - * - * @param cellStyle {@link CellStyle} - * @param color 背景颜色 + * + * @param cellStyle {@link CellStyle} + * @param color 背景颜色 * @param fillPattern 填充方式 {@link FillPatternType}枚举 * @return {@link CellStyle} */ @@ -96,9 +96,9 @@ public class StyleUtil { /** * 给cell设置颜色 - * - * @param cellStyle {@link CellStyle} - * @param color 背景颜色 + * + * @param cellStyle {@link CellStyle} + * @param color 背景颜色 * @param fillPattern 填充方式 {@link FillPatternType}枚举 * @return {@link CellStyle} */ @@ -107,12 +107,12 @@ public class StyleUtil { cellStyle.setFillPattern(fillPattern); return cellStyle; } - + /** * 创建字体 - * + * * @param workbook {@link Workbook} - * @param color 字体颜色 + * @param color 字体颜色 * @param fontSize 字体大小 * @param fontName 字体名称,可以为null使用默认字体 * @return {@link Font} @@ -121,24 +121,24 @@ public class StyleUtil { final Font font = workbook.createFont(); return setFontStyle(font, color, fontSize, fontName); } - + /** * 设置字体样式 - * - * @param font 字体{@link Font} - * @param color 字体颜色 + * + * @param font 字体{@link Font} + * @param color 字体颜色 * @param fontSize 字体大小 * @param fontName 字体名称,可以为null使用默认字体 * @return {@link Font} */ public static Font setFontStyle(Font font, short color, short fontSize, String fontName) { - if(color > 0) { + if (color > 0) { font.setColor(color); } - if(fontSize > 0) { + if (fontSize > 0) { font.setFontHeightInPoints(fontSize); } - if(StrUtil.isNotBlank(fontName)) { + if (StrUtil.isNotBlank(fontName)) { font.setFontName(fontName); } return font; @@ -153,7 +153,7 @@ public class StyleUtil { * @since 5.4.0 */ public static CellStyle createCellStyle(Workbook workbook) { - if(null == workbook){ + if (null == workbook) { return null; } return workbook.createCellStyle(); @@ -161,12 +161,12 @@ public class StyleUtil { /** * 创建默认普通单元格样式 - * + * *

     	 * 1. 文字上下左右居中
     	 * 2. 细边框,黑色
     	 * 
    - * + * * @param workbook {@link Workbook} 工作簿 * @return {@link CellStyle} */ @@ -179,7 +179,7 @@ public class StyleUtil { /** * 创建默认头部样式 - * + * * @param workbook {@link Workbook} 工作簿 * @return {@link CellStyle} */ @@ -190,15 +190,28 @@ public class StyleUtil { setColor(cellStyle, IndexedColors.GREY_25_PERCENT, FillPatternType.SOLID_FOREGROUND); return cellStyle; } - + /** - * 给定样式是否为null(无样式)或默认样式,默认样式为workbook.getCellStyleAt(0) + * 给定样式是否为null(无样式)或默认样式,默认样式为{@code workbook.getCellStyleAt(0)} + * * @param workbook 工作簿 - * @param style 被检查的样式 + * @param style 被检查的样式 * @return 是否为null(无样式)或默认样式 * @since 4.6.3 */ public static boolean isNullOrDefaultStyle(Workbook workbook, CellStyle style) { return (null == style) || style.equals(workbook.getCellStyleAt(0)); } + + /** + * 创建数据格式并获取格式 + * + * @param format 数据格式 + * @return 数据格式 + * @since 5.5.5 + */ + public Short getFormat(Workbook workbook, String format) { + final DataFormat dataFormat = workbook.createDataFormat(); + return dataFormat.getFormat(format); + } } diff --git a/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java b/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java index 4d5ef39f8..8ac66a995 100644 --- a/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java @@ -58,9 +58,19 @@ public class ExcelSaxReadTest { @Test public void readBySaxTest() { + ExcelUtil.readBySax("blankAndDateTest.xlsx", "0", createRowHandler()); + } + + @Test + public void readBySaxByRidTest() { ExcelUtil.readBySax("blankAndDateTest.xlsx", 0, createRowHandler()); } + @Test + public void readBySaxByNameTest() { + ExcelUtil.readBySax("blankAndDateTest.xlsx", "Sheet1", createRowHandler()); + } + @Test @Ignore public void readBySaxTest2() { @@ -164,6 +174,14 @@ public class ExcelSaxReadTest { Assert.assertEquals("2012-12-21 00:00:00", rows.get(4)); } + @Test + @Ignore + public void dateReadXlsxTest2() { + ExcelUtil.readBySax("d:/test/custom_date_format2.xlsx", 0, + (i, i1, list) -> Console.log(list) + ); + } + @Test @Ignore public void readBlankTest() { diff --git a/hutool-script/pom.xml b/hutool-script/pom.xml index 60c38c5b8..3e08508e3 100644 --- a/hutool-script/pom.xml +++ b/hutool-script/pom.xml @@ -8,7 +8,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-script @@ -18,7 +18,7 @@ 2.7.2 3.0.1 - 3.0.6 + 3.0.7 diff --git a/hutool-setting/pom.xml b/hutool-setting/pom.xml index 975b734c7..525d898ef 100644 --- a/hutool-setting/pom.xml +++ b/hutool-setting/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-setting diff --git a/hutool-setting/src/main/java/cn/hutool/setting/dialect/PropsUtil.java b/hutool-setting/src/main/java/cn/hutool/setting/dialect/PropsUtil.java index a8a121c63..3c274c0f3 100644 --- a/hutool-setting/src/main/java/cn/hutool/setting/dialect/PropsUtil.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/dialect/PropsUtil.java @@ -40,9 +40,9 @@ public class PropsUtil { /** * 获取给定路径找到的第一个配置文件
    - * * name可以为不包括扩展名的文件名(默认.setting为结尾),也可以是文件名全称 + * * name可以为不包括扩展名的文件名(默认.properties为结尾),也可以是文件名全称 * - * @param names 文件名,如果没有扩展名,默认为.setting + * @param names 文件名,如果没有扩展名,默认为.properties * * @return 当前环境下配置文件 */ diff --git a/hutool-socket/pom.xml b/hutool-socket/pom.xml index 0c565c437..4d116860d 100644 --- a/hutool-socket/pom.xml +++ b/hutool-socket/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-socket diff --git a/hutool-system/pom.xml b/hutool-system/pom.xml index 4d88fb9e5..d9fb303d3 100644 --- a/hutool-system/pom.xml +++ b/hutool-system/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool-system @@ -26,7 +26,7 @@ com.github.oshi oshi-core - 5.3.6 + 5.3.7 provided
    diff --git a/pom.xml b/pom.xml index 8561b4443..3adc36402 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ cn.hutool hutool-parent - 5.5.4 + 5.5.5 hutool Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。 https://github.com/looly/hutool