Merge remote-tracking branch 'origin/v5-dev' into v5-dev

This commit is contained in:
duandazhi 2021-03-28 19:51:36 +08:00
commit 015d6ae9f3
54 changed files with 541 additions and 206 deletions

View File

@ -3,14 +3,29 @@
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.6.2 (2021-03-21) # 5.6.3 (2021-03-28)
### 新特性
### Bug修复
-------------------------------------------------------------------------------------------------------------
# 5.6.2 (2021-03-28)
### 新特性 ### 新特性
* 【core 】 Validator增加车架号(车辆识别码)验证、驾驶证驾驶证档案编号的正则校验pr#280@Gitee * 【core 】 Validator增加车架号(车辆识别码)验证、驾驶证驾驶证档案编号的正则校验pr#280@Gitee
* 【core 】 CopyOptions增加propertiesFilterpr#281@Gitee * 【core 】 CopyOptions增加propertiesFilterpr#281@Gitee
* 【extra 】 增加Wit模板引擎支持 * 【extra 】 增加Wit模板引擎支持
* 【core 】 增加DesensitizedUtilpr#282@Gitee * 【core 】 增加DesensitizedUtilpr#282@Gitee
* 【core 】 增加DateTime字符串构造issue#I3CQZG@Gitee
* 【core 】 修改ArrayUtil代码风格pr#287@Gitee
* 【json 】 JSONConfig增加setStripTrailingZeros配置issue#I3DJI8@Gitee
* 【db 】 升级兼容BeeCP3.x
### Bug修复 ### Bug修复
* 【core 】 修复FileTypeUtil中OFD格式判断问题pr#1489@Github
* 【core 】 修复CamelCaseLinkedMap和CaseInsensitiveLinkedMap的Linked失效问题pr#1490@Github
* 【core 】 修复UrlPath中=被转义的问题
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------

View File

@ -125,19 +125,19 @@ Each module can be introduced individually, or all modules can be introduced by
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
<version>5.6.2</version> <version>5.6.3</version>
</dependency> </dependency>
``` ```
### Gradle ### Gradle
``` ```
compile 'cn.hutool:hutool-all:5.6.2' compile 'cn.hutool:hutool-all:5.6.3'
``` ```
## Download ## Download
- [Maven1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.2/) - [Maven1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.3/)
- [Maven2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.6.2/) - [Maven2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.6.3/)
> note: > 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. > Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available.

View File

@ -123,20 +123,20 @@ Hutool的存在就是为了减少代码搜索成本避免网络上参差不
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
<version>5.6.2</version> <version>5.6.3</version>
</dependency> </dependency>
``` ```
### Gradle ### Gradle
``` ```
compile 'cn.hutool:hutool-all:5.6.2' compile 'cn.hutool:hutool-all:5.6.3'
``` ```
### 非Maven项目 ### 非Maven项目
点击以下任一链接,下载`hutool-all-X.X.X.jar`即可: 点击以下任一链接,下载`hutool-all-X.X.X.jar`即可:
- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.2/) - [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.3/)
> 注意 > 注意
> Hutool 5.x支持JDK8+对Android平台没有测试不能保证所有工具类或工具方法可用。 > Hutool 5.x支持JDK8+对Android平台没有测试不能保证所有工具类或工具方法可用。

View File

@ -1 +1 @@
5.6.2 5.6.3

View File

@ -1 +1 @@
var version = '5.6.2' var version = '5.6.3'

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-aop</artifactId> <artifactId>hutool-aop</artifactId>
@ -19,7 +19,7 @@
<properties> <properties>
<!-- versions --> <!-- versions -->
<cglib.version>3.3.0</cglib.version> <cglib.version>3.3.0</cglib.version>
<spring.version>5.3.4</spring.version> <spring.version>5.3.5</spring.version>
</properties> </properties>
<dependencies> <dependencies>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-bloomFilter</artifactId> <artifactId>hutool-bloomFilter</artifactId>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-bom</artifactId> <artifactId>hutool-bom</artifactId>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-cache</artifactId> <artifactId>hutool-cache</artifactId>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-captcha</artifactId> <artifactId>hutool-captcha</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-core</artifactId> <artifactId>hutool-core</artifactId>

View File

@ -122,7 +122,7 @@ public class DateTime extends Date {
*/ */
public DateTime(Date date) { public DateTime(Date date) {
this( this(
date.getTime(),// date,//
(date instanceof DateTime) ? ((DateTime) date).timeZone : TimeZone.getDefault() (date instanceof DateTime) ? ((DateTime) date).timeZone : TimeZone.getDefault()
); );
} }
@ -135,7 +135,7 @@ public class DateTime extends Date {
* @since 4.1.2 * @since 4.1.2
*/ */
public DateTime(Date date, TimeZone timeZone) { public DateTime(Date date, TimeZone timeZone) {
this(date.getTime(), timeZone); this(ObjectUtil.defaultIfNull(date, new Date()).getTime(), timeZone);
} }
/** /**
@ -211,6 +211,38 @@ public class DateTime extends Date {
this.timeZone = ObjectUtil.defaultIfNull(timeZone, TimeZone.getDefault()); this.timeZone = ObjectUtil.defaultIfNull(timeZone, TimeZone.getDefault());
} }
/**
* 构造格式<br>
* <ol>
* <li>yyyy-MM-dd HH:mm:ss</li>
* <li>yyyy/MM/dd HH:mm:ss</li>
* <li>yyyy.MM.dd HH:mm:ss</li>
* <li>yyyy年MM月dd日 HH时mm分ss秒</li>
* <li>yyyy-MM-dd</li>
* <li>yyyy/MM/dd</li>
* <li>yyyy.MM.dd</li>
* <li>HH:mm:ss</li>
* <li>HH时mm分ss秒</li>
* <li>yyyy-MM-dd HH:mm</li>
* <li>yyyy-MM-dd HH:mm:ss.SSS</li>
* <li>yyyyMMddHHmmss</li>
* <li>yyyyMMddHHmmssSSS</li>
* <li>yyyyMMdd</li>
* <li>EEE, dd MMM yyyy HH:mm:ss z</li>
* <li>EEE MMM dd HH:mm:ss zzz yyyy</li>
* <li>yyyy-MM-dd'T'HH:mm:ss'Z'</li>
* <li>yyyy-MM-dd'T'HH:mm:ss.SSS'Z'</li>
* <li>yyyy-MM-dd'T'HH:mm:ssZ</li>
* <li>yyyy-MM-dd'T'HH:mm:ss.SSSZ</li>
* </ol>
*
* @param dateStr Date字符串
* @since 5.6.2
*/
public DateTime(CharSequence dateStr) {
this(DateUtil.parse(dateStr));
}
/** /**
* 构造 * 构造
* *

View File

@ -60,7 +60,6 @@ public class FileTypeUtil {
FILE_TYPE_MAP.put("4d546864000000060001", "mid"); // MIDI (mid) FILE_TYPE_MAP.put("4d546864000000060001", "mid"); // MIDI (mid)
FILE_TYPE_MAP.put("526172211a0700cf9073", "rar"); // WinRAR FILE_TYPE_MAP.put("526172211a0700cf9073", "rar"); // WinRAR
FILE_TYPE_MAP.put("235468697320636f6e66", "ini"); FILE_TYPE_MAP.put("235468697320636f6e66", "ini");
FILE_TYPE_MAP.put("504B0304140000000800", "ofd"); // ofd文件 国标版式文件
FILE_TYPE_MAP.put("504B03040a0000000000", "jar"); FILE_TYPE_MAP.put("504B03040a0000000000", "jar");
FILE_TYPE_MAP.put("504B0304140008000800", "jar"); FILE_TYPE_MAP.put("504B0304140008000800", "jar");
// MS Excel 注意wordmsi excel的文件头一样 // MS Excel 注意wordmsi excel的文件头一样
@ -140,7 +139,7 @@ public class FileTypeUtil {
* <pre> * <pre>
* 1无法识别类型默认按照扩展名识别 * 1无法识别类型默认按照扩展名识别
* 2xlsdocmsi头信息无法区分按照扩展名区分 * 2xlsdocmsi头信息无法区分按照扩展名区分
* 3zip可能为docxxlsxpptxjarwar头信息无法区分按照扩展名区分 * 3zip可能为docxxlsxpptxjarwarofd头信息无法区分按照扩展名区分
* </pre> * </pre>
* @param in {@link InputStream} * @param in {@link InputStream}
* @param filename 文件名 * @param filename 文件名
@ -162,7 +161,7 @@ public class FileTypeUtil {
typeName = "msi"; typeName = "msi";
} }
} else if ("zip".equals(typeName)) { } else if ("zip".equals(typeName)) {
// zip可能为docxxlsxpptxjarwar等格式扩展名辅助判断 // zip可能为docxxlsxpptxjarwarofd等格式扩展名辅助判断
final String extName = FileUtil.extName(filename); final String extName = FileUtil.extName(filename);
if ("docx".equalsIgnoreCase(extName)) { if ("docx".equalsIgnoreCase(extName)) {
typeName = "docx"; typeName = "docx";
@ -174,6 +173,8 @@ public class FileTypeUtil {
typeName = "jar"; typeName = "jar";
} else if ("war".equalsIgnoreCase(extName)) { } else if ("war".equalsIgnoreCase(extName)) {
typeName = "war"; typeName = "war";
} else if ("ofd".equalsIgnoreCase(extName)) {
typeName = "ofd";
} }
} }
return typeName; return typeName;

View File

@ -1,5 +1,7 @@
package cn.hutool.core.map; package cn.hutool.core.map;
import cn.hutool.core.util.StrUtil;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@ -13,7 +15,7 @@ import java.util.Map;
* @param <V> 值类型 * @param <V> 值类型
* @since 4.0.7 * @since 4.0.7
*/ */
public class CamelCaseLinkedMap<K, V> extends CamelCaseMap<K, V> { public class CamelCaseLinkedMap<K, V> extends CustomKeyMap<K, V> {
private static final long serialVersionUID = 4043263744224569870L; private static final long serialVersionUID = 4043263744224569870L;
// ------------------------------------------------------------------------- Constructor start // ------------------------------------------------------------------------- Constructor start
@ -63,4 +65,18 @@ public class CamelCaseLinkedMap<K, V> extends CamelCaseMap<K, V> {
super(new LinkedHashMap<>(initialCapacity, loadFactor)); super(new LinkedHashMap<>(initialCapacity, loadFactor));
} }
// ------------------------------------------------------------------------- Constructor end // ------------------------------------------------------------------------- Constructor end
/**
* 将Key转为驼峰风格如果key为字符串的话
*
* @param key KEY
* @return 驼峰Key
*/
@Override
protected Object customKey(Object key) {
if (key instanceof CharSequence) {
key = StrUtil.toCamelCase(key.toString());
}
return key;
}
} }

View File

@ -13,7 +13,7 @@ import java.util.Map;
* @param <V> 值类型 * @param <V> 值类型
* @since 3.3.1 * @since 3.3.1
*/ */
public class CaseInsensitiveLinkedMap<K, V> extends CaseInsensitiveMap<K, V> { public class CaseInsensitiveLinkedMap<K, V> extends CustomKeyMap<K, V> {
private static final long serialVersionUID = 4043263744224569870L; private static final long serialVersionUID = 4043263744224569870L;
// ------------------------------------------------------------------------- Constructor start // ------------------------------------------------------------------------- Constructor start
@ -64,4 +64,18 @@ public class CaseInsensitiveLinkedMap<K, V> extends CaseInsensitiveMap<K, V> {
super(new LinkedHashMap<>(initialCapacity, loadFactor)); super(new LinkedHashMap<>(initialCapacity, loadFactor));
} }
// ------------------------------------------------------------------------- Constructor end // ------------------------------------------------------------------------- Constructor end
/**
* 将Key转为小写
*
* @param key KEY
* @return 小写KEY
*/
@Override
protected Object customKey(Object key) {
if (key instanceof CharSequence) {
key = key.toString().toLowerCase();
}
return key;
}
} }

View File

@ -128,7 +128,7 @@ public class UrlPath {
final StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
for (String segment : segments) { for (String segment : segments) {
builder.append(CharUtil.SLASH).append(URLUtil.encodeAll(segment, charset)); builder.append(CharUtil.SLASH).append(URLUtil.encode(segment, charset));
} }
if (withEngTag || StrUtil.isEmpty(builder)) { if (withEngTag || StrUtil.isEmpty(builder)) {
builder.append(CharUtil.SLASH); builder.append(CharUtil.SLASH);

View File

@ -54,6 +54,30 @@ public class UnicodeUtil {
return sb.toString(); return sb.toString();
} }
/**
* 字符编码为Unicode形式
*
* @param c 被编码的字符
* @return Unicode字符串
* @since 5.6.2
* @see HexUtil#toUnicodeHex(char)
*/
public static String toUnicode(char c) {
return HexUtil.toUnicodeHex(c);
}
/**
* 字符编码为Unicode形式
*
* @param c 被编码的字符
* @return Unicode字符串
* @since 5.6.2
* @see HexUtil#toUnicodeHex(int)
*/
public static String toUnicode(int c) {
return HexUtil.toUnicodeHex(c);
}
/** /**
* 字符串编码为Unicode形式 * 字符串编码为Unicode形式
* *

View File

@ -89,7 +89,7 @@ public class ArrayUtil extends PrimitiveArrayUtil {
* @return 是否为非空 * @return 是否为非空
*/ */
public static <T> boolean isNotEmpty(T[] array) { public static <T> boolean isNotEmpty(T[] array) {
return (array != null && array.length != 0); return (null != array && array.length != 0);
} }
/** /**
@ -653,7 +653,7 @@ public class ArrayUtil extends PrimitiveArrayUtil {
* @since 3.2.2 * @since 3.2.2
*/ */
public static <T extends CharSequence> T[] removeEmpty(T[] array) { public static <T extends CharSequence> T[] removeEmpty(T[] array) {
return filter(array, (Filter<T>) t -> false == StrUtil.isEmpty(t)); return filter(array, StrUtil::isNotEmpty);
} }
/** /**
@ -665,7 +665,7 @@ public class ArrayUtil extends PrimitiveArrayUtil {
* @since 3.2.2 * @since 3.2.2
*/ */
public static <T extends CharSequence> T[] removeBlank(T[] array) { public static <T extends CharSequence> T[] removeBlank(T[] array) {
return filter(array, (Filter<T>) t -> false == StrUtil.isBlank(t)); return filter(array, StrUtil::isNotBlank);
} }
/** /**
@ -900,11 +900,7 @@ public class ArrayUtil extends PrimitiveArrayUtil {
* @return 是否为数组对象如果为{@code null} 返回false * @return 是否为数组对象如果为{@code null} 返回false
*/ */
public static boolean isArray(Object obj) { public static boolean isArray(Object obj) {
if (null == obj) { return null != obj && obj.getClass().isArray();
// throw new NullPointerException("Object check for isArray is null");
return false;
}
return obj.getClass().isArray();
} }
/** /**
@ -1227,35 +1223,39 @@ public class ArrayUtil extends PrimitiveArrayUtil {
* @return 连接后的字符串 * @return 连接后的字符串
*/ */
public static String join(Object array, CharSequence conjunction) { public static String join(Object array, CharSequence conjunction) {
if (isArray(array)) { if(null == array){
final Class<?> componentType = array.getClass().getComponentType(); throw new NullPointerException("Array must be not null!");
if (componentType.isPrimitive()) { }
final String componentTypeName = componentType.getName(); if (false == isArray(array)) {
switch (componentTypeName) { throw new IllegalArgumentException(StrUtil.format("[{}] is not a Array!", array.getClass()));
case "long": }
return join((long[]) array, conjunction);
case "int": final Class<?> componentType = array.getClass().getComponentType();
return join((int[]) array, conjunction); if (componentType.isPrimitive()) {
case "short": final String componentTypeName = componentType.getName();
return join((short[]) array, conjunction); switch (componentTypeName) {
case "char": case "long":
return join((char[]) array, conjunction); return join((long[]) array, conjunction);
case "byte": case "int":
return join((byte[]) array, conjunction); return join((int[]) array, conjunction);
case "boolean": case "short":
return join((boolean[]) array, conjunction); return join((short[]) array, conjunction);
case "float": case "char":
return join((float[]) array, conjunction); return join((char[]) array, conjunction);
case "double": case "byte":
return join((double[]) array, conjunction); return join((byte[]) array, conjunction);
default: case "boolean":
throw new UtilException("Unknown primitive type: [{}]", componentTypeName); return join((boolean[]) array, conjunction);
} case "float":
} else { return join((float[]) array, conjunction);
return join((Object[]) array, conjunction); case "double":
} return join((double[]) array, conjunction);
default:
throw new UtilException("Unknown primitive type: [{}]", componentTypeName);
}
} else {
return join((Object[]) array, conjunction);
} }
throw new UtilException(StrUtil.format("[{}] is not a Array!", array.getClass()));
} }
/** /**
@ -1266,7 +1266,9 @@ public class ArrayUtil extends PrimitiveArrayUtil {
* @since 3.0.1 * @since 3.0.1
*/ */
public static byte[] toArray(ByteBuffer bytebuffer) { public static byte[] toArray(ByteBuffer bytebuffer) {
if (false == bytebuffer.hasArray()) { if (bytebuffer.hasArray()) {
return Arrays.copyOfRange(bytebuffer.array(), bytebuffer.position(), bytebuffer.limit());
} else {
int oldPosition = bytebuffer.position(); int oldPosition = bytebuffer.position();
bytebuffer.position(0); bytebuffer.position(0);
int size = bytebuffer.limit(); int size = bytebuffer.limit();
@ -1274,8 +1276,6 @@ public class ArrayUtil extends PrimitiveArrayUtil {
bytebuffer.get(buffers); bytebuffer.get(buffers);
bytebuffer.position(oldPosition); bytebuffer.position(oldPosition);
return buffers; return buffers;
} else {
return Arrays.copyOfRange(bytebuffer.array(), bytebuffer.position(), bytebuffer.limit());
} }
} }

View File

@ -366,4 +366,47 @@ public class CharUtil {
public static int digit16(int b) { public static int digit16(int b) {
return Character.digit(b, 16); return Character.digit(b, 16);
} }
/**
* 将字母数字转换为带圈的字符
* <pre>
* '1' - '①'
* 'A' - 'Ⓐ'
* 'a' - 'ⓐ'
* </pre>
*
* @param c 被转换的字符如果字符不支持转换返回原字符
* @return 转换后的字符
* @since 5.6.2
*/
public static char toCloseChar(char c){
int result = c;
if(c >='1' && c <= '9'){
result = '①' + c - '1';
} else if(c >='A' && c <= 'Z'){
result = 'Ⓐ' + c - 'A';
} else if(c >='a' && c <= 'z'){
result = 'ⓐ' + c - 'a';
}
return (char) result;
}
/**
* [1-20]数字转换为带圈的字符
* <pre>
* 1 - '①'
* 12 - '⑫'
* 20 - '⑳'
* </pre>
*
* @param number 被转换的数字
* @return 转换后的字符
* @since 5.6.2
*/
public static char toCloseByNumber(int number){
if(number > 20){
throw new IllegalArgumentException("Number must be [1-20]");
}
return (char) ('①' + number - 1);
}
} }

View File

@ -57,11 +57,12 @@ public class DesensitizedUtil {
* DesensitizedUtil.desensitized("duandazhi-jack@gmail.com.cn", DesensitizedUtils.DesensitizedType.EMAIL)) = "d*************@gmail.com.cn" * DesensitizedUtil.desensitized("duandazhi-jack@gmail.com.cn", DesensitizedUtils.DesensitizedType.EMAIL)) = "d*************@gmail.com.cn"
* DesensitizedUtil.desensitized("1234567890", DesensitizedUtils.DesensitizedType.PASSWORD)) = "**********" * DesensitizedUtil.desensitized("1234567890", DesensitizedUtils.DesensitizedType.PASSWORD)) = "**********"
* DesensitizedUtil.desensitized("苏D40000", DesensitizedUtils.DesensitizedType.CAR_LICENSE)) = "苏D4***0" * DesensitizedUtil.desensitized("苏D40000", DesensitizedUtils.DesensitizedType.CAR_LICENSE)) = "苏D4***0"
* </pre>
* *
* @author dazer and neusoft and qiaomu * @param str 字符串
* @param str 字符串
* @param desensitizedType 脱敏类型;可以脱敏用户id中文名身份证号座机号手机号地址电子邮件密码 * @param desensitizedType 脱敏类型;可以脱敏用户id中文名身份证号座机号手机号地址电子邮件密码
* @return 脱敏之后的字符串 * @return 脱敏之后的字符串
* @author dazer and neusoft and qiaomu
* @since 5.6.2 * @since 5.6.2
*/ */
public static String desensitized(CharSequence str, DesensitizedUtil.DesensitizedType desensitizedType) { public static String desensitized(CharSequence str, DesensitizedUtil.DesensitizedType desensitizedType) {
@ -77,7 +78,7 @@ public class DesensitizedUtil {
newStr = DesensitizedUtil.chineseName(String.valueOf(str)); newStr = DesensitizedUtil.chineseName(String.valueOf(str));
break; break;
case ID_CARD: case ID_CARD:
newStr = DesensitizedUtil.idCardNum(String.valueOf(str),1,2); newStr = DesensitizedUtil.idCardNum(String.valueOf(str), 1, 2);
break; break;
case FIXED_PHONE: case FIXED_PHONE:
newStr = DesensitizedUtil.fixedPhone(String.valueOf(str)); newStr = DesensitizedUtil.fixedPhone(String.valueOf(str));
@ -159,7 +160,7 @@ public class DesensitizedUtil {
if (StrUtil.isBlank(num)) { if (StrUtil.isBlank(num)) {
return StrUtil.EMPTY; return StrUtil.EMPTY;
} }
return StrUtil.hide(num, 4, num.length()-2); return StrUtil.hide(num, 4, num.length() - 2);
} }
/** /**
@ -172,7 +173,7 @@ public class DesensitizedUtil {
if (StrUtil.isBlank(num)) { if (StrUtil.isBlank(num)) {
return StrUtil.EMPTY; return StrUtil.EMPTY;
} }
return StrUtil.hide(num, 3, num.length()-4); return StrUtil.hide(num, 3, num.length() - 4);
} }
/** /**
@ -187,11 +188,11 @@ public class DesensitizedUtil {
return StrUtil.EMPTY; return StrUtil.EMPTY;
} }
int length = address.length(); int length = address.length();
return StrUtil.hide(address, length-sensitiveSize, length); return StrUtil.hide(address, length - sensitiveSize, length);
} }
/** /**
* 电子邮箱邮箱前缀仅显示第一个字母前缀其他隐藏用星号代替@及后面的地址显示比如d**@126.com> * 电子邮箱邮箱前缀仅显示第一个字母前缀其他隐藏用星号代替@及后面的地址显示比如d**@126.com
* *
* @param email 邮箱 * @param email 邮箱
* @return 脱敏后的邮箱 * @return 脱敏后的邮箱
@ -222,11 +223,11 @@ public class DesensitizedUtil {
/** /**
* 中国车牌车牌中间用*代替 * 中国车牌车牌中间用*代替
* eg1null => "" * eg1null - ""
* eg1"" => "" * eg1"" - ""
* eg3苏D40000 => 苏D4***0 * eg3苏D40000 - 苏D4***0
* eg4陕A12345D => 陕A1****D * eg4陕A12345D - 陕A1****D
* eg5京A123 => 京A123 如果是错误的车牌不处理 * eg5京A123 - 京A123 如果是错误的车牌不处理
* *
* @param carLicense 完整的车牌号 * @param carLicense 完整的车牌号
* @return 脱敏后的车牌 * @return 脱敏后的车牌

View File

@ -262,7 +262,7 @@ public class HexUtil {
* 转换的字符串如果u后不足4位则前面用0填充例如 * 转换的字符串如果u后不足4位则前面用0填充例如
* *
* <pre> * <pre>
* '' =\u4f60 * '' =\u4f60
* </pre> * </pre>
* *
* @param value int值也可以是char * @param value int值也可以是char
@ -287,7 +287,7 @@ public class HexUtil {
* 转换的字符串如果u后不足4位则前面用0填充例如 * 转换的字符串如果u后不足4位则前面用0填充例如
* *
* <pre> * <pre>
* '我' =\u4f60 * '你' ='\u4f60'
* </pre> * </pre>
* *
* @param ch char值 * @param ch char值

View File

@ -1,6 +1,7 @@
package cn.hutool.core.collection; package cn.hutool.core.collection;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.Dict; import cn.hutool.core.lang.Dict;
import cn.hutool.core.lang.Editor; import cn.hutool.core.lang.Editor;
import cn.hutool.core.lang.Filter; import cn.hutool.core.lang.Filter;

View File

@ -32,6 +32,27 @@ public class DateTimeTest {
Assert.assertEquals(5, day); Assert.assertEquals(5, day);
} }
@Test
public void datetimeTest2() {
DateTime dateTime = new DateTime("2017-01-05 12:34:23");
//
int year = dateTime.year();
Assert.assertEquals(2017, year);
// 季度非季节
Quarter season = dateTime.quarterEnum();
Assert.assertEquals(Quarter.Q1, season);
// 月份
Month month = dateTime.monthEnum();
Assert.assertEquals(Month.JANUARY, month);
//
int day = dateTime.dayOfMonth();
Assert.assertEquals(5, day);
}
@Test @Test
public void quarterTest() { public void quarterTest() {
DateTime dateTime = new DateTime("2017-01-05 12:34:23", DatePattern.NORM_DATETIME_FORMAT); DateTime dateTime = new DateTime("2017-01-05 12:34:23", DatePattern.NORM_DATETIME_FORMAT);

View File

@ -235,4 +235,12 @@ public class UrlBuilderTest {
final UrlBuilder urlBuilder = UrlBuilder.of(webUrl, StandardCharsets.UTF_8); final UrlBuilder urlBuilder = UrlBuilder.of(webUrl, StandardCharsets.UTF_8);
Assert.assertEquals("a=123&b=4%3F6&c=789", urlBuilder.getQueryStr()); Assert.assertEquals("a=123&b=4%3F6&c=789", urlBuilder.getQueryStr());
} }
@Test
public void encodePathTest(){
// Path中的某些符号无需转义比如=
final String urlStr = "http://hq.sinajs.cn/list=sh600519";
final UrlBuilder urlBuilder = UrlBuilder.ofHttp(urlStr, CharsetUtil.CHARSET_UTF_8);
Assert.assertEquals(urlStr, urlBuilder.toString());
}
} }

View File

@ -53,6 +53,12 @@ public class ArrayUtilTest {
public void isNotEmptyTest() { public void isNotEmptyTest() {
int[] a = {1, 2}; int[] a = {1, 2};
Assert.assertTrue(ArrayUtil.isNotEmpty(a)); Assert.assertTrue(ArrayUtil.isNotEmpty(a));
String[] b = {"a", "b", "c"};
Assert.assertTrue(ArrayUtil.isNotEmpty(b));
Object c = new Object[]{"1", "2", 3, 4D};
Assert.assertTrue(ArrayUtil.isNotEmpty(c));
} }
@Test @Test
@ -253,15 +259,19 @@ public class ArrayUtilTest {
String[] array = {"aa", "bb", "cc", "dd"}; String[] array = {"aa", "bb", "cc", "dd"};
String join = ArrayUtil.join(array, ",", "[", "]"); String join = ArrayUtil.join(array, ",", "[", "]");
Assert.assertEquals("[aa],[bb],[cc],[dd]", join); Assert.assertEquals("[aa],[bb],[cc],[dd]", join);
Object array2 = new String[]{"aa", "bb", "cc", "dd"};
String join2 = ArrayUtil.join(array2, ",");
Assert.assertEquals("aa,bb,cc,dd", join2);
} }
@Test @Test
public void getArrayTypeTest() { public void getArrayTypeTest() {
Class<?> arrayType = ArrayUtil.getArrayType(int.class); Class<?> arrayType = ArrayUtil.getArrayType(int.class);
Assert.assertEquals(int[].class, arrayType); Assert.assertSame(int[].class, arrayType);
arrayType = ArrayUtil.getArrayType(String.class); arrayType = ArrayUtil.getArrayType(String.class);
Assert.assertEquals(String[].class, arrayType); Assert.assertSame(String[].class, arrayType);
} }
@Test @Test
@ -384,4 +394,34 @@ public class ArrayUtilTest {
final int[] reverse = ArrayUtil.reverse(a); final int[] reverse = ArrayUtil.reverse(a);
Assert.assertArrayEquals(new int[]{4,3,2,1}, reverse); Assert.assertArrayEquals(new int[]{4,3,2,1}, reverse);
} }
@Test
public void removeEmptyTest() {
String[] a = {"a", "b", "", null, " ", "c"};
String[] resultA = {"a", "b", " ", "c"};
Assert.assertArrayEquals(ArrayUtil.removeEmpty(a), resultA);
}
@Test
public void removeBlankTest() {
String[] a = {"a", "b", "", null, " ", "c"};
String[] resultA = {"a", "b", "c"};
Assert.assertArrayEquals(ArrayUtil.removeBlank(a), resultA);
}
@Test
public void nullToEmptyTest() {
String[] a = {"a", "b", "", null, " ", "c"};
String[] resultA = {"a", "b", "", "", " ", "c"};
Assert.assertArrayEquals(ArrayUtil.nullToEmpty(a), resultA);
}
@Test
public void wrapTest() {
Object a = new int[]{1, 2, 3, 4};
Object[] wrapA = ArrayUtil.wrap(a);
for (Object o : wrapA) {
Assert.assertTrue(o instanceof Integer);
}
}
} }

View File

@ -38,4 +38,18 @@ public class CharUtilTest {
char a3 = '\u3000'; char a3 = '\u3000';
Assert.assertTrue(CharUtil.isBlankChar(a3)); Assert.assertTrue(CharUtil.isBlankChar(a3));
} }
@Test
public void toCloseCharTest(){
Assert.assertEquals('②', CharUtil.toCloseChar('2'));
Assert.assertEquals('Ⓜ', CharUtil.toCloseChar('M'));
Assert.assertEquals('ⓡ', CharUtil.toCloseChar('r'));
}
@Test
public void toCloseByNumberTest(){
Assert.assertEquals('②', CharUtil.toCloseByNumber(2));
Assert.assertEquals('⑫', CharUtil.toCloseByNumber(12));
Assert.assertEquals('⑳', CharUtil.toCloseByNumber(20));
}
} }

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-cron</artifactId> <artifactId>hutool-cron</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-crypto</artifactId> <artifactId>hutool-crypto</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-db</artifactId> <artifactId>hutool-db</artifactId>
@ -26,7 +26,7 @@
<mongo.version>3.12.8</mongo.version> <mongo.version>3.12.8</mongo.version>
<sqlite.version>3.34.0</sqlite.version> <sqlite.version>3.34.0</sqlite.version>
<hsqldb.version>2.5.1</hsqldb.version> <hsqldb.version>2.5.1</hsqldb.version>
<jedis.version>3.5.1</jedis.version> <jedis.version>3.5.2</jedis.version>
</properties> </properties>
<dependencies> <dependencies>
@ -79,8 +79,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.chris2018998</groupId> <groupId>com.github.chris2018998</groupId>
<artifactId>BeeCP</artifactId> <artifactId>beecp</artifactId>
<version>2.5.3</version> <version>3.1.2</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>
@ -148,7 +148,7 @@
<dependency> <dependency>
<groupId>org.postgresql</groupId> <groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>
<version>42.2.18.jre7</version> <version>42.2.19.jre7</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -33,11 +33,6 @@ public class BeeDSFactory extends AbstractDSFactory {
final BeeDataSourceConfig beeConfig = new BeeDataSourceConfig(driver, jdbcUrl, user, pass); final BeeDataSourceConfig beeConfig = new BeeDataSourceConfig(driver, jdbcUrl, user, pass);
poolSetting.toBean(beeConfig); poolSetting.toBean(beeConfig);
// 修复BeeCP默认参数无效问题
if(beeConfig.getBorrowConcurrentSize() > beeConfig.getMaxActive()){
beeConfig.setMaxActive(beeConfig.getBorrowConcurrentSize() + 1);
}
// remarks等特殊配置since 5.3.8 // remarks等特殊配置since 5.3.8
String connValue; String connValue;
for (String key : KEY_CONN_PROPS) { for (String key : KEY_CONN_PROPS) {

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-dfa</artifactId> <artifactId>hutool-dfa</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-extra</artifactId> <artifactId>hutool-extra</artifactId>
@ -30,7 +30,7 @@
<net.version>3.7.2</net.version> <net.version>3.7.2</net.version>
<emoji-java.version>5.1.1</emoji-java.version> <emoji-java.version>5.1.1</emoji-java.version>
<servlet-api.version>4.0.1</servlet-api.version> <servlet-api.version>4.0.1</servlet-api.version>
<spring-boot.version>2.4.3</spring-boot.version> <spring-boot.version>2.4.4</spring-boot.version>
<cglib.version>3.3.0</cglib.version> <cglib.version>3.3.0</cglib.version>
</properties> </properties>
@ -241,7 +241,7 @@
<dependency> <dependency>
<groupId>org.apache.lucene</groupId> <groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-smartcn</artifactId> <artifactId>lucene-analyzers-smartcn</artifactId>
<version>8.7.0</version> <version>8.8.1</version>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
@ -426,7 +426,7 @@
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId> <artifactId>spring-expression</artifactId>
<version>5.3.2</version> <version>5.3.5</version>
<scope>compile</scope> <scope>compile</scope>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
@ -448,7 +448,7 @@
<dependency> <dependency>
<groupId>org.tukaani</groupId> <groupId>org.tukaani</groupId>
<artifactId>xz</artifactId> <artifactId>xz</artifactId>
<version>1.8</version> <version>1.9</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -320,7 +320,7 @@ public class QrCodeUtil {
// ------------------------------------------------------------------------------------------------------------------- decode // ------------------------------------------------------------------------------------------------------------------- decode
/** /**
* 解码二维码图片为文本 * 解码二维码或条形码图片为文本
* *
* @param qrCodeInputstream 二维码输入流 * @param qrCodeInputstream 二维码输入流
* @return 解码文本 * @return 解码文本
@ -330,7 +330,7 @@ public class QrCodeUtil {
} }
/** /**
* 解码二维码图片为文本 * 解码二维码或条形码图片为文本
* *
* @param qrCodeFile 二维码文件 * @param qrCodeFile 二维码文件
* @return 解码文本 * @return 解码文本
@ -340,7 +340,7 @@ public class QrCodeUtil {
} }
/** /**
* 将二维码图片解码为文本 * 将二维码或条形码图片解码为文本
* *
* @param image {@link Image} 二维码图片 * @param image {@link Image} 二维码图片
* @return 解码后的文本 * @return 解码后的文本
@ -350,7 +350,7 @@ public class QrCodeUtil {
} }
/** /**
* 将二维码图片解码为文本 * 将二维码或条形码图片解码为文本
* *
* @param image {@link Image} 二维码图片 * @param image {@link Image} 二维码图片
* @param isTryHarder 是否优化精度 * @param isTryHarder 是否优化精度

View File

@ -58,6 +58,7 @@ public class ServletUtil {
public static final String METHOD_TRACE = "TRACE"; public static final String METHOD_TRACE = "TRACE";
// --------------------------------------------------------- getParam start // --------------------------------------------------------- getParam start
/** /**
* 获得所有请求参数 * 获得所有请求参数
* *
@ -92,7 +93,7 @@ public class ServletUtil {
* @since 4.0.2 * @since 4.0.2
*/ */
public static String getBody(ServletRequest request) { public static String getBody(ServletRequest request) {
try(final BufferedReader reader = request.getReader()) { try (final BufferedReader reader = request.getReader()) {
return IoUtil.read(reader); return IoUtil.read(reader);
} catch (IOException e) { } catch (IOException e) {
throw new IORuntimeException(e); throw new IORuntimeException(e);
@ -117,12 +118,13 @@ public class ServletUtil {
// --------------------------------------------------------- getParam end // --------------------------------------------------------- getParam end
// --------------------------------------------------------- fillBean start // --------------------------------------------------------- fillBean start
/** /**
* ServletRequest 参数转Bean * ServletRequest 参数转Bean
* *
* @param <T> Bean类型 * @param <T> Bean类型
* @param request ServletRequest * @param request ServletRequest
* @param bean Bean * @param bean Bean
* @param copyOptions 注入时的设置 * @param copyOptions 注入时的设置
* @return Bean * @return Bean
* @since 3.0.4 * @since 3.0.4
@ -133,17 +135,17 @@ public class ServletUtil {
@Override @Override
public Object value(String key, Type valueType) { public Object value(String key, Type valueType) {
String[] values = request.getParameterValues(key); String[] values = request.getParameterValues(key);
if(ArrayUtil.isEmpty(values)){ if (ArrayUtil.isEmpty(values)) {
values = request.getParameterValues(beanName + StrUtil.DOT + key); values = request.getParameterValues(beanName + StrUtil.DOT + key);
if(ArrayUtil.isEmpty(values)){ if (ArrayUtil.isEmpty(values)) {
return null; return null;
} }
} }
if(1 == values.length){ if (1 == values.length) {
// 单值表单直接返回这个值 // 单值表单直接返回这个值
return values[0]; return values[0];
}else{ } else {
// 多值表单返回数组 // 多值表单返回数组
return values; return values;
} }
@ -160,9 +162,9 @@ public class ServletUtil {
/** /**
* ServletRequest 参数转Bean * ServletRequest 参数转Bean
* *
* @param <T> Bean类型 * @param <T> Bean类型
* @param request {@link ServletRequest} * @param request {@link ServletRequest}
* @param bean Bean * @param bean Bean
* @param isIgnoreError 是否忽略注入错误 * @param isIgnoreError 是否忽略注入错误
* @return Bean * @return Bean
*/ */
@ -173,9 +175,9 @@ public class ServletUtil {
/** /**
* ServletRequest 参数转Bean * ServletRequest 参数转Bean
* *
* @param <T> Bean类型 * @param <T> Bean类型
* @param request ServletRequest * @param request ServletRequest
* @param beanClass Bean Class * @param beanClass Bean Class
* @param isIgnoreError 是否忽略注入错误 * @param isIgnoreError 是否忽略注入错误
* @return Bean * @return Bean
*/ */
@ -202,12 +204,12 @@ public class ServletUtil {
* 需要注意的是使用此方法获取的客户IP地址必须在Http服务器例如Nginx中配置头信息否则容易造成IP伪造 * 需要注意的是使用此方法获取的客户IP地址必须在Http服务器例如Nginx中配置头信息否则容易造成IP伪造
* </p> * </p>
* *
* @param request 请求对象{@link HttpServletRequest} * @param request 请求对象{@link HttpServletRequest}
* @param otherHeaderNames 其他自定义头文件通常在Http服务器例如Nginx中配置 * @param otherHeaderNames 其他自定义头文件通常在Http服务器例如Nginx中配置
* @return IP地址 * @return IP地址
*/ */
public static String getClientIP(HttpServletRequest request, String... otherHeaderNames) { public static String getClientIP(HttpServletRequest request, String... otherHeaderNames) {
String[] headers = { "X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR" }; String[] headers = {"X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"};
if (ArrayUtil.isNotEmpty(otherHeaderNames)) { if (ArrayUtil.isNotEmpty(otherHeaderNames)) {
headers = ArrayUtil.addAll(headers, otherHeaderNames); headers = ArrayUtil.addAll(headers, otherHeaderNames);
} }
@ -223,7 +225,7 @@ public class ServletUtil {
* 需要注意的是使用此方法获取的客户IP地址必须在Http服务器例如Nginx中配置头信息否则容易造成IP伪造 * 需要注意的是使用此方法获取的客户IP地址必须在Http服务器例如Nginx中配置头信息否则容易造成IP伪造
* </p> * </p>
* *
* @param request 请求对象{@link HttpServletRequest} * @param request 请求对象{@link HttpServletRequest}
* @param headerNames 自定义头通常在Http服务器例如Nginx中配置 * @param headerNames 自定义头通常在Http服务器例如Nginx中配置
* @return IP地址 * @return IP地址
* @since 4.4.1 * @since 4.4.1
@ -258,7 +260,7 @@ public class ServletUtil {
* 包括文件和普通表单数据<br> * 包括文件和普通表单数据<br>
* 在同一次请求中此方法只能被执行一次 * 在同一次请求中此方法只能被执行一次
* *
* @param request {@link ServletRequest} * @param request {@link ServletRequest}
* @param uploadSetting 上传文件的设定包括最大文件大小保存在内存的边界大小临时目录扩展名限定等 * @param uploadSetting 上传文件的设定包括最大文件大小保存在内存的边界大小临时目录扩展名限定等
* @return MultiPart表单 * @return MultiPart表单
* @throws IORuntimeException IO异常 * @throws IORuntimeException IO异常
@ -276,6 +278,7 @@ public class ServletUtil {
} }
// --------------------------------------------------------- Header start // --------------------------------------------------------- Header start
/** /**
* 获取请求所有的头header信息 * 获取请求所有的头header信息
* *
@ -300,7 +303,7 @@ public class ServletUtil {
/** /**
* 忽略大小写获得请求header中的信息 * 忽略大小写获得请求header中的信息
* *
* @param request 请求对象{@link HttpServletRequest} * @param request 请求对象{@link HttpServletRequest}
* @param nameIgnoreCase 忽略大小写头信息的KEY * @param nameIgnoreCase 忽略大小写头信息的KEY
* @return header值 * @return header值
*/ */
@ -320,8 +323,8 @@ public class ServletUtil {
/** /**
* 获得请求header中的信息 * 获得请求header中的信息
* *
* @param request 请求对象{@link HttpServletRequest} * @param request 请求对象{@link HttpServletRequest}
* @param name 头信息的KEY * @param name 头信息的KEY
* @param charsetName 字符集 * @param charsetName 字符集
* @return header值 * @return header值
*/ */
@ -333,7 +336,7 @@ public class ServletUtil {
* 获得请求header中的信息 * 获得请求header中的信息
* *
* @param request 请求对象{@link HttpServletRequest} * @param request 请求对象{@link HttpServletRequest}
* @param name 头信息的KEY * @param name 头信息的KEY
* @param charset 字符集 * @param charset 字符集
* @return header值 * @return header值
* @since 4.6.2 * @since 4.6.2
@ -402,11 +405,12 @@ public class ServletUtil {
// --------------------------------------------------------- Header end // --------------------------------------------------------- Header end
// --------------------------------------------------------- Cookie start // --------------------------------------------------------- Cookie start
/** /**
* 获得指定的Cookie * 获得指定的Cookie
* *
* @param httpServletRequest {@link HttpServletRequest} * @param httpServletRequest {@link HttpServletRequest}
* @param name cookie名 * @param name cookie名
* @return Cookie对象 * @return Cookie对象
*/ */
public static Cookie getCookie(HttpServletRequest httpServletRequest, String name) { public static Cookie getCookie(HttpServletRequest httpServletRequest, String name) {
@ -421,7 +425,7 @@ public class ServletUtil {
*/ */
public static Map<String, Cookie> readCookieMap(HttpServletRequest httpServletRequest) { public static Map<String, Cookie> readCookieMap(HttpServletRequest httpServletRequest) {
final Cookie[] cookies = httpServletRequest.getCookies(); final Cookie[] cookies = httpServletRequest.getCookies();
if(ArrayUtil.isEmpty(cookies)){ if (ArrayUtil.isEmpty(cookies)) {
return MapUtil.empty(); return MapUtil.empty();
} }
@ -435,7 +439,7 @@ public class ServletUtil {
* 设定返回给客户端的Cookie * 设定返回给客户端的Cookie
* *
* @param response 响应对象{@link HttpServletResponse} * @param response 响应对象{@link HttpServletResponse}
* @param cookie Servlet Cookie对象 * @param cookie Servlet Cookie对象
*/ */
public static void addCookie(HttpServletResponse response, Cookie cookie) { public static void addCookie(HttpServletResponse response, Cookie cookie) {
response.addCookie(cookie); response.addCookie(cookie);
@ -445,8 +449,8 @@ public class ServletUtil {
* 设定返回给客户端的Cookie * 设定返回给客户端的Cookie
* *
* @param response 响应对象{@link HttpServletResponse} * @param response 响应对象{@link HttpServletResponse}
* @param name Cookie名 * @param name Cookie名
* @param value Cookie值 * @param value Cookie值
*/ */
public static void addCookie(HttpServletResponse response, String name, String value) { public static void addCookie(HttpServletResponse response, String name, String value) {
response.addCookie(new Cookie(name, value)); response.addCookie(new Cookie(name, value));
@ -455,12 +459,12 @@ public class ServletUtil {
/** /**
* 设定返回给客户端的Cookie * 设定返回给客户端的Cookie
* *
* @param response 响应对象{@link HttpServletResponse} * @param response 响应对象{@link HttpServletResponse}
* @param name cookie名 * @param name cookie名
* @param value cookie值 * @param value cookie值
* @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. &gt;0 : Cookie存在的秒数. * @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. &gt;0 : Cookie存在的秒数.
* @param path Cookie的有效路径 * @param path Cookie的有效路径
* @param domain the domain name within which this cookie is visible; form is according to RFC 2109 * @param domain the domain name within which this cookie is visible; form is according to RFC 2109
*/ */
public static void addCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds, String path, String domain) { public static void addCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds, String path, String domain) {
Cookie cookie = new Cookie(name, value); Cookie cookie = new Cookie(name, value);
@ -477,9 +481,9 @@ public class ServletUtil {
* Path: "/"<br> * Path: "/"<br>
* No Domain * No Domain
* *
* @param response 响应对象{@link HttpServletResponse} * @param response 响应对象{@link HttpServletResponse}
* @param name cookie名 * @param name cookie名
* @param value cookie值 * @param value cookie值
* @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. &gt;0 : Cookie存在的秒数. * @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. &gt;0 : Cookie存在的秒数.
*/ */
public static void addCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds) { public static void addCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds) {
@ -488,6 +492,7 @@ public class ServletUtil {
// --------------------------------------------------------- Cookie end // --------------------------------------------------------- Cookie end
// --------------------------------------------------------- Response start // --------------------------------------------------------- Response start
/** /**
* 获得PrintWriter * 获得PrintWriter
* *
@ -506,8 +511,8 @@ public class ServletUtil {
/** /**
* 返回数据给客户端 * 返回数据给客户端
* *
* @param response 响应对象{@link HttpServletResponse} * @param response 响应对象{@link HttpServletResponse}
* @param text 返回的内容 * @param text 返回的内容
* @param contentType 返回的类型 * @param contentType 返回的类型
*/ */
public static void write(HttpServletResponse response, String text, String contentType) { public static void write(HttpServletResponse response, String text, String contentType) {
@ -528,7 +533,7 @@ public class ServletUtil {
* 返回文件给客户端 * 返回文件给客户端
* *
* @param response 响应对象{@link HttpServletResponse} * @param response 响应对象{@link HttpServletResponse}
* @param file 写出的文件对象 * @param file 写出的文件对象
* @since 4.1.15 * @since 4.1.15
*/ */
public static void write(HttpServletResponse response, File file) { public static void write(HttpServletResponse response, File file) {
@ -546,21 +551,21 @@ public class ServletUtil {
/** /**
* 返回数据给客户端 * 返回数据给客户端
* *
* @param response 响应对象{@link HttpServletResponse} * @param response 响应对象{@link HttpServletResponse}
* @param in 需要返回客户端的内容 * @param in 需要返回客户端的内容
* @param contentType 返回的类型 * @param contentType 返回的类型
* *
* 1application/pdf * 1application/pdf
* 2application/vnd.ms-excel * 2application/vnd.ms-excel
* 3application/msword * 3application/msword
* 4application/vnd.ms-powerpoint * 4application/vnd.ms-powerpoint
* docxxlsx 这种 office 2007 格式 设置 MIME;网页里面docx 文件是没问题但是下载下来了之后就变成doc格式了 * docxxlsx 这种 office 2007 格式 设置 MIME;网页里面docx 文件是没问题但是下载下来了之后就变成doc格式了
* https://blog.csdn.net/cyh2260629/article/details/73824760 * https://blog.csdn.net/cyh2260629/article/details/73824760
* 5MIME_EXCELX_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; * 5MIME_EXCELX_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
* 6MIME_PPTX_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; * 6MIME_PPTX_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
* 7MIME_WORDX_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; * 7MIME_WORDX_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
* 8MIME_STREAM_TYPE = "application/octet-stream;charset=utf-8"; #原始字节流 * 8MIME_STREAM_TYPE = "application/octet-stream;charset=utf-8"; #原始字节流
* @param fileName 文件名 * @param fileName 文件名
* @since 4.1.15 * @since 4.1.15
*/ */
public static void write(HttpServletResponse response, InputStream in, String contentType, String fileName) { public static void write(HttpServletResponse response, InputStream in, String contentType, String fileName) {
@ -573,8 +578,8 @@ public class ServletUtil {
/** /**
* 返回数据给客户端 * 返回数据给客户端
* *
* @param response 响应对象{@link HttpServletResponse} * @param response 响应对象{@link HttpServletResponse}
* @param in 需要返回客户端的内容 * @param in 需要返回客户端的内容
* @param contentType 返回的类型 * @param contentType 返回的类型
*/ */
public static void write(HttpServletResponse response, InputStream in, String contentType) { public static void write(HttpServletResponse response, InputStream in, String contentType) {
@ -586,7 +591,7 @@ public class ServletUtil {
* 返回数据给客户端 * 返回数据给客户端
* *
* @param response 响应对象{@link HttpServletResponse} * @param response 响应对象{@link HttpServletResponse}
* @param in 需要返回客户端的内容 * @param in 需要返回客户端的内容
*/ */
public static void write(HttpServletResponse response, InputStream in) { public static void write(HttpServletResponse response, InputStream in) {
write(response, in, IoUtil.DEFAULT_BUFFER_SIZE); write(response, in, IoUtil.DEFAULT_BUFFER_SIZE);
@ -595,8 +600,8 @@ public class ServletUtil {
/** /**
* 返回数据给客户端 * 返回数据给客户端
* *
* @param response 响应对象{@link HttpServletResponse} * @param response 响应对象{@link HttpServletResponse}
* @param in 需要返回客户端的内容 * @param in 需要返回客户端的内容
* @param bufferSize 缓存大小 * @param bufferSize 缓存大小
*/ */
public static void write(HttpServletResponse response, InputStream in, int bufferSize) { public static void write(HttpServletResponse response, InputStream in, int bufferSize) {
@ -616,15 +621,15 @@ public class ServletUtil {
* 设置响应的Header * 设置响应的Header
* *
* @param response 响应对象{@link HttpServletResponse} * @param response 响应对象{@link HttpServletResponse}
* @param name * @param name
* @param value 可以是StringDate int * @param value 可以是StringDate int
*/ */
public static void setHeader(HttpServletResponse response, String name, Object value) { public static void setHeader(HttpServletResponse response, String name, Object value) {
if (value instanceof String) { if (value instanceof String) {
response.setHeader(name, (String) value); response.setHeader(name, (String) value);
} else if (Date.class.isAssignableFrom(value.getClass())) { } else if (Date.class.isAssignableFrom(value.getClass())) {
response.setDateHeader(name, ((Date) value).getTime()); response.setDateHeader(name, ((Date) value).getTime());
} else if (value instanceof Integer || "int".equals(value.getClass().getSimpleName().toLowerCase())) { } else if (value instanceof Integer || "int".equalsIgnoreCase(value.getClass().getSimpleName())) {
response.setIntHeader(name, (int) value); response.setIntHeader(name, (int) value);
} else { } else {
response.setHeader(name, value.toString()); response.setHeader(name, value.toString());

View File

@ -9,6 +9,8 @@ import cn.hutool.extra.template.TemplateConfig.ResourceMode;
import cn.hutool.extra.template.TemplateEngine; import cn.hutool.extra.template.TemplateEngine;
import com.jfinal.template.source.FileSourceFactory; import com.jfinal.template.source.FileSourceFactory;
import java.io.File;
/** /**
* Enjoy库的引擎包装 * Enjoy库的引擎包装
* *
@ -99,7 +101,8 @@ public class EnjoyEngine implements TemplateEngine {
break; break;
case WEB_ROOT: case WEB_ROOT:
engine.setSourceFactory(new FileSourceFactory()); engine.setSourceFactory(new FileSourceFactory());
engine.setBaseTemplatePath(FileUtil.getAbsolutePath(FileUtil.getWebRoot())); final File root = FileUtil.file(FileUtil.getWebRoot(), config.getPath());
engine.setBaseTemplatePath(FileUtil.getAbsolutePath(root));
break; break;
default: default:
break; break;

View File

@ -1,11 +1,16 @@
package cn.hutool.extra.template.engine.wit; package cn.hutool.extra.template.engine.wit;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.extra.template.Template; import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig; import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine; import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateException; import cn.hutool.extra.template.TemplateException;
import org.febit.wit.Engine; import org.febit.wit.Engine;
import org.febit.wit.exceptions.ResourceNotFoundException; import org.febit.wit.exceptions.ResourceNotFoundException;
import org.febit.wit.util.Props;
import java.io.File;
/** /**
* Wit(http://zqq90.github.io/webit-script/)模板引擎封装 * Wit(http://zqq90.github.io/webit-script/)模板引擎封装
@ -75,10 +80,34 @@ public class WitEngine implements TemplateEngine {
* @return {@link Engine} * @return {@link Engine}
*/ */
private static Engine createEngine(TemplateConfig config) { private static Engine createEngine(TemplateConfig config) {
if (null == config) { final Props configProps = Engine.createConfigProps("");
config = TemplateConfig.DEFAULT; Dict dict = null;
if (null != config) {
dict = Dict.create();
// 自定义编码
dict.set("DEFAULT_ENCODING", config.getCharset());
switch (config.getResourceMode()){
case CLASSPATH:
configProps.set("pathLoader.root", config.getPath());
configProps.set("routeLoader.defaultLoader", "classpathLoader");
break;
case STRING:
configProps.set("routeLoader.defaultLoader", "stringLoader");
break;
case FILE:
configProps.set("pathLoader.root", config.getPath());
configProps.set("routeLoader.defaultLoader", "fileLoader");
break;
case WEB_ROOT:
final File root = FileUtil.file(FileUtil.getWebRoot(), config.getPath());
configProps.set("pathLoader.root", FileUtil.getAbsolutePath(root));
configProps.set("routeLoader.defaultLoader", "fileLoader");
break;
}
} }
return Engine.create(); return Engine.create(configProps,dict);
} }
} }

View File

@ -54,6 +54,14 @@ public class QrCodeUtilTest {
Console.log(decode); Console.log(decode);
} }
@Test
@Ignore
public void decodeTest2() {
// 条形码
String decode = QrCodeUtil.decode(FileUtil.file("d:/test/90.png"));
Console.log(decode);
}
@Test @Test
@Ignore @Ignore
public void generateAsBase64Test(){ public void generateAsBase64Test(){

View File

@ -1,5 +1,6 @@
package cn.hutool.extra.servlet; package cn.hutool.extra.servlet;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -8,18 +9,22 @@ import java.nio.charset.StandardCharsets;
/** /**
* ServletUtil工具类测试 * ServletUtil工具类测试
*
* @author dazer * @author dazer
* @date 2021/3/24 15:02 * @date 2021/3/24 15:02
* @see ServletUtil * @see ServletUtil
*/ */
public class ServletUtilTest { public class ServletUtilTest {
@Test @Test
@Ignore
public void writeTest() { public void writeTest() {
HttpServletResponse response = null; HttpServletResponse response = null;
byte[] bytes = new String("地球是我们共同的家园,需要大家珍惜.").getBytes(StandardCharsets.UTF_8); byte[] bytes = "地球是我们共同的家园,需要大家珍惜.".getBytes(StandardCharsets.UTF_8);
//下载文件 //下载文件
// 这里没法直接测试直接写到这里方便调用 // 这里没法直接测试直接写到这里方便调用
//noinspection ConstantConditions
if (response != null) { if (response != null) {
String fileName = "签名文件.pdf"; String fileName = "签名文件.pdf";
String contentType = "application/pdf";// application/octet-streamimage/jpegimage/gif String contentType = "application/pdf";// application/octet-streamimage/jpegimage/gif

View File

@ -157,10 +157,20 @@ public class TemplateUtilTest {
@Test @Test
public void WitEngineTest() { public void WitEngineTest() {
TemplateEngine engine = TemplateUtil.createEngine( //classpath模板
new TemplateConfig("templates", ResourceMode.CLASSPATH).setCustomEngine(WitEngine.class)); TemplateConfig config = new TemplateConfig("templates", ResourceMode.CLASSPATH)
Template template = engine.getTemplate("/templates/wit_test.wit"); .setCustomEngine(WitEngine.class);
TemplateEngine engine = TemplateUtil.createEngine(config);
Template template = engine.getTemplate("/wit_test.wit");
String result = template.render(Dict.create().set("name", "hutool")); String result = template.render(Dict.create().set("name", "hutool"));
Assert.assertEquals("hello,hutool", StrUtil.trim(result)); Assert.assertEquals("hello,hutool", StrUtil.trim(result));
// 字符串模板
config = new TemplateConfig("templates", ResourceMode.STRING)
.setCustomEngine(WitEngine.class);
engine = TemplateUtil.createEngine(config);
template = engine.getTemplate("<%var name;%>hello,${name}");
result = template.render(Dict.create().set("name", "hutool"));
Assert.assertEquals("hello,hutool", StrUtil.trim(result));
} }
} }

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-http</artifactId> <artifactId>hutool-http</artifactId>

View File

@ -318,4 +318,11 @@ public class HttpUtilTest {
final String s = HttpUtil.get(url); final String s = HttpUtil.get(url);
Console.log(s); Console.log(s);
} }
@Test
@Ignore
public void sinajsTest(){
final String s = HttpUtil.get("http://hq.sinajs.cn/list=sh600519");
Console.log(s);
}
} }

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-json</artifactId> <artifactId>hutool-json</artifactId>

View File

@ -50,7 +50,9 @@ final class InternalJSONUtil {
} else if (value instanceof Iterable || value instanceof Iterator || value.getClass().isArray()) { } else if (value instanceof Iterable || value instanceof Iterator || value.getClass().isArray()) {
new JSONArray(value).write(writer, indentFactor, indent); new JSONArray(value).write(writer, indentFactor, indent);
} else if (value instanceof Number) { } else if (value instanceof Number) {
writer.write(NumberUtil.toStr((Number) value)); // since 5.6.2可配置是否去除末尾多余0例如如果为true,5.0返回5
final boolean isStripTrailingZeros = null == config || config.isStripTrailingZeros();
writer.write(NumberUtil.toStr((Number) value, isStripTrailingZeros));
} else if (value instanceof Date || value instanceof Calendar || value instanceof TemporalAccessor) { } else if (value instanceof Date || value instanceof Calendar || value instanceof TemporalAccessor) {
final String format = (null == config) ? null : config.getDateFormat(); final String format = (null == config) ? null : config.getDateFormat();
writer.write(formatDate(value, format)); writer.write(formatDate(value, format));

View File

@ -36,6 +36,11 @@ public class JSONConfig implements Serializable {
*/ */
private boolean transientSupport = true; private boolean transientSupport = true;
/**
* 是否去除末尾多余0例如如果为true,5.0返回5
*/
private boolean stripTrailingZeros = true;
/** /**
* 创建默认的配置项 * 创建默认的配置项
* *
@ -192,4 +197,23 @@ public class JSONConfig implements Serializable {
this.transientSupport = transientSupport; this.transientSupport = transientSupport;
return this; return this;
} }
/**
* 是否去除末尾多余0例如如果为true,5.0返回5
* @return 是否去除末尾多余0例如如果为true,5.0返回5
* @since 5.6.2
*/
public boolean isStripTrailingZeros() {
return stripTrailingZeros;
}
/**
* 设置是否去除末尾多余0例如如果为true,5.0返回5
* @param stripTrailingZeros 是否去除末尾多余0例如如果为true,5.0返回5
* @since 5.6.2
*/
public JSONConfig setStripTrailingZeros(boolean stripTrailingZeros) {
this.stripTrailingZeros = stripTrailingZeros;
return this;
}
} }

View File

@ -173,6 +173,23 @@ public class JSONUtilTest {
Assert.assertEquals("{\"test2\":12.0}", jsonObject.toString()); Assert.assertEquals("{\"test2\":12.0}", jsonObject.toString());
} }
@Test
public void setStripTrailingZerosTest() {
// 默认去除多余的0
final JSONObject jsonObjectDefault = JSONUtil.createObj()
.set("test2", 12.00D);
Assert.assertEquals("{\"test2\":12}", jsonObjectDefault.toString());
// 不去除多余的0
final JSONObject jsonObject = JSONUtil.createObj(JSONConfig.create().setStripTrailingZeros(false))
.set("test2", 12.00D);
Assert.assertEquals("{\"test2\":12.0}", jsonObject.toString());
// 去除多余的0
jsonObject.getConfig().setStripTrailingZeros(true);
Assert.assertEquals("{\"test2\":12}", jsonObject.toString());
}
@Test @Test
public void parseObjTest() { public void parseObjTest() {
// 测试转义 // 测试转义

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-log</artifactId> <artifactId>hutool-log</artifactId>

View File

@ -8,7 +8,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-poi</artifactId> <artifactId>hutool-poi</artifactId>
@ -44,7 +44,7 @@
<dependency> <dependency>
<groupId>org.ofdrw</groupId> <groupId>org.ofdrw</groupId>
<artifactId>ofdrw-full</artifactId> <artifactId>ofdrw-full</artifactId>
<version>1.7.3</version> <version>1.7.4</version>
<scope>compile</scope> <scope>compile</scope>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>

View File

@ -8,7 +8,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-script</artifactId> <artifactId>hutool-script</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-setting</artifactId> <artifactId>hutool-setting</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-socket</artifactId> <artifactId>hutool-socket</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-system</artifactId> <artifactId>hutool-system</artifactId>
@ -26,7 +26,7 @@
<dependency> <dependency>
<groupId>com.github.oshi</groupId> <groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId> <artifactId>oshi-core</artifactId>
<version>5.6.0</version> <version>5.6.1</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -8,7 +8,7 @@
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.6.2-SNAPSHOT</version> <version>5.6.3-SNAPSHOT</version>
<name>hutool</name> <name>hutool</name>
<description>Hutool是一个小而全的Java工具类库通过静态方法封装降低相关API的学习成本提高工作效率使Java拥有函数式语言般的优雅让Java语言也可以“甜甜的”。</description> <description>Hutool是一个小而全的Java工具类库通过静态方法封装降低相关API的学习成本提高工作效率使Java拥有函数式语言般的优雅让Java语言也可以“甜甜的”。</description>
<url>https://github.com/looly/hutool</url> <url>https://github.com/looly/hutool</url>