mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
Merge remote-tracking branch 'origin/v5-dev' into v5-dev
This commit is contained in:
commit
c1e6ea8d42
13
CHANGELOG.md
13
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无效问题
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -1299,14 +1299,14 @@ public class CollUtil {
|
||||
* @param <E> 集合元素类型
|
||||
* @param resultCollection 存放移除结果的集合
|
||||
* @param targetCollection 被操作移除元素的集合
|
||||
* @param filter 用于是否移除判断的过滤器
|
||||
* @param predicate 用于是否移除判断的过滤器
|
||||
*/
|
||||
public static <T extends Collection<E>, E> T removeWithAddIf(T targetCollection, T resultCollection, Predicate<? super E> filter) {
|
||||
Objects.requireNonNull(filter);
|
||||
public static <T extends Collection<E>, E> T removeWithAddIf(T targetCollection, T resultCollection, Predicate<? super E> predicate) {
|
||||
Objects.requireNonNull(predicate);
|
||||
final Iterator<E> 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 {
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除集合中的多个元素,并将结果存放到生成的新集合中后返回
|
||||
* 移除集合中的多个元素,并将结果存放到生成的新集合中后返回<br>
|
||||
* 此方法直接修改原集合
|
||||
*
|
||||
* @param <T> 集合类型
|
||||
* @param <E> 集合元素类型
|
||||
* @param targetCollection 被操作移除元素的集合
|
||||
* @param filter 用于是否移除判断的过滤器
|
||||
* @param predicate 用于是否移除判断的过滤器
|
||||
* @return 移除结果的集合
|
||||
* @since 5.7.17
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Collection<E>, E> T removeWithAddIf(T targetCollection, Predicate<? super E> filter) {
|
||||
Collection<E> resultCollection = new ArrayList<>();
|
||||
removeWithAddIf(targetCollection, resultCollection, filter);
|
||||
return (T) resultCollection;
|
||||
public static <T extends Collection<E>, E> List<E> removeWithAddIf(T targetCollection, Predicate<? super E> predicate) {
|
||||
final List<E> removed = new ArrayList<>();
|
||||
removeWithAddIf(targetCollection, removed, predicate);
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,7 +56,8 @@ public class RingIndexUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过cas操作 实现对指定值内的回环累加
|
||||
* 通过cas操作 实现对指定值内的回环累加<br>
|
||||
* 此方法一般用于大量数据完成回环累加(如数据库中的值大于int最大值)
|
||||
*
|
||||
* @param modulo 回环周期值
|
||||
* @param atomicLong 原子操作类
|
||||
|
@ -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之间的数字<br>
|
||||
* 这个方法显示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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字字符转中文,非数字字符原样返回
|
||||
*
|
||||
|
@ -525,8 +525,8 @@ public class CalendarUtil {
|
||||
* 将指定Calendar时间格式化为纯中文形式,比如:
|
||||
*
|
||||
* <pre>
|
||||
* 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)
|
||||
* </pre>
|
||||
*
|
||||
* @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('秒');
|
||||
}
|
||||
|
||||
|
@ -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{
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化输出时间差<br>
|
||||
* 格式化输出时间差
|
||||
*
|
||||
* @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
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
|
@ -215,7 +215,7 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
|
||||
|
||||
/**
|
||||
* 递归过滤当前树,注意此方法会修改当前树<br>
|
||||
* 通过{@link Filter}指定的过滤规则,本节点或子节点满足过滤条件,则保留当前节点,否则抛弃节点及其子节点
|
||||
* 通过{@link Filter}指定的过滤规则,本节点或子节点满足过滤条件,则保留当前节点及其所有子节点,否则抛弃节点及其子节点
|
||||
*
|
||||
* @param filter 节点过滤规则函数,只需处理本级节点本身即可
|
||||
* @return 过滤后的节点,{@code null} 表示不满足过滤要求,丢弃之
|
||||
@ -223,6 +223,11 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
|
||||
* @since 5.7.17
|
||||
*/
|
||||
public Tree<T> filter(Filter<Tree<T>> filter) {
|
||||
if(filter.accept(this)){
|
||||
// 本节点满足,则包括所有子节点都保留
|
||||
return this;
|
||||
}
|
||||
|
||||
final List<Tree<T>> children = getChildren();
|
||||
if (CollUtil.isNotEmpty(children)) {
|
||||
// 递归过滤子节点
|
||||
@ -243,7 +248,7 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
|
||||
}
|
||||
|
||||
// 子节点都不符合过滤条件,检查本节点
|
||||
return filter.accept(this) ? this : null;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
|
@ -470,7 +470,6 @@ public class StrBuilder implements CharSequence, Appendable, Serializable {
|
||||
/**
|
||||
* 生成字符串
|
||||
*/
|
||||
@SuppressWarnings("NullableProblems")
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(false);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2707,6 +2707,30 @@ public class NumberUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为奇数<br>
|
||||
*
|
||||
* @param num 被判断的数值
|
||||
* @return 是否是奇数
|
||||
* @author GuoZG
|
||||
* @since 5.7.17
|
||||
*/
|
||||
public static boolean isOdd(int num) {
|
||||
return (num & 1) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为偶数<br>
|
||||
*
|
||||
* @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) {
|
||||
|
@ -45,7 +45,7 @@ public class CollUtilTest {
|
||||
ArrayList<Integer> exceptRemovedList = CollUtil.newArrayList(2, 3);
|
||||
ArrayList<Integer> exceptResultList = CollUtil.newArrayList(1);
|
||||
|
||||
ArrayList<Integer> resultList = CollUtil.removeWithAddIf(list, ele -> 1 == ele);
|
||||
List<Integer> resultList = CollUtil.removeWithAddIf(list, ele -> 1 == ele);
|
||||
Assert.assertEquals(list, exceptRemovedList);
|
||||
Assert.assertEquals(resultList, exceptResultList);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -94,12 +94,12 @@ public class TreeTest {
|
||||
final Tree<String> 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<String> 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<String> newTree = tree.filterNew((t)->{
|
||||
final CharSequence name = t.getName();
|
||||
return null != name && name.toString().contains("管理");
|
||||
return null != name && name.toString().contains("店铺");
|
||||
});
|
||||
|
||||
List<String> ids = new ArrayList<>();
|
||||
newTree.walk((tr)-> ids.add(tr.getId()));
|
||||
Assert .assertEquals(6, ids.size());
|
||||
Assert .assertEquals(4, ids.size());
|
||||
|
||||
List<String> ids2 = new ArrayList<>();
|
||||
tree.walk((tr)-> ids2.add(tr.getId()));
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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<String, String> map = new LinkedHashMap<>();
|
||||
|
@ -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]));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -81,7 +81,7 @@
|
||||
<dependency>
|
||||
<groupId>com.github.chris2018998</groupId>
|
||||
<artifactId>beecp</artifactId>
|
||||
<version>3.2.9</version>
|
||||
<version>3.3.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
|
@ -241,7 +241,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-analyzers-smartcn</artifactId>
|
||||
<version>8.10.1</version>
|
||||
<version>8.11.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -384,7 +384,7 @@
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.6</version>
|
||||
<version>1.2.7</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@ -432,7 +432,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-expression</artifactId>
|
||||
<version>5.3.12</version>
|
||||
<version>5.3.13</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
@ -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管理
|
||||
*
|
||||
|
@ -1228,9 +1228,10 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
* @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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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输出流封装<br>
|
||||
* 遵循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)[换行]
|
||||
* </pre>
|
||||
*/
|
||||
private void beginPart(){
|
||||
private void beginPart() {
|
||||
// --分隔符(boundary)[换行]
|
||||
write("--", BOUNDARY, StrUtil.CRLF);
|
||||
write("--", boundary, StrUtil.CRLF);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ public class SoapClient extends HttpBase<SoapClient> {
|
||||
*/
|
||||
public SoapClient setMethod(QName name, Map<String, Object> params, boolean useMethodPrefix) {
|
||||
setMethod(name);
|
||||
final String prefix = name.getPrefix();
|
||||
final String prefix = useMethodPrefix ? name.getPrefix() : null;
|
||||
final SOAPBodyElement methodEle = this.methodEle;
|
||||
for (Entry<String, Object> entry : MapUtil.wrap(params)) {
|
||||
setParam(methodEle, entry.getKey(), entry.getValue(), prefix);
|
||||
@ -618,7 +618,7 @@ public class SoapClient extends HttpBase<SoapClient> {
|
||||
* @param ele 方法节点
|
||||
* @param name 参数名
|
||||
* @param value 参数值
|
||||
* @param prefix 命名空间前缀
|
||||
* @param prefix 命名空间前缀, {@code null}表示不使用前缀
|
||||
* @return {@link SOAPElement}子节点
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user