diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d5d59309..44cb158c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.7.17 (2021-11-29) +# 5.7.17 (2021-12-06) ### 🐣新特性 * 【core 】 增加AsyncUtil(pr#457@Gitee) @@ -29,6 +29,10 @@ * 【core 】 CopyOptions增加override配置(issue#I4JQ1N@Gitee) * 【poi 】 SheetRidReader可以获取所有sheet名(issue#I4JA3M@Gitee) * 【core 】 AsyncUtil.waitAny增加返回值(pr#473@Gitee) +* 【core 】 Calculator.compare改为private(issue#1982@Github) +* 【core 】 NumberUtil增加isOdd、isEven方法(pr#474@Gitee) +* 【http 】 增加HttpGlobalConfig.setBoundary,删除MultipartBody.BOUNDARY和getContentType(issue#I4KSLY@Gitee) +* 【core 】 DateTime增加setMinimalDaysInFirstWeek(issue#1988@Github) * ### 🐞Bug修复 * 【core 】 修复FileResource构造fileName参数无效问题(issue#1942@Github) @@ -36,6 +40,13 @@ * 【core 】 修复ZipUtil相对路径父路径获取null问题(issue#1961@Github) * 【http 】 修复HttpUtil.normalizeParams未判空导致的问题(issue#1975@Github) * 【poi 】 修复读取日期类型的自定义样式单元格时间结果为1899年问题(pr#1977@Github) +* 【poi 】 修复SoapClient参数未使用问题 +* 【core 】 修复HashUtil.cityHash128参数未使用问题 +* 【core 】 修复DateUtil.formatChineseDate显示问题(issue#I4KK5F@Gitee) +* 【poi 】 修复CellUtil.setCellValuestyle空导致值无法写入问题(issue#1995@Github) +* 【poi 】 修复CellUtil.setComment参数设置错误问题 +* 【core 】 修复QueryBuilder解析路径导致的错误(issue#1989@Github) +* 【core 】 修复DateTime.between中DateUnit无效问题 ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java index 329c37d5d..94f4d357c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java @@ -1299,14 +1299,14 @@ public class CollUtil { * @param 集合元素类型 * @param resultCollection 存放移除结果的集合 * @param targetCollection 被操作移除元素的集合 - * @param filter 用于是否移除判断的过滤器 + * @param predicate 用于是否移除判断的过滤器 */ - public static , E> T removeWithAddIf(T targetCollection, T resultCollection, Predicate filter) { - Objects.requireNonNull(filter); + public static , E> T removeWithAddIf(T targetCollection, T resultCollection, Predicate predicate) { + Objects.requireNonNull(predicate); final Iterator each = targetCollection.iterator(); while (each.hasNext()) { E next = each.next(); - if (filter.test(next)) { + if (predicate.test(next)) { resultCollection.add(next); each.remove(); } @@ -1315,20 +1315,20 @@ public class CollUtil { } /** - * 移除集合中的多个元素,并将结果存放到生成的新集合中后返回 + * 移除集合中的多个元素,并将结果存放到生成的新集合中后返回
* 此方法直接修改原集合 * * @param 集合类型 * @param 集合元素类型 * @param targetCollection 被操作移除元素的集合 - * @param filter 用于是否移除判断的过滤器 + * @param predicate 用于是否移除判断的过滤器 * @return 移除结果的集合 + * @since 5.7.17 */ - @SuppressWarnings("unchecked") - public static , E> T removeWithAddIf(T targetCollection, Predicate filter) { - Collection resultCollection = new ArrayList<>(); - removeWithAddIf(targetCollection, resultCollection, filter); - return (T) resultCollection; + public static , E> List removeWithAddIf(T targetCollection, Predicate predicate) { + final List removed = new ArrayList<>(); + removeWithAddIf(targetCollection, removed, predicate); + return removed; } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/RingIndexUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/RingIndexUtil.java index b997b1428..34fd8c738 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/RingIndexUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/RingIndexUtil.java @@ -56,7 +56,8 @@ public class RingIndexUtil { } /** - * 通过cas操作 实现对指定值内的回环累加 + * 通过cas操作 实现对指定值内的回环累加
+ * 此方法一般用于大量数据完成回环累加(如数据库中的值大于int最大值) * * @param modulo 回环周期值 * @param atomicLong 原子操作类 diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/NumberChineseFormatter.java b/hutool-core/src/main/java/cn/hutool/core/convert/NumberChineseFormatter.java index b794d9104..afbb9d472 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/NumberChineseFormatter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/NumberChineseFormatter.java @@ -64,7 +64,7 @@ public class NumberChineseFormatter { return "零"; } Assert.checkBetween(amount, -99_9999_9999_9999.99, 99_9999_9999_9999.99, - "Number support only: (-99999999999999.99 ~ 99999999999999.99)!"); + "Number support only: (-99999999999999.99 ~ 99999999999999.99)!"); final StringBuilder chineseStr = new StringBuilder(); @@ -126,6 +126,52 @@ public class NumberChineseFormatter { return chineseStr.toString(); } + /** + * 阿拉伯数字(支持正负整数)转换成中文 + * + * @param amount 数字 + * @param isUseTraditional 是否使用繁体 + * @return 中文 + * @since 5.7.17 + */ + public static String format(long amount, boolean isUseTraditional){ + if(0 == amount){ + return "零"; + } + Assert.checkBetween(amount, -99_9999_9999_9999.99, 99_9999_9999_9999.99, + "Number support only: (-99999999999999.99 ~ 99999999999999.99)!"); + + final StringBuilder chineseStr = new StringBuilder(); + + // 负数 + if (amount < 0) { + chineseStr.append("负"); + amount = -amount; + } + + chineseStr.append(longToChinese(amount, isUseTraditional)); + return chineseStr.toString(); + } + + /** + * 格式化-999~999之间的数字
+ * 这个方法显示10~19以下的数字时使用"十一"而非"一十一"。 + * + * @param amount 数字 + * @param isUseTraditional 是否使用繁体 + * @return 中文 + * @since 5.7.17 + */ + public static String formatThousand(int amount, boolean isUseTraditional){ + Assert.checkBetween(amount, -999, 999, "Number support only: (-999 ~ 999)!"); + final String chinese = thousandToChinese(amount, isUseTraditional); + if(amount < 20 && amount > 10){ + // "十一"而非"一十一" + return chinese.substring(1); + } + return chinese; + } + /** * 数字字符转中文,非数字字符原样返回 * diff --git a/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java index cb9aa732f..752a052c8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java @@ -525,8 +525,8 @@ public class CalendarUtil { * 将指定Calendar时间格式化为纯中文形式,比如: * *
-	 *     2018-02-24 12:13:14转换为 二〇一八年二月二十四日(withTime为false)
-	 *     2018-02-24 12:13:14 转换为 二〇一八年二月二十四日一十二时一十三分一十四秒(withTime为true)
+	 *     2018-02-24 12:13:14 转换为 二〇一八年二月二十四日(withTime为false)
+	 *     2018-02-24 12:13:14 转换为 二〇一八年二月二十四日十二时十三分十四秒(withTime为true)
 	 * 
* * @param calendar {@link Calendar} @@ -538,7 +538,7 @@ public class CalendarUtil { final StringBuilder result = StrUtil.builder(); // 年 - String year = String.valueOf(calendar.get(Calendar.YEAR)); + final String year = String.valueOf(calendar.get(Calendar.YEAR)); final int length = year.length(); for (int i = 0; i < length; i++) { result.append(NumberChineseFormatter.numberCharToChinese(year.charAt(i), false)); @@ -547,26 +547,26 @@ public class CalendarUtil { // 月 int month = calendar.get(Calendar.MONTH) + 1; - result.append(NumberChineseFormatter.format(month, false)); + result.append(NumberChineseFormatter.formatThousand(month, false)); result.append('月'); // 日 int day = calendar.get(Calendar.DAY_OF_MONTH); - result.append(NumberChineseFormatter.format(day, false)); + result.append(NumberChineseFormatter.formatThousand(day, false)); result.append('日'); if (withTime) { // 时 int hour = calendar.get(Calendar.HOUR_OF_DAY); - result.append(NumberChineseFormatter.format(hour, false)); + result.append(NumberChineseFormatter.formatThousand(hour, false)); result.append('时'); // 分 int minute = calendar.get(Calendar.MINUTE); - result.append(NumberChineseFormatter.format(minute, false)); + result.append(NumberChineseFormatter.formatThousand(minute, false)); result.append('分'); // 秒 int second = calendar.get(Calendar.SECOND); - result.append(NumberChineseFormatter.format(second, false)); + result.append(NumberChineseFormatter.formatThousand(second, false)); result.append('秒'); } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateBetween.java b/hutool-core/src/main/java/cn/hutool/core/date/DateBetween.java index 3be908942..ead72e629 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateBetween.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateBetween.java @@ -10,14 +10,17 @@ import java.util.Date; * 日期间隔 * * @author Looly - * */ -public class DateBetween implements Serializable{ +public class DateBetween implements Serializable { private static final long serialVersionUID = 1L; - /** 开始日期 */ + /** + * 开始日期 + */ private final Date begin; - /** 结束日期 */ + /** + * 结束日期 + */ private final Date end; /** @@ -25,7 +28,7 @@ public class DateBetween implements Serializable{ * 在前的日期做为起始时间,在后的做为结束时间,间隔只保留绝对值正数 * * @param begin 起始时间 - * @param end 结束时间 + * @param end 结束时间 * @return DateBetween * @since 3.2.3 */ @@ -38,7 +41,7 @@ public class DateBetween implements Serializable{ * 在前的日期做为起始时间,在后的做为结束时间,间隔只保留绝对值正数 * * @param begin 起始时间 - * @param end 结束时间 + * @param end 结束时间 * @param isAbs 日期间隔是否只保留绝对值正数 * @return DateBetween * @since 3.2.3 @@ -52,7 +55,7 @@ public class DateBetween implements Serializable{ * 在前的日期做为起始时间,在后的做为结束时间,间隔只保留绝对值正数 * * @param begin 起始时间 - * @param end 结束时间 + * @param end 结束时间 */ public DateBetween(Date begin, Date end) { this(begin, end, true); @@ -63,7 +66,7 @@ public class DateBetween implements Serializable{ * 在前的日期做为起始时间,在后的做为结束时间 * * @param begin 起始时间 - * @param end 结束时间 + * @param end 结束时间 * @param isAbs 日期间隔是否只保留绝对值正数 * @since 3.1.1 */ @@ -135,9 +138,9 @@ public class DateBetween implements Serializable{ int result = endCal.get(Calendar.YEAR) - beginCal.get(Calendar.YEAR); if (false == isReset) { // 考虑闰年的2月情况 - if(Calendar.FEBRUARY == beginCal.get(Calendar.MONTH) && Calendar.FEBRUARY == endCal.get(Calendar.MONTH)){ - if(beginCal.get(Calendar.DAY_OF_MONTH) == beginCal.getActualMaximum(Calendar.DAY_OF_MONTH) - && endCal.get(Calendar.DAY_OF_MONTH) == endCal.getActualMaximum(Calendar.DAY_OF_MONTH)){ + if (Calendar.FEBRUARY == beginCal.get(Calendar.MONTH) && Calendar.FEBRUARY == endCal.get(Calendar.MONTH)) { + if (beginCal.get(Calendar.DAY_OF_MONTH) == beginCal.getActualMaximum(Calendar.DAY_OF_MONTH) + && endCal.get(Calendar.DAY_OF_MONTH) == endCal.getActualMaximum(Calendar.DAY_OF_MONTH)) { // 两个日期都位于2月的最后一天,此时月数按照相等对待,此时都设置为1号 beginCal.set(Calendar.DAY_OF_MONTH, 1); endCal.set(Calendar.DAY_OF_MONTH, 1); @@ -154,13 +157,25 @@ public class DateBetween implements Serializable{ } /** - * 格式化输出时间差
+ * 格式化输出时间差 + * + * @param unit 日期单位 + * @param level 级别 + * @return 字符串 + * @since 5.7.17 + */ + public String toString(DateUnit unit, BetweenFormatter.Level level) { + return DateUtil.formatBetween(between(unit), level); + } + + /** + * 格式化输出时间差 * * @param level 级别 * @return 字符串 */ public String toString(BetweenFormatter.Level level) { - return DateUtil.formatBetween(between(DateUnit.MS), level); + return toString(DateUnit.MS, level); } @Override 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 5727c460f..4fa0d3e81 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 @@ -44,6 +44,11 @@ public class DateTime extends Date { */ private TimeZone timeZone; + /** + * 第一周最少天数 + */ + private int minimalDaysInFirstWeek; + /** * 转换时间戳为 DateTime * @@ -670,6 +675,10 @@ public class DateTime extends Date { final Calendar cal = (null != zone) ? Calendar.getInstance(zone, locale) : Calendar.getInstance(locale); //noinspection MagicConstant cal.setFirstDayOfWeek(firstDayOfWeek.getValue()); + // issue#1988@Github + if (minimalDaysInFirstWeek > 0) { + cal.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek); + } cal.setTime(this); return cal; } @@ -743,7 +752,7 @@ public class DateTime extends Date { * @return 相差时长 */ public String between(Date date, DateUnit unit, BetweenFormatter.Level formatLevel) { - return new DateBetween(this, date).toString(formatLevel); + return new DateBetween(this, date).toString(unit, formatLevel); } /** @@ -908,6 +917,18 @@ public class DateTime extends Date { return this; } + /** + * 设置第一周最少天数 + * + * @param minimalDaysInFirstWeek 第一周最少天数 + * @return this + * @since 5.7.17 + */ + public DateTime setMinimalDaysInFirstWeek(int minimalDaysInFirstWeek) { + this.minimalDaysInFirstWeek = minimalDaysInFirstWeek; + return this; + } + // -------------------------------------------------------------------- toString start /** diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/tree/Tree.java b/hutool-core/src/main/java/cn/hutool/core/lang/tree/Tree.java index 76272e9bc..34775f92d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/tree/Tree.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/tree/Tree.java @@ -215,7 +215,7 @@ public class Tree extends LinkedHashMap implements Node { /** * 递归过滤当前树,注意此方法会修改当前树
- * 通过{@link Filter}指定的过滤规则,本节点或子节点满足过滤条件,则保留当前节点,否则抛弃节点及其子节点 + * 通过{@link Filter}指定的过滤规则,本节点或子节点满足过滤条件,则保留当前节点及其所有子节点,否则抛弃节点及其子节点 * * @param filter 节点过滤规则函数,只需处理本级节点本身即可 * @return 过滤后的节点,{@code null} 表示不满足过滤要求,丢弃之 @@ -223,6 +223,11 @@ public class Tree extends LinkedHashMap implements Node { * @since 5.7.17 */ public Tree filter(Filter> filter) { + if(filter.accept(this)){ + // 本节点满足,则包括所有子节点都保留 + return this; + } + final List> children = getChildren(); if (CollUtil.isNotEmpty(children)) { // 递归过滤子节点 @@ -243,7 +248,7 @@ public class Tree extends LinkedHashMap implements Node { } // 子节点都不符合过滤条件,检查本节点 - return filter.accept(this) ? this : null; + return null; } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/math/Calculator.java b/hutool-core/src/main/java/cn/hutool/core/math/Calculator.java index 2117d47ee..a6c6a09d1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/math/Calculator.java +++ b/hutool-core/src/main/java/cn/hutool/core/math/Calculator.java @@ -154,7 +154,7 @@ public class Calculator { * @param peek peek * @return 优先级 */ - public boolean compare(char cur, char peek) {// 如果是peek优先级高于cur,返回true,默认都是peek优先级要低 + private boolean compare(char cur, char peek) {// 如果是peek优先级高于cur,返回true,默认都是peek优先级要低 final int offset = 40; if(cur == '%'){ // %优先级最高 @@ -165,7 +165,7 @@ public class Calculator { peek = 47; } - return operatPriority[(peek) - offset] >= operatPriority[(cur) - offset]; + return operatPriority[peek - offset] >= operatPriority[cur - offset]; } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java index 6260c727a..0ebbae359 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java @@ -322,14 +322,6 @@ public class UrlQuery { } } - if (i - pos == len) { - // 没有任何参数符号 - if (queryStr.startsWith("http") || queryStr.contains("/")) { - // 可能为url路径,忽略之 - return this; - } - } - // 处理结尾 addParam(name, queryStr.substring(pos, i), charset); diff --git a/hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java b/hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java index 69bc75f04..a09dc0681 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java @@ -470,7 +470,6 @@ public class StrBuilder implements CharSequence, Appendable, Serializable { /** * 生成字符串 */ - @SuppressWarnings("NullableProblems") @Override public String toString() { return toString(false); diff --git a/hutool-core/src/main/java/cn/hutool/core/util/HashUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/HashUtil.java index b429318a6..97ee1537b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/HashUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/HashUtil.java @@ -543,6 +543,6 @@ public class HashUtil { * @since 5.2.5 */ public static long[] cityHash128(byte[] data, Number128 seed) { - return CityHash.hash128(data).getLongArray(); + return CityHash.hash128(data, seed).getLongArray(); } -} \ No newline at end of file +} 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 c5e2f7aed..a4688cb57 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 @@ -2707,6 +2707,30 @@ public class NumberUtil { } } + /** + * 检查是否为奇数
+ * + * @param num 被判断的数值 + * @return 是否是奇数 + * @author GuoZG + * @since 5.7.17 + */ + public static boolean isOdd(int num) { + return (num & 1) == 1; + } + + /** + * 检查是否为偶数
+ * + * @param num 被判断的数值 + * @return 是否是偶数 + * @author GuoZG + * @since 5.7.17 + */ + public static boolean isEven(int num) { + return false == isOdd(num); + } + // ------------------------------------------------------------------------------------------- Private method start private static int mathSubNode(int selectNum, int minNum) { if (selectNum == minNum) { diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/CollUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/CollUtilTest.java index 833d4a79b..bd889916f 100644 --- a/hutool-core/src/test/java/cn/hutool/core/collection/CollUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/collection/CollUtilTest.java @@ -45,7 +45,7 @@ public class CollUtilTest { ArrayList exceptRemovedList = CollUtil.newArrayList(2, 3); ArrayList exceptResultList = CollUtil.newArrayList(1); - ArrayList resultList = CollUtil.removeWithAddIf(list, ele -> 1 == ele); + List resultList = CollUtil.removeWithAddIf(list, ele -> 1 == ele); Assert.assertEquals(list, exceptRemovedList); Assert.assertEquals(resultList, exceptResultList); diff --git a/hutool-core/src/test/java/cn/hutool/core/date/CalendarUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/CalendarUtilTest.java index 63e7fc7f9..7b0a20101 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/CalendarUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/CalendarUtilTest.java @@ -14,7 +14,7 @@ public class CalendarUtilTest { final String chineseDate = CalendarUtil.formatChineseDate(calendar, false); Assert.assertEquals("二〇一八年二月二十四日", chineseDate); final String chineseDateTime = CalendarUtil.formatChineseDate(calendar, true); - Assert.assertEquals("二〇一八年二月二十四日一十二时一十三分一十四秒", chineseDateTime); + Assert.assertEquals("二〇一八年二月二十四日十二时十三分十四秒", chineseDateTime); } @Test(expected = IllegalArgumentException.class) 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 738995533..8495eccd5 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 @@ -116,7 +116,7 @@ public class DateUtilTest { } @Test - public void truncateTest(){ + public void truncateTest() { String dateStr2 = "2020-02-29 12:59:34"; Date date2 = DateUtil.parse(dateStr2); final DateTime dateTime = DateUtil.truncate(date2, DateField.MINUTE); @@ -124,7 +124,7 @@ public class DateUtilTest { } @Test - public void ceilingMinuteTest(){ + public void ceilingMinuteTest() { String dateStr2 = "2020-02-29 12:59:34"; Date date2 = DateUtil.parse(dateStr2); @@ -137,7 +137,7 @@ public class DateUtilTest { } @Test - public void ceilingDayTest(){ + public void ceilingDayTest() { String dateStr2 = "2020-02-29 12:59:34"; Date date2 = DateUtil.parse(dateStr2); @@ -279,13 +279,16 @@ public class DateUtilTest { public void formatChineseDateTest() { String formatChineseDate = DateUtil.formatChineseDate(DateUtil.parse("2018-02-24"), true, false); Assert.assertEquals("二〇一八年二月二十四日", formatChineseDate); + + formatChineseDate = DateUtil.formatChineseDate(DateUtil.parse("2018-02-14"), true, false); + Assert.assertEquals("二〇一八年二月十四日", formatChineseDate); } - @Test - public void formatChineseDateTimeTest() { - String formatChineseDateTime = DateUtil.formatChineseDate(DateUtil.parse("2018-02-24 12:13:14"), true, true); - Assert.assertEquals("二〇一八年二月二十四日一十二时一十三分一十四秒", formatChineseDateTime); - } + @Test + public void formatChineseDateTimeTest() { + String formatChineseDateTime = DateUtil.formatChineseDate(DateUtil.parse("2018-02-24 12:13:14"), true, true); + Assert.assertEquals("二〇一八年二月二十四日十二时十三分十四秒", formatChineseDateTime); + } @Test public void formatBetweenTest() { @@ -666,24 +669,24 @@ public class DateUtilTest { } @Test - public void parseUTCTest2(){ + public void parseUTCTest2() { // issue1503@Github // 检查不同毫秒长度都可以正常匹配 - String utcTime="2021-03-30T12:56:51.3Z"; + String utcTime = "2021-03-30T12:56:51.3Z"; DateTime parse = DateUtil.parseUTC(utcTime); Assert.assertEquals("2021-03-30 12:56:51", parse.toString()); - utcTime="2021-03-30T12:56:51.34Z"; + utcTime = "2021-03-30T12:56:51.34Z"; parse = DateUtil.parseUTC(utcTime); Assert.assertEquals("2021-03-30 12:56:51", parse.toString()); - utcTime="2021-03-30T12:56:51.345Z"; + utcTime = "2021-03-30T12:56:51.345Z"; parse = DateUtil.parseUTC(utcTime); Assert.assertEquals("2021-03-30 12:56:51", parse.toString()); } @Test - public void parseCSTTest(){ + public void parseCSTTest() { String dateStr = "Wed Sep 16 11:26:23 CST 2009"; SimpleDateFormat sdf = new SimpleDateFormat(DatePattern.JDK_DATETIME_PATTERN, Locale.US); @@ -697,7 +700,7 @@ public class DateUtilTest { } @Test - public void parseCSTTest2(){ + public void parseCSTTest2() { String dateStr = "Wed Sep 16 11:26:23 CST 2009"; SimpleDateFormat sdf = new SimpleDateFormat(DatePattern.JDK_DATETIME_PATTERN, Locale.US); @@ -737,7 +740,7 @@ public class DateUtilTest { Date date = DateUtil.endOfQuarter( DateUtil.parse("2020-05-31 00:00:00")); - Assert.assertEquals("2020-06-30 23:59:59", DateUtil.format(date,"yyyy-MM-dd HH:mm:ss")); + Assert.assertEquals("2020-06-30 23:59:59", DateUtil.format(date, "yyyy-MM-dd HH:mm:ss")); } @Test @@ -803,7 +806,7 @@ public class DateUtilTest { } @Test - public void toInstantTest(){ + public void toInstantTest() { LocalDateTime localDateTime = LocalDateTime.parse("2017-05-06T08:30:00", DateTimeFormatter.ISO_DATE_TIME); Instant instant = DateUtil.toInstant(localDateTime); Assert.assertEquals("2017-05-06T00:30:00Z", instant.toString()); @@ -818,7 +821,7 @@ public class DateUtilTest { } @Test - public void dateTest(){ + public void dateTest() { //LocalDateTime ==> date LocalDateTime localDateTime = LocalDateTime.parse("2017-05-06T08:30:00", DateTimeFormatter.ISO_DATE_TIME); DateTime date = DateUtil.date(localDateTime); @@ -828,11 +831,11 @@ public class DateUtilTest { LocalDate localDate = localDateTime.toLocalDate(); DateTime date2 = DateUtil.date(localDate); Assert.assertEquals("2017-05-06", - DateUtil.format(date2, DatePattern.NORM_DATE_PATTERN)); + DateUtil.format(date2, DatePattern.NORM_DATE_PATTERN)); } @Test - public void dateTest2(){ + public void dateTest2() { // 测试负数日期 long dateLong = -1497600000; final DateTime date = DateUtil.date(dateLong); @@ -840,7 +843,7 @@ public class DateUtilTest { } @Test - public void ageTest(){ + public void ageTest() { String d1 = "2000-02-29"; String d2 = "2018-02-28"; final int age = DateUtil.age(DateUtil.parseDate(d1), DateUtil.parseDate(d2)); @@ -848,14 +851,14 @@ public class DateUtilTest { } @Test(expected = IllegalArgumentException.class) - public void ageTest2(){ + public void ageTest2() { String d1 = "2019-02-29"; String d2 = "2018-02-28"; DateUtil.age(DateUtil.parseDate(d1), DateUtil.parseDate(d2)); } @Test - public void isExpiredTest(){ + public void isExpiredTest() { DateTime startDate = DateUtil.parse("2019-12-01 17:02:30"); DateTime endDate = DateUtil.parse("2019-12-02 17:02:30"); int length = 3; @@ -916,7 +919,7 @@ public class DateUtilTest { @SuppressWarnings("ConstantConditions") @Test - public void parseSingleNumberTest(){ + public void parseSingleNumberTest() { DateTime dateTime = DateUtil.parse("2020-5-08"); Assert.assertEquals("2020-05-08 00:00:00", dateTime.toString()); dateTime = DateUtil.parse("2020-5-8"); @@ -938,21 +941,21 @@ public class DateUtilTest { @SuppressWarnings("ConstantConditions") @Test - public void parseISO8601Test(){ + public void parseISO8601Test() { String dt = "2020-06-03 12:32:12,333"; final DateTime parse = DateUtil.parse(dt); Assert.assertEquals("2020-06-03 12:32:12", parse.toString()); } @Test(expected = DateException.class) - public void parseNotFitTest(){ + public void parseNotFitTest() { //https://github.com/looly/hutool/issues/1332 // 在日期格式不匹配的时候,测试是否正常报错 DateUtil.parse("2020-12-23", DatePattern.PURE_DATE_PATTERN); } @Test - public void formatTest(){ + public void formatTest() { Calendar calendar = new GregorianCalendar(); calendar.set(2021, Calendar.JULY, 14, 23, 59, 59); Date date = new DateTime(calendar); @@ -963,7 +966,7 @@ public class DateUtilTest { } @Test - public void formatNormDateTimeFormatterTest(){ + public void formatNormDateTimeFormatterTest() { String format = DateUtil.format(DateUtil.parse("2021-07-14 10:05:38"), DatePattern.NORM_DATETIME_FORMATTER); Assert.assertEquals("2021-07-14 10:05:38", format); @@ -973,7 +976,7 @@ public class DateUtilTest { } @Test - public void isWeekendTest(){ + public void isWeekendTest() { DateTime parse = DateUtil.parse("2021-07-28"); Assert.assertFalse(DateUtil.isWeekend(parse)); @@ -984,14 +987,14 @@ public class DateUtilTest { } @Test - public void parseSingleMonthAndDayTest(){ + public void parseSingleMonthAndDayTest() { final DateTime parse = DateUtil.parse("2021-1-1"); Assert.assertNotNull(parse); Assert.assertEquals("2021-01-01 00:00:00", parse.toString()); } @Test - public void parseByDateTimeFormatterTest(){ + public void parseByDateTimeFormatterTest() { final DateTime parse = DateUtil.parse("2021-12-01", DatePattern.NORM_DATE_FORMATTER); Assert.assertEquals("2021-12-01 00:00:00", parse.toString()); } diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeTest.java index c695a707c..fc9131cc7 100644 --- a/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeTest.java @@ -94,12 +94,12 @@ public class TreeTest { final Tree tree = TreeUtil.buildSingle(nodeList, "0"); tree.filter((t)->{ final CharSequence name = t.getName(); - return null != name && name.toString().contains("管理"); + return null != name && name.toString().contains("店铺"); }); List ids = new ArrayList<>(); tree.walk((tr)-> ids.add(tr.getId())); - Assert .assertEquals(6, ids.size()); + Assert .assertEquals(4, ids.size()); } @Test @@ -109,12 +109,12 @@ public class TreeTest { // 经过过滤,生成新的树 Tree newTree = tree.filterNew((t)->{ final CharSequence name = t.getName(); - return null != name && name.toString().contains("管理"); + return null != name && name.toString().contains("店铺"); }); List ids = new ArrayList<>(); newTree.walk((tr)-> ids.add(tr.getId())); - Assert .assertEquals(6, ids.size()); + Assert .assertEquals(4, ids.size()); List ids2 = new ArrayList<>(); tree.walk((tr)-> ids2.add(tr.getId())); diff --git a/hutool-core/src/test/java/cn/hutool/core/math/CalculatorTest.java b/hutool-core/src/test/java/cn/hutool/core/math/CalculatorTest.java index 7dbd128d2..7c67abdbe 100644 --- a/hutool-core/src/test/java/cn/hutool/core/math/CalculatorTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/math/CalculatorTest.java @@ -1,6 +1,7 @@ package cn.hutool.core.math; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; public class CalculatorTest { @@ -28,4 +29,12 @@ public class CalculatorTest { final double conversion = Calculator.conversion("(88*66/23)%26+45%9"); Assert.assertEquals((88D * 66 / 23) % 26, conversion, 2); } + + @Test + @Ignore + public void conversationTest5(){ + // https://github.com/dromara/hutool/issues/1984 + final double conversion = Calculator.conversion("((1/1) / (1/1) -1) * 100"); + Assert.assertEquals((88D * 66 / 23) % 26, conversion, 2); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java b/hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java index a094b9838..af4ac5d9b 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java @@ -313,4 +313,11 @@ public class UrlBuilderTest { final UrlBuilder of = UrlBuilder.ofHttpWithoutEncode(url); Assert.assertEquals(url, of.toString()); } + + @Test + public void paramTest(){ + String url = "http://ci.xiaohongshu.com/spectrum/c136c98aa2047babe25b994a26ffa7b492bd8058?imageMogr2/thumbnail/x800/format/jpg"; + final UrlBuilder builder = UrlBuilder.ofHttp(url); + Assert.assertEquals(url, builder.toString()); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/net/UrlQueryTest.java b/hutool-core/src/test/java/cn/hutool/core/net/UrlQueryTest.java index 4bdaabc0d..54ce50a51 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/UrlQueryTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/UrlQueryTest.java @@ -46,10 +46,18 @@ public class UrlQueryTest { public void parseTest3(){ // issue#1688@Github String u = "https://www.baidu.com/proxy"; - final UrlQuery query = UrlQuery.of(u, Charset.defaultCharset()); + final UrlQuery query = UrlQuery.of(URLUtil.url(u).getQuery(), Charset.defaultCharset()); Assert.assertTrue(MapUtil.isEmpty(query.getQueryMap())); } + @Test + public void parseTest4(){ + // https://github.com/dromara/hutool/issues/1989 + String queryStr = "imageMogr2/thumbnail/x800/format/jpg"; + final UrlQuery query = UrlQuery.of(queryStr, CharsetUtil.CHARSET_UTF_8); + Assert.assertEquals(queryStr, query.toString()); + } + @Test public void buildWithMapTest() { Map map = new LinkedHashMap<>(); 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 e5ee4565e..489a3faf8 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 @@ -412,4 +412,26 @@ public class NumberUtilTest { final Integer[] integers = NumberUtil.generateBySet(10, 100, 5); Assert.assertEquals(5, integers.length); } + + @Test + public void isOddOrEvenTest(){ + int[] a = { 0, 32, -32, 123, -123 }; + Assert.assertFalse(NumberUtil.isOdd(a[0])); + Assert.assertTrue(NumberUtil.isEven(a[0])); + + Assert.assertFalse(NumberUtil.isOdd(a[1])); + Assert.assertTrue(NumberUtil.isEven(a[1])); + + Assert.assertFalse(NumberUtil.isOdd(a[2])); + Assert.assertTrue(NumberUtil.isEven(a[2])); + + Assert.assertTrue(NumberUtil.isOdd(a[3])); + Assert.assertFalse(NumberUtil.isEven(a[3])); + + Assert.assertTrue(NumberUtil.isOdd(a[4])); + Assert.assertFalse(NumberUtil.isEven(a[4])); + } + + + } diff --git a/hutool-db/pom.xml b/hutool-db/pom.xml index 835eede43..779270085 100644 --- a/hutool-db/pom.xml +++ b/hutool-db/pom.xml @@ -81,7 +81,7 @@ com.github.chris2018998 beecp - 3.2.9 + 3.3.0 slf4j-api diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml index 9f32ccf43..bbc362788 100644 --- a/hutool-extra/pom.xml +++ b/hutool-extra/pom.xml @@ -241,7 +241,7 @@ org.apache.lucene lucene-analyzers-smartcn - 8.10.1 + 8.11.0 true @@ -384,7 +384,7 @@ ch.qos.logback logback-classic - 1.2.6 + 1.2.7 test @@ -432,7 +432,7 @@ org.springframework spring-expression - 5.3.12 + 5.3.13 compile true diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpGlobalConfig.java b/hutool-http/src/main/java/cn/hutool/http/HttpGlobalConfig.java index d45d23593..ae76d932d 100755 --- a/hutool-http/src/main/java/cn/hutool/http/HttpGlobalConfig.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpGlobalConfig.java @@ -1,6 +1,7 @@ package cn.hutool.http; import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.ReflectUtil; import cn.hutool.http.cookie.GlobalCookieManager; @@ -21,6 +22,7 @@ public class HttpGlobalConfig implements Serializable { protected static int timeout = -1; private static boolean isAllowPatch = false; + private static String boundary = "--------------------Hutool_" + RandomUtil.randomString(16); /** * 获取全局默认的超时时长 @@ -40,6 +42,26 @@ public class HttpGlobalConfig implements Serializable { timeout = customTimeout; } + /** + * 获取全局默认的Multipart边界 + * + * @return 全局默认的Multipart边界 + * @since 5.7.17 + */ + public static String getBoundary() { + return boundary; + } + + /** + * 设置默认的Multipart边界 + * + * @param customBoundary 自定义Multipart边界 + * @since 5.7.17 + */ + synchronized public static void setBoundary(String customBoundary) { + boundary = customBoundary; + } + /** * 获取Cookie管理器,用于自定义Cookie管理 * diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java index 12a14e699..67a43e027 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java @@ -1228,9 +1228,10 @@ public class HttpRequest extends HttpBase { * @throws IOException IO异常 */ private void sendMultipart() throws IOException { + final MultipartBody multipartBody = MultipartBody.create(this.form, this.charset); //设置表单类型为Multipart(文件上传) - this.httpConnection.header(Header.CONTENT_TYPE, MultipartBody.getContentType(), true); - MultipartBody.create(this.form, this.charset).writeClose(this.httpConnection.getOutputStream()); + this.httpConnection.header(Header.CONTENT_TYPE, multipartBody.getContentType(), true); + multipartBody.writeClose(this.httpConnection.getOutputStream()); } /** diff --git a/hutool-http/src/main/java/cn/hutool/http/MultipartOutputStream.java b/hutool-http/src/main/java/cn/hutool/http/MultipartOutputStream.java index 5ca620ad1..53f905aca 100644 --- a/hutool-http/src/main/java/cn/hutool/http/MultipartOutputStream.java +++ b/hutool-http/src/main/java/cn/hutool/http/MultipartOutputStream.java @@ -7,7 +7,6 @@ import cn.hutool.core.io.resource.MultiResource; import cn.hutool.core.io.resource.Resource; import cn.hutool.core.io.resource.StringResource; import cn.hutool.core.util.StrUtil; -import cn.hutool.http.body.MultipartBody; import java.io.IOException; import java.io.OutputStream; @@ -17,13 +16,11 @@ import java.nio.charset.Charset; * Multipart/form-data输出流封装
* 遵循RFC2388规范 * - * @since 5.7.17 * @author looly + * @since 5.7.17 */ public class MultipartOutputStream extends OutputStream { - private static final String BOUNDARY = MultipartBody.BOUNDARY; - private static final String BOUNDARY_END = StrUtil.format("--{}--\r\n", BOUNDARY); private static final String CONTENT_DISPOSITION_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"\r\n"; private static final String CONTENT_DISPOSITION_FILE_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"; filename=\"{}\"\r\n"; @@ -31,17 +28,32 @@ public class MultipartOutputStream extends OutputStream { private final OutputStream out; private final Charset charset; + private final String boundary; + private boolean isFinish; /** - * 构造 + * 构造,使用全局默认的边界字符串 * * @param out HTTP写出流 * @param charset 编码 */ public MultipartOutputStream(OutputStream out, Charset charset) { + this(out, charset, HttpGlobalConfig.getBoundary()); + } + + /** + * 构造 + * + * @param out HTTP写出流 + * @param charset 编码 + * @param boundary 边界符 + * @since 5.7.17 + */ + public MultipartOutputStream(OutputStream out, Charset charset, String boundary) { this.out = out; this.charset = charset; + this.boundary = boundary; } /** @@ -65,6 +77,7 @@ public class MultipartOutputStream extends OutputStream { * * @param formFieldName 表单名 * @param value 值,可以是普通值、资源(如文件等) + * @return this * @throws IORuntimeException IO异常 */ public MultipartOutputStream write(String formFieldName, Object value) throws IORuntimeException { @@ -101,8 +114,8 @@ public class MultipartOutputStream extends OutputStream { * @throws IORuntimeException IO异常 */ public void finish() throws IORuntimeException { - if(false == isFinish){ - write(BOUNDARY_END); + if (false == isFinish) { + write(StrUtil.format("--{}--\r\n", boundary)); this.isFinish = true; } } @@ -139,7 +152,7 @@ public class MultipartOutputStream extends OutputStream { // Content-Type: 类型[换行] write(StrUtil.format(CONTENT_TYPE_FILE_TEMPLATE, contentType)); } - } else if(StrUtil.isNotEmpty(fileName)){ + } else if (StrUtil.isNotEmpty(fileName)) { // 根据name的扩展名指定互联网媒体类型,默认二进制流数据 write(StrUtil.format(CONTENT_TYPE_FILE_TEMPLATE, HttpUtil.getMimeType(fileName, ContentType.OCTET_STREAM.getValue()))); @@ -156,9 +169,9 @@ public class MultipartOutputStream extends OutputStream { * --分隔符(boundary)[换行] * */ - private void beginPart(){ + private void beginPart() { // --分隔符(boundary)[换行] - write("--", BOUNDARY, StrUtil.CRLF); + write("--", boundary, StrUtil.CRLF); } /** diff --git a/hutool-http/src/main/java/cn/hutool/http/body/MultipartBody.java b/hutool-http/src/main/java/cn/hutool/http/body/MultipartBody.java index dbf955363..37077832f 100644 --- a/hutool-http/src/main/java/cn/hutool/http/body/MultipartBody.java +++ b/hutool-http/src/main/java/cn/hutool/http/body/MultipartBody.java @@ -2,8 +2,8 @@ package cn.hutool.http.body; import cn.hutool.core.io.IoUtil; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.RandomUtil; import cn.hutool.http.ContentType; +import cn.hutool.http.HttpGlobalConfig; import cn.hutool.http.MultipartOutputStream; import java.io.ByteArrayOutputStream; @@ -20,7 +20,6 @@ import java.util.Map; */ public class MultipartBody implements RequestBody { - public static final String BOUNDARY = "--------------------Hutool_" + RandomUtil.randomString(16); private static final String CONTENT_TYPE_MULTIPART_PREFIX = ContentType.MULTIPART.getValue() + "; boundary="; /** @@ -31,6 +30,10 @@ public class MultipartBody implements RequestBody { * 编码 */ private final Charset charset; + /** + * 边界 + */ + private final String boundary = HttpGlobalConfig.getBoundary(); /** * 根据已有表单内容,构建MultipartBody @@ -48,8 +51,8 @@ public class MultipartBody implements RequestBody { * * @return Multipart的Content-Type类型 */ - public static String getContentType() { - return CONTENT_TYPE_MULTIPART_PREFIX + BOUNDARY; + public String getContentType() { + return CONTENT_TYPE_MULTIPART_PREFIX + boundary; } /** @@ -70,7 +73,7 @@ public class MultipartBody implements RequestBody { */ @Override public void write(OutputStream out) { - final MultipartOutputStream stream = new MultipartOutputStream(out, this.charset); + final MultipartOutputStream stream = new MultipartOutputStream(out, this.charset, this.boundary); if (MapUtil.isNotEmpty(this.form)) { this.form.forEach(stream::write); } diff --git a/hutool-http/src/main/java/cn/hutool/http/webservice/SoapClient.java b/hutool-http/src/main/java/cn/hutool/http/webservice/SoapClient.java index 4c892c285..35b155fff 100644 --- a/hutool-http/src/main/java/cn/hutool/http/webservice/SoapClient.java +++ b/hutool-http/src/main/java/cn/hutool/http/webservice/SoapClient.java @@ -338,7 +338,7 @@ public class SoapClient extends HttpBase { */ public SoapClient setMethod(QName name, Map params, boolean useMethodPrefix) { setMethod(name); - final String prefix = name.getPrefix(); + final String prefix = useMethodPrefix ? name.getPrefix() : null; final SOAPBodyElement methodEle = this.methodEle; for (Entry entry : MapUtil.wrap(params)) { setParam(methodEle, entry.getKey(), entry.getValue(), prefix); @@ -618,7 +618,7 @@ public class SoapClient extends HttpBase { * @param ele 方法节点 * @param name 参数名 * @param value 参数值 - * @param prefix 命名空间前缀 + * @param prefix 命名空间前缀, {@code null}表示不使用前缀 * @return {@link SOAPElement}子节点 */ @SuppressWarnings("rawtypes") 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 2d3883ddb..2a60abe11 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 @@ -162,9 +162,9 @@ public class CellUtil { */ public static void setCellValue(Cell cell, Object value, CellStyle style) { setCellValue(cell, (CellSetter) cell1 -> { + setCellValue(cell, value); if (null != style) { cell1.setCellStyle(style); - setCellValue(cell, value); } }); } @@ -175,7 +175,7 @@ public class CellUtil { * 当为头部样式时默认赋值头部样式,但是头部中如果有数字、日期等类型,将按照数字、日期样式设置 * * @param cell 单元格 - * @param value 值 + * @param value 值或{@link CellSetter} * @since 5.6.4 */ public static void setCellValue(Cell cell, Object value) { @@ -402,7 +402,7 @@ public class CellUtil { } Comment comment = drawing.createCellComment(anchor); comment.setString(factory.createRichTextString(commentText)); - comment.setAuthor(StrUtil.nullToEmpty(commentText)); + comment.setAuthor(StrUtil.nullToEmpty(commentAuthor)); cell.setCellComment(comment); }