mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
Prepare release
This commit is contained in:
commit
14921e4142
24
CHANGELOG.md
24
CHANGELOG.md
@ -3,13 +3,35 @@
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.5.5 (2020-12-27)
|
||||
|
||||
### 新特性
|
||||
* 【core 】 URLUtil.normalize新增重载(pr#233@Gitee)
|
||||
* 【core 】 PathUtil增加isSub和toAbsNormal方法
|
||||
* 【db 】 RedisDS实现序列化接口(pr#1323@Github)
|
||||
* 【poi 】 StyleUtil增加getFormat方法(pr#235@Gitee)
|
||||
* 【poi 】 增加ExcelDateUtil更多日期格式支持(issue#1316@Github)
|
||||
* 【core 】 NumberUtil.toBigDecimal支持各类数字格式,如1,234.56等(issue#1334@Github)
|
||||
* 【core 】 NumberUtil增加parseXXX方法(issue#1334@Github)
|
||||
* 【poi 】 Excel07SaxReader支持通过sheetName读取(issue#I2AOSE@Gitee)
|
||||
|
||||
### Bug修复
|
||||
* 【core 】 FileUtil.isSub相对路径判断问题(pr#1315@Github)
|
||||
* 【core 】 TreeUtil增加空判定(issue#I2ACCW@Gitee)
|
||||
* 【db 】 解决Hive获取表名失败问题(issue#I2AGLU@Gitee)
|
||||
* 【core 】 修复DateUtil.parse未使用严格模式导致结果不正常的问题(issue#1332@Github)
|
||||
* 【core 】 修复RuntimeUtil.getUsableMemory非static问题(issue#I2AQ2M@Gitee)
|
||||
* 【core 】 修复ArrayUtil.equals方法严格判断问题(issue#I2AO8B@Gitee)
|
||||
* 【poi 】 修复SheetRidReader在获取rid时读取错误问题(issue#I2AOQW@Gitee)
|
||||
* 【core 】 修复强依赖了POI的问题(issue#1336@Github)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
# 5.5.4 (2020-12-16)
|
||||
|
||||
### 新特性
|
||||
### Bug修复
|
||||
* 【core 】 修复IoUtil.readBytes的问题
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.5.3 (2020-12-11)
|
||||
|
@ -125,19 +125,19 @@ Each module can be introduced individually, or all modules can be introduced by
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Gradle
|
||||
```
|
||||
compile 'cn.hutool:hutool-all:5.5.4'
|
||||
compile 'cn.hutool:hutool-all:5.5.5'
|
||||
```
|
||||
|
||||
## Download
|
||||
|
||||
- [Maven1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.5.4/)
|
||||
- [Maven2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.5.4/)
|
||||
- [Maven1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.5.5/)
|
||||
- [Maven2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.5.5/)
|
||||
|
||||
> note:
|
||||
> Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available.
|
||||
|
@ -123,21 +123,21 @@ Hutool的存在就是为了减少代码搜索成本,避免网络上参差不
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Gradle
|
||||
```
|
||||
compile 'cn.hutool:hutool-all:5.5.4'
|
||||
compile 'cn.hutool:hutool-all:5.5.5'
|
||||
```
|
||||
|
||||
### 非Maven项目
|
||||
|
||||
点击以下任一链接,下载`hutool-all-X.X.X.jar`即可:
|
||||
|
||||
- [Maven中央库1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.5.4/)
|
||||
- [Maven中央库2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.5.4/)
|
||||
- [Maven中央库1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.5.5/)
|
||||
- [Maven中央库2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.5.5/)
|
||||
|
||||
> 注意
|
||||
> Hutool 5.x支持JDK8+,对Android平台没有测试,不能保证所有工具类或工具方法可用。
|
||||
|
@ -1 +1 @@
|
||||
5.5.4
|
||||
5.5.5
|
||||
|
@ -1 +1 @@
|
||||
var version = '5.5.4'
|
||||
var version = '5.5.5'
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-all</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-aop</artifactId>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-bloomFilter</artifactId>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-bom</artifactId>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-cache</artifactId>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-captcha</artifactId>
|
||||
|
@ -5,19 +5,11 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-core</artifactId>
|
||||
|
@ -1,10 +1,10 @@
|
||||
package cn.hutool.core.codec;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Base64编码
|
||||
*
|
||||
@ -128,11 +128,11 @@ public class Base64Encoder {
|
||||
|
||||
/**
|
||||
* 编码为Base64<br>
|
||||
* 如果isMultiLine为<code>true</code>,则每76个字符一个换行符,否则在一行显示
|
||||
* 如果isMultiLine为{@code true},则每76个字符一个换行符,否则在一行显示
|
||||
*
|
||||
* @param arr 被编码的数组
|
||||
* @param isMultiLine 在76个char之后是CRLF还是EOF
|
||||
* @param isUrlSafe 是否使用URL安全字符,一般为<code>false</code>
|
||||
* @param isUrlSafe 是否使用URL安全字符,一般为{@code false}
|
||||
* @return 编码后的bytes
|
||||
*/
|
||||
public static byte[] encode(byte[] arr, boolean isMultiLine, boolean isUrlSafe) {
|
||||
|
@ -21,16 +21,16 @@ import java.util.function.Function;
|
||||
* 数字转换器<br>
|
||||
* 支持类型为:<br>
|
||||
* <ul>
|
||||
* <li><code>java.lang.Byte</code></li>
|
||||
* <li><code>java.lang.Short</code></li>
|
||||
* <li><code>java.lang.Integer</code></li>
|
||||
* <li><code>java.util.concurrent.atomic.AtomicInteger</code></li>
|
||||
* <li><code>java.lang.Long</code></li>
|
||||
* <li><code>java.util.concurrent.atomic.AtomicLong</code></li>
|
||||
* <li><code>java.lang.Float</code></li>
|
||||
* <li><code>java.lang.Double</code></li>
|
||||
* <li><code>java.math.BigDecimal</code></li>
|
||||
* <li><code>java.math.BigInteger</code></li>
|
||||
* <li>{@code java.lang.Byte}</li>
|
||||
* <li>{@code java.lang.Short}</li>
|
||||
* <li>{@code java.lang.Integer}</li>
|
||||
* <li>{@code java.util.concurrent.atomic.AtomicInteger}</li>
|
||||
* <li>{@code java.lang.Long}</li>
|
||||
* <li>{@code java.util.concurrent.atomic.AtomicLong}</li>
|
||||
* <li>{@code java.lang.Float}</li>
|
||||
* <li>{@code java.lang.Double}</li>
|
||||
* <li>{@code java.math.BigDecimal}</li>
|
||||
* <li>{@code java.math.BigInteger}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Looly
|
||||
@ -80,7 +80,11 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
return BooleanUtil.toByteObj((Boolean) value);
|
||||
}
|
||||
final String valueStr = toStrFunc.apply(value);
|
||||
return StrUtil.isBlank(valueStr) ? null : Byte.valueOf(valueStr);
|
||||
try{
|
||||
return StrUtil.isBlank(valueStr) ? null : Byte.valueOf(valueStr);
|
||||
} catch (NumberFormatException e){
|
||||
return NumberUtil.parseNumber(valueStr).byteValue();
|
||||
}
|
||||
} else if (Short.class == targetType) {
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).shortValue();
|
||||
@ -88,7 +92,11 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
return BooleanUtil.toShortObj((Boolean) value);
|
||||
}
|
||||
final String valueStr = toStrFunc.apply((value));
|
||||
return StrUtil.isBlank(valueStr) ? null : Short.valueOf(valueStr);
|
||||
try{
|
||||
return StrUtil.isBlank(valueStr) ? null : Short.valueOf(valueStr);
|
||||
} catch (NumberFormatException e){
|
||||
return NumberUtil.parseNumber(valueStr).shortValue();
|
||||
}
|
||||
} else if (Integer.class == targetType) {
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).intValue();
|
||||
@ -146,8 +154,7 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
return BooleanUtil.toFloatObj((Boolean) value);
|
||||
}
|
||||
final String valueStr = toStrFunc.apply((value));
|
||||
return StrUtil.isBlank(valueStr) ? null : Float.valueOf(valueStr);
|
||||
|
||||
return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseFloat(valueStr);
|
||||
} else if (Double.class == targetType) {
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).doubleValue();
|
||||
@ -155,7 +162,7 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
return BooleanUtil.toDoubleObj((Boolean) value);
|
||||
}
|
||||
final String valueStr = toStrFunc.apply((value));
|
||||
return StrUtil.isBlank(valueStr) ? null : Double.valueOf(valueStr);
|
||||
return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseDouble(valueStr);
|
||||
} else if (DoubleAdder.class == targetType) {
|
||||
//jdk8 新增
|
||||
final Number number = convert(value, Long.class, toStrFunc);
|
||||
|
@ -219,7 +219,7 @@ public class DateTime extends Date {
|
||||
* @see DatePattern
|
||||
*/
|
||||
public DateTime(CharSequence dateStr, String format) {
|
||||
this(dateStr, new SimpleDateFormat(format));
|
||||
this(dateStr, DateUtil.newSimpleFormat(format));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -895,9 +895,7 @@ public class DateTime extends Date {
|
||||
*/
|
||||
public String toString(TimeZone timeZone) {
|
||||
if (null != timeZone) {
|
||||
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
|
||||
simpleDateFormat.setTimeZone(timeZone);
|
||||
return toString(simpleDateFormat);
|
||||
return toString(DateUtil.newSimpleFormat(DatePattern.NORM_DATETIME_PATTERN, null, timeZone));
|
||||
}
|
||||
return toString(DatePattern.NORM_DATETIME_FORMAT);
|
||||
}
|
||||
@ -910,9 +908,7 @@ public class DateTime extends Date {
|
||||
*/
|
||||
public String toDateStr() {
|
||||
if (null != this.timeZone) {
|
||||
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatePattern.NORM_DATE_PATTERN);
|
||||
simpleDateFormat.setTimeZone(this.timeZone);
|
||||
return toString(simpleDateFormat);
|
||||
return toString(DateUtil.newSimpleFormat(DatePattern.NORM_DATE_PATTERN, null, timeZone));
|
||||
}
|
||||
return toString(DatePattern.NORM_DATE_FORMAT);
|
||||
}
|
||||
@ -925,9 +921,7 @@ public class DateTime extends Date {
|
||||
*/
|
||||
public String toTimeStr() {
|
||||
if (null != this.timeZone) {
|
||||
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatePattern.NORM_TIME_PATTERN);
|
||||
simpleDateFormat.setTimeZone(this.timeZone);
|
||||
return toString(simpleDateFormat);
|
||||
return toString(DateUtil.newSimpleFormat(DatePattern.NORM_TIME_PATTERN, null, timeZone));
|
||||
}
|
||||
return toString(DatePattern.NORM_TIME_FORMAT);
|
||||
}
|
||||
@ -940,9 +934,7 @@ public class DateTime extends Date {
|
||||
*/
|
||||
public String toString(String format) {
|
||||
if (null != this.timeZone) {
|
||||
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
|
||||
simpleDateFormat.setTimeZone(this.timeZone);
|
||||
return toString(simpleDateFormat);
|
||||
return toString(DateUtil.newSimpleFormat(format, null, timeZone));
|
||||
}
|
||||
return toString(FastDateFormat.getInstance(format));
|
||||
}
|
||||
|
@ -14,14 +14,18 @@ import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.Year;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
@ -506,14 +510,11 @@ public class DateUtil extends CalendarUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
final SimpleDateFormat sdf = new SimpleDateFormat(format);
|
||||
TimeZone timeZone = null;
|
||||
if (date instanceof DateTime) {
|
||||
final TimeZone timeZone = ((DateTime) date).getTimeZone();
|
||||
if (null != timeZone) {
|
||||
sdf.setTimeZone(timeZone);
|
||||
}
|
||||
timeZone = ((DateTime) date).getTimeZone();
|
||||
}
|
||||
return format(date, sdf);
|
||||
return format(date, newSimpleFormat(format, null, timeZone));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -717,7 +718,7 @@ public class DateUtil extends CalendarUtil {
|
||||
* @since 4.5.18
|
||||
*/
|
||||
public static DateTime parse(CharSequence dateStr, String format, Locale locale) {
|
||||
return new DateTime(dateStr, new SimpleDateFormat(format, locale));
|
||||
return new DateTime(dateStr, DateUtil.newSimpleFormat(format, locale, null));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1917,7 +1918,7 @@ public class DateUtil extends CalendarUtil {
|
||||
/**
|
||||
* 获得指定月份的总天数
|
||||
*
|
||||
* @param month 年份
|
||||
* @param month 年份
|
||||
* @param isLeapYear 是否闰年
|
||||
* @return 天
|
||||
* @since 5.4.2
|
||||
@ -1926,6 +1927,40 @@ public class DateUtil extends CalendarUtil {
|
||||
return java.time.Month.of(month).length(isLeapYear);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建{@link SimpleDateFormat},注意此对象非线程安全!<br>
|
||||
* 此对象默认为严格格式模式,即parse时如果格式不正确会报错。
|
||||
*
|
||||
* @param pattern 表达式
|
||||
* @return {@link SimpleDateFormat}
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public static SimpleDateFormat newSimpleFormat(String pattern) {
|
||||
return newSimpleFormat(pattern, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建{@link SimpleDateFormat},注意此对象非线程安全!<br>
|
||||
* 此对象默认为严格格式模式,即parse时如果格式不正确会报错。
|
||||
*
|
||||
* @param pattern 表达式
|
||||
* @param locale {@link Locale},{@code null}表示默认
|
||||
* @param timeZone {@link TimeZone},{@code null}表示默认
|
||||
* @return {@link SimpleDateFormat}
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public static SimpleDateFormat newSimpleFormat(String pattern, Locale locale, TimeZone timeZone) {
|
||||
if (null == locale) {
|
||||
locale = Locale.getDefault(Locale.Category.FORMAT);
|
||||
}
|
||||
final SimpleDateFormat format = new SimpleDateFormat(pattern, locale);
|
||||
if (null != timeZone) {
|
||||
format.setTimeZone(timeZone);
|
||||
}
|
||||
format.setLenient(false);
|
||||
return format;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------ Private method start
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,8 @@
|
||||
package cn.hutool.core.date.format;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.lang.Tuple;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.Format;
|
||||
import java.text.SimpleDateFormat;
|
||||
@ -8,9 +11,6 @@ import java.util.TimeZone;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.lang.Tuple;
|
||||
|
||||
/**
|
||||
* 日期格式化器缓存<br>
|
||||
* Thanks to Apache Commons Lang 3.5
|
||||
@ -43,7 +43,7 @@ abstract class FormatCache<F extends Format> {
|
||||
* @param timeZone 时区,默认当前时区
|
||||
* @param locale 地区,默认使用当前地区
|
||||
* @return 格式化器
|
||||
* @throws IllegalArgumentException pattern 无效或<code>null</code>
|
||||
* @throws IllegalArgumentException pattern 无效或{@code null}
|
||||
*/
|
||||
public F getInstance(final String pattern, TimeZone timeZone, Locale locale) {
|
||||
Assert.notBlank(pattern, "pattern must not be blank") ;
|
||||
@ -74,7 +74,7 @@ abstract class FormatCache<F extends Format> {
|
||||
* @param timeZone 时区,默认当前时区
|
||||
* @param locale 地区,默认使用当前地区
|
||||
* @return 格式化器
|
||||
* @throws IllegalArgumentException pattern 无效或<code>null</code>
|
||||
* @throws IllegalArgumentException pattern 无效或{@code null}
|
||||
*/
|
||||
abstract protected F createInstance(String pattern, TimeZone timeZone, Locale locale);
|
||||
|
||||
|
@ -3194,7 +3194,7 @@ public class FileUtil extends PathUtil {
|
||||
public static boolean isSub(File parent, File sub) {
|
||||
Assert.notNull(parent);
|
||||
Assert.notNull(sub);
|
||||
return sub.toPath().startsWith(parent.toPath());
|
||||
return isSub(parent.toPath(), sub.toPath());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -515,4 +515,43 @@ public class PathUtil {
|
||||
final LinkOption[] options = isFollowLinks ? new LinkOption[0] : new LinkOption[]{LinkOption.NOFOLLOW_LINKS};
|
||||
return Files.exists(path, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定的目录是否为给定文件或文件夹的子目录
|
||||
*
|
||||
* @param parent 父目录
|
||||
* @param sub 子目录
|
||||
* @return 子目录是否为父目录的子目录
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public static boolean isSub(Path parent, Path sub) {
|
||||
return toAbsNormal(sub).startsWith(toAbsNormal(parent));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Path路径转换为标准的绝对路径
|
||||
*
|
||||
* @param path 文件或目录Path
|
||||
* @return 转换后的Path
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public static Path toAbsNormal(Path path){
|
||||
Assert.notNull(path);
|
||||
return path.toAbsolutePath().normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得文件的MimeType
|
||||
*
|
||||
* @param file 文件
|
||||
* @return MimeType
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public static String getMimeType(Path file) {
|
||||
try {
|
||||
return Files.probeContentType(file);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ public class TreeUtil {
|
||||
|
||||
List<Tree<E>> finalTreeList = CollUtil.newArrayList();
|
||||
for (Tree<E> node : treeList) {
|
||||
if (parentId.equals(node.getParentId())) {
|
||||
if (ObjectUtil.equals(parentId,node.getParentId())) {
|
||||
finalTreeList.add(node);
|
||||
innerBuild(treeList, node, 0, treeNodeConfig.getDeep());
|
||||
}
|
||||
|
@ -523,7 +523,7 @@ public class ArrayUtil extends PrimitiveArrayUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 克隆数组,如果非数组返回<code>null</code>
|
||||
* 克隆数组,如果非数组返回{@code null}
|
||||
*
|
||||
* @param <T> 数组元素类型
|
||||
* @param obj 数组对象
|
||||
@ -1667,11 +1667,6 @@ public class ArrayUtil extends PrimitiveArrayUtil {
|
||||
Assert.isTrue(isArray(array1), "First is not a Array !");
|
||||
Assert.isTrue(isArray(array2), "Second is not a Array !");
|
||||
|
||||
// 数组类型一致性判断
|
||||
if (array1.getClass() != array2.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (array1 instanceof long[]) {
|
||||
return Arrays.equals((long[]) array1, (long[]) array2);
|
||||
} else if (array1 instanceof int[]) {
|
||||
|
@ -2044,6 +2044,11 @@ public class NumberUtil {
|
||||
* @since 4.0.9
|
||||
*/
|
||||
public static BigDecimal toBigDecimal(String number) {
|
||||
try{
|
||||
number = parseNumber(number).toString();
|
||||
} catch (Exception ignore){
|
||||
// 忽略解析错误
|
||||
}
|
||||
return StrUtil.isBlank(number) ? BigDecimal.ZERO : new BigDecimal(number);
|
||||
}
|
||||
|
||||
@ -2287,7 +2292,7 @@ public class NumberUtil {
|
||||
*
|
||||
* <pre>
|
||||
* 1、0x开头的视为16进制数字
|
||||
* 2、0开头的视为8进制数字
|
||||
* 2、0开头的忽略开头的0
|
||||
* 3、其它情况按照10进制转换
|
||||
* 4、空串返回0
|
||||
* 5、.123形式返回0(按照小于0的小数对待)
|
||||
@ -2304,18 +2309,16 @@ public class NumberUtil {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 对于带小数转换为整数采取去掉小数的策略
|
||||
number = StrUtil.subBefore(number, CharUtil.DOT, false);
|
||||
if (StrUtil.isEmpty(number)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (StrUtil.startWithIgnoreCase(number, "0x")) {
|
||||
// 0x04表示16进制数
|
||||
return Integer.parseInt(number.substring(2), 16);
|
||||
}
|
||||
|
||||
return Integer.parseInt(removeNumberFlag(number));
|
||||
try{
|
||||
return Integer.parseInt(number);
|
||||
} catch (NumberFormatException e){
|
||||
return parseNumber(number).intValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2323,9 +2326,11 @@ public class NumberUtil {
|
||||
*
|
||||
* <pre>
|
||||
* 1、0x开头的视为16进制数字
|
||||
* 2、0开头的视为8进制数字
|
||||
* 2、0开头的忽略开头的0
|
||||
* 3、空串返回0
|
||||
* 4、其它情况按照10进制转换
|
||||
* 5、.123形式返回0(按照小于0的小数对待)
|
||||
* 6、123.56截取小数点之前的数字,忽略小数部分
|
||||
* </pre>
|
||||
*
|
||||
* @param number 数字,支持0x开头、0开头和普通十进制
|
||||
@ -2334,13 +2339,7 @@ public class NumberUtil {
|
||||
*/
|
||||
public static long parseLong(String number) {
|
||||
if (StrUtil.isBlank(number)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 对于带小数转换为整数采取去掉小数的策略
|
||||
number = StrUtil.subBefore(number, CharUtil.DOT, false);
|
||||
if (StrUtil.isEmpty(number)) {
|
||||
return 0;
|
||||
return 0L;
|
||||
}
|
||||
|
||||
if (number.startsWith("0x")) {
|
||||
@ -2348,7 +2347,63 @@ public class NumberUtil {
|
||||
return Long.parseLong(number.substring(2), 16);
|
||||
}
|
||||
|
||||
return Long.parseLong(removeNumberFlag(number));
|
||||
try{
|
||||
return Long.parseLong(number);
|
||||
} catch (NumberFormatException e){
|
||||
return parseNumber(number).longValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析转换数字字符串为long型数字,规则如下:
|
||||
*
|
||||
* <pre>
|
||||
* 1、0开头的忽略开头的0
|
||||
* 2、空串返回0
|
||||
* 3、其它情况按照10进制转换
|
||||
* 4、.123形式返回0.123(按照小于0的小数对待)
|
||||
* </pre>
|
||||
*
|
||||
* @param number 数字,支持0x开头、0开头和普通十进制
|
||||
* @return long
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public static float parseFloat(String number) {
|
||||
if (StrUtil.isBlank(number)) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
try{
|
||||
return Float.parseFloat(number);
|
||||
} catch (NumberFormatException e){
|
||||
return parseNumber(number).floatValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析转换数字字符串为long型数字,规则如下:
|
||||
*
|
||||
* <pre>
|
||||
* 1、0开头的忽略开头的0
|
||||
* 2、空串返回0
|
||||
* 3、其它情况按照10进制转换
|
||||
* 4、.123形式返回0.123(按照小于0的小数对待)
|
||||
* </pre>
|
||||
*
|
||||
* @param number 数字,支持0x开头、0开头和普通十进制
|
||||
* @return long
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public static double parseDouble(String number) {
|
||||
if (StrUtil.isBlank(number)) {
|
||||
return 0D;
|
||||
}
|
||||
|
||||
try{
|
||||
return Double.parseDouble(number);
|
||||
} catch (NumberFormatException e){
|
||||
return parseNumber(number).doubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2357,13 +2412,15 @@ public class NumberUtil {
|
||||
* @param numberStr Number字符串
|
||||
* @return Number对象
|
||||
* @since 4.1.15
|
||||
* @throws NumberFormatException 包装了{@link ParseException},当给定的数字字符串无法解析时抛出
|
||||
*/
|
||||
public static Number parseNumber(String numberStr) {
|
||||
numberStr = removeNumberFlag(numberStr);
|
||||
public static Number parseNumber(String numberStr) throws NumberFormatException{
|
||||
try {
|
||||
return NumberFormat.getInstance().parse(numberStr);
|
||||
} catch (ParseException e) {
|
||||
throw new UtilException(e);
|
||||
final NumberFormatException nfe = new NumberFormatException(e.getMessage());
|
||||
nfe.initCause(e);
|
||||
throw nfe;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2509,25 +2566,5 @@ public class NumberUtil {
|
||||
return selectNum * mathNode(selectNum - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 去掉数字尾部的数字标识,例如12D,44.0F,22L中的最后一个字母
|
||||
*
|
||||
* @param number 数字字符串
|
||||
* @return 去掉标识的字符串
|
||||
*/
|
||||
private static String removeNumberFlag(String number) {
|
||||
// 去掉千位分隔符
|
||||
if (StrUtil.contains(number, CharUtil.COMMA)) {
|
||||
number = StrUtil.removeAll(number, CharUtil.COMMA);
|
||||
}
|
||||
// 去掉类型标识的结尾
|
||||
final int lastPos = number.length() - 1;
|
||||
final char lastCharUpper = Character.toUpperCase(number.charAt(lastPos));
|
||||
if ('D' == lastCharUpper || 'L' == lastCharUpper || 'F' == lastCharUpper) {
|
||||
number = StrUtil.subPre(number, lastPos);
|
||||
}
|
||||
return number;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------- Private method end
|
||||
}
|
||||
|
@ -298,7 +298,7 @@ public class RuntimeUtil {
|
||||
*
|
||||
* @return 最大可用内存
|
||||
*/
|
||||
public final long getUsableMemory() {
|
||||
public static long getUsableMemory() {
|
||||
return getMaxMemory() - getTotalMemory() + getFreeMemory();
|
||||
}
|
||||
}
|
||||
|
@ -14,14 +14,7 @@ import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarFile;
|
||||
@ -669,9 +662,11 @@ public class URLUtil {
|
||||
/**
|
||||
* 标准化URL字符串,包括:
|
||||
*
|
||||
* <pre>
|
||||
* 1. 多个/替换为一个
|
||||
* </pre>
|
||||
* <ol>
|
||||
* <li>自动补齐“http://”头</li>
|
||||
* <li>去除开头的\或者/</li>
|
||||
* <li>替换\为/</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param url URL字符串
|
||||
* @return 标准化后的URL字符串
|
||||
@ -683,9 +678,11 @@ public class URLUtil {
|
||||
/**
|
||||
* 标准化URL字符串,包括:
|
||||
*
|
||||
* <pre>
|
||||
* 1. 多个/替换为一个
|
||||
* </pre>
|
||||
* <ol>
|
||||
* <li>自动补齐“http://”头</li>
|
||||
* <li>去除开头的\或者/</li>
|
||||
* <li>替换\为/</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param url URL字符串
|
||||
* @param isEncodePath 是否对URL中path部分的中文和特殊字符做转义(不包括 http:, /和域名部分)
|
||||
@ -693,6 +690,26 @@ public class URLUtil {
|
||||
* @since 4.4.1
|
||||
*/
|
||||
public static String normalize(String url, boolean isEncodePath) {
|
||||
return normalize(url, isEncodePath, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标准化URL字符串,包括:
|
||||
*
|
||||
* <ol>
|
||||
* <li>自动补齐“http://”头</li>
|
||||
* <li>去除开头的\或者/</li>
|
||||
* <li>替换\为/</li>
|
||||
* <li>如果replaceSlash为true,则替换多个/为一个</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param url URL字符串
|
||||
* @param isEncodePath 是否对URL中path部分的中文和特殊字符做转义(不包括 http:, /和域名部分)
|
||||
* @param replaceSlash 是否替换url body中的 //
|
||||
* @return 标准化后的URL字符串
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public static String normalize(String url, boolean isEncodePath, boolean replaceSlash) {
|
||||
if (StrUtil.isBlank(url)) {
|
||||
return url;
|
||||
}
|
||||
@ -718,10 +735,12 @@ public class URLUtil {
|
||||
// 去除开头的\或者/
|
||||
//noinspection ConstantConditions
|
||||
body = body.replaceAll("^[\\\\/]+", StrUtil.EMPTY);
|
||||
// 替换多个\或/为单个/
|
||||
// 替换\为/
|
||||
body = body.replace("\\", "/");
|
||||
//issue#I25MZL,双斜杠在URL中是允许存在的,不做替换
|
||||
//.replaceAll("//+", "/");
|
||||
if (replaceSlash) {
|
||||
//issue#I25MZL@Gitee,双斜杠在URL中是允许存在的,默认不做替换
|
||||
body = body.replaceAll("//+", "/");
|
||||
}
|
||||
}
|
||||
|
||||
final int pathSepIndex = StrUtil.indexOf(body, '/');
|
||||
|
@ -0,0 +1,22 @@
|
||||
package cn.hutool.core.convert;
|
||||
|
||||
import cn.hutool.core.convert.impl.NumberConverter;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class NumberConverterTest {
|
||||
|
||||
@Test
|
||||
public void toDoubleTest(){
|
||||
final NumberConverter numberConverter = new NumberConverter(Double.class);
|
||||
final Number convert = numberConverter.convert("1,234.55", null);
|
||||
Assert.assertEquals(1234.55D, convert);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toIntegerTest(){
|
||||
final NumberConverter numberConverter = new NumberConverter(Integer.class);
|
||||
final Number convert = numberConverter.convert("1,234.55", null);
|
||||
Assert.assertEquals(1234, convert);
|
||||
}
|
||||
}
|
@ -831,4 +831,11 @@ public class DateUtilTest {
|
||||
final DateTime parse = DateUtil.parse(dt);
|
||||
Assert.assertEquals("2020-06-03 12:32:12", parse.toString());
|
||||
}
|
||||
|
||||
@Test(expected = DateException.class)
|
||||
public void parseNotFitTest(){
|
||||
//https://github.com/looly/hutool/issues/1332
|
||||
// 在日期格式不匹配的时候,测试是否正常报错
|
||||
final DateTime parse = DateUtil.parse("2020-12-23", DatePattern.PURE_DATE_PATTERN);
|
||||
}
|
||||
}
|
||||
|
@ -384,4 +384,11 @@ public class FileUtilTest {
|
||||
File file2 = new File("d:/test2/aaa");
|
||||
Assert.assertFalse(FileUtil.isSub(file, file2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSubRelativeTest() {
|
||||
File file = new File("..");
|
||||
File file2 = new File(".");
|
||||
Assert.assertTrue(FileUtil.isSub(file, file2));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.hutool.core.io.file;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -33,4 +34,10 @@ public class PathUtilTest {
|
||||
public void moveTest(){
|
||||
PathUtil.move(Paths.get("d:/lombok.jar"), Paths.get("d:/test/"), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMimeTypeTest(){
|
||||
final String mimeType = PathUtil.getMimeType(Paths.get("d:/test/test.jpg"));
|
||||
Assert.assertEquals("image/jpeg", mimeType);
|
||||
}
|
||||
}
|
||||
|
@ -189,6 +189,12 @@ public class NumberUtilTest {
|
||||
|
||||
BigDecimal bigDecimal = NumberUtil.toBigDecimal(a);
|
||||
Assert.assertEquals("3.14", bigDecimal.toString());
|
||||
|
||||
bigDecimal = NumberUtil.toBigDecimal("1,234.55");
|
||||
Assert.assertEquals("1234.55", bigDecimal.toString());
|
||||
|
||||
bigDecimal = NumberUtil.toBigDecimal("1,234.56D");
|
||||
Assert.assertEquals("1234.56", bigDecimal.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -205,21 +211,33 @@ public class NumberUtilTest {
|
||||
|
||||
@Test
|
||||
public void parseIntTest() {
|
||||
int v1 = NumberUtil.parseInt("0xFF");
|
||||
Assert.assertEquals(255, v1);
|
||||
int v2 = NumberUtil.parseInt("010");
|
||||
Assert.assertEquals(10, v2);
|
||||
int v3 = NumberUtil.parseInt("10");
|
||||
Assert.assertEquals(10, v3);
|
||||
int v4 = NumberUtil.parseInt(" ");
|
||||
Assert.assertEquals(0, v4);
|
||||
int v5 = NumberUtil.parseInt("10F");
|
||||
Assert.assertEquals(10, v5);
|
||||
int v6 = NumberUtil.parseInt("22.4D");
|
||||
Assert.assertEquals(22, v6);
|
||||
int number = NumberUtil.parseInt("0xFF");
|
||||
Assert.assertEquals(255, number);
|
||||
|
||||
int v7 = NumberUtil.parseInt("0");
|
||||
Assert.assertEquals(0, v7);
|
||||
// 0开头
|
||||
number = NumberUtil.parseInt("010");
|
||||
Assert.assertEquals(10, number);
|
||||
|
||||
number = NumberUtil.parseInt("10");
|
||||
Assert.assertEquals(10, number);
|
||||
|
||||
number = NumberUtil.parseInt(" ");
|
||||
Assert.assertEquals(0, number);
|
||||
|
||||
number = NumberUtil.parseInt("10F");
|
||||
Assert.assertEquals(10, number);
|
||||
|
||||
number = NumberUtil.parseInt("22.4D");
|
||||
Assert.assertEquals(22, number);
|
||||
|
||||
number = NumberUtil.parseInt("22.6D");
|
||||
Assert.assertEquals(22, number);
|
||||
|
||||
number = NumberUtil.parseInt("0");
|
||||
Assert.assertEquals(0, number);
|
||||
|
||||
number = NumberUtil.parseInt(".123");
|
||||
Assert.assertEquals(0, number);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -236,22 +254,40 @@ public class NumberUtilTest {
|
||||
// 千位分隔符去掉
|
||||
int v1 = NumberUtil.parseNumber("1,482.00").intValue();
|
||||
Assert.assertEquals(1482, v1);
|
||||
|
||||
Number v2 = NumberUtil.parseNumber("1,482.00D");
|
||||
Assert.assertEquals(1482L, v2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseLongTest() {
|
||||
long v1 = NumberUtil.parseLong("0xFF");
|
||||
Assert.assertEquals(255L, v1);
|
||||
long v2 = NumberUtil.parseLong("010");
|
||||
Assert.assertEquals(10L, v2);
|
||||
long v3 = NumberUtil.parseLong("10");
|
||||
Assert.assertEquals(10L, v3);
|
||||
long v4 = NumberUtil.parseLong(" ");
|
||||
Assert.assertEquals(0L, v4);
|
||||
long v5 = NumberUtil.parseLong("10F");
|
||||
Assert.assertEquals(10L, v5);
|
||||
long v6 = NumberUtil.parseLong("22.4D");
|
||||
Assert.assertEquals(22L, v6);
|
||||
long number = NumberUtil.parseLong("0xFF");
|
||||
Assert.assertEquals(255, number);
|
||||
|
||||
// 0开头
|
||||
number = NumberUtil.parseLong("010");
|
||||
Assert.assertEquals(10, number);
|
||||
|
||||
number = NumberUtil.parseLong("10");
|
||||
Assert.assertEquals(10, number);
|
||||
|
||||
number = NumberUtil.parseLong(" ");
|
||||
Assert.assertEquals(0, number);
|
||||
|
||||
number = NumberUtil.parseLong("10F");
|
||||
Assert.assertEquals(10, number);
|
||||
|
||||
number = NumberUtil.parseLong("22.4D");
|
||||
Assert.assertEquals(22, number);
|
||||
|
||||
number = NumberUtil.parseLong("22.6D");
|
||||
Assert.assertEquals(22, number);
|
||||
|
||||
number = NumberUtil.parseLong("0");
|
||||
Assert.assertEquals(0, number);
|
||||
|
||||
number = NumberUtil.parseLong(".123");
|
||||
Assert.assertEquals(0, number);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,11 +1,10 @@
|
||||
package cn.hutool.core.util;
|
||||
|
||||
import cn.hutool.core.lang.Console;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import cn.hutool.core.lang.Console;
|
||||
import cn.hutool.core.util.RuntimeUtil;
|
||||
|
||||
/**
|
||||
* 命令行单元测试
|
||||
* @author looly
|
||||
@ -26,4 +25,9 @@ public class RuntimeUtilTest {
|
||||
String str = RuntimeUtil.execForStr("cmd /c dir");
|
||||
Console.log(str);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUsableMemoryTest(){
|
||||
Assert.assertTrue(RuntimeUtil.getUsableMemory() > 0);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-cron</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-db</artifactId>
|
||||
@ -21,12 +21,12 @@
|
||||
<c3p0.version>0.9.5.5</c3p0.version>
|
||||
<dbcp2.version>2.8.0</dbcp2.version>
|
||||
<tomcat-jdbc.version>9.0.30</tomcat-jdbc.version>
|
||||
<druid.version>1.2.3</druid.version>
|
||||
<druid.version>1.2.4</druid.version>
|
||||
<hikariCP.version>2.4.13</hikariCP.version>
|
||||
<mongo.version>3.12.7</mongo.version>
|
||||
<sqlite.version>3.32.3.2</sqlite.version>
|
||||
<sqlite.version>3.34.0</sqlite.version>
|
||||
<hsqldb.version>2.5.1</hsqldb.version>
|
||||
<jedis.version>3.3.0</jedis.version>
|
||||
<jedis.version>3.4.1</jedis.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -154,7 +154,12 @@ public class HandleHelper {
|
||||
row.put(meta.getColumnLabel(i), getColumnValue(rs, i, type, null));
|
||||
}
|
||||
if (withMetaInfo) {
|
||||
row.setTableName(meta.getTableName(1));
|
||||
try {
|
||||
row.setTableName(meta.getTableName(1));
|
||||
} catch (SQLException ignore){
|
||||
//issue#I2AGLU@Gitee
|
||||
// Hive等NoSQL中无表的概念,此处报错,跳过。
|
||||
}
|
||||
row.setFieldNames(row.keySet());
|
||||
}
|
||||
return row;
|
||||
|
@ -9,6 +9,7 @@ import redis.clients.jedis.JedisPoolConfig;
|
||||
import redis.clients.jedis.Protocol;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Jedis数据源
|
||||
@ -16,7 +17,8 @@ import java.io.Closeable;
|
||||
* @author looly
|
||||
* @since 3.2.3
|
||||
*/
|
||||
public class RedisDS implements Closeable{
|
||||
public class RedisDS implements Closeable, Serializable {
|
||||
private static final long serialVersionUID = -5605411972456177456L;
|
||||
/** 默认配置文件 */
|
||||
public final static String REDIS_CONFIG_PATH = "config/redis.setting";
|
||||
|
||||
@ -29,7 +31,7 @@ public class RedisDS implements Closeable{
|
||||
/**
|
||||
* 创建RedisDS,使用默认配置文件,默认分组
|
||||
*
|
||||
* @return {@link RedisDS}
|
||||
* @return RedisDS
|
||||
*/
|
||||
public static RedisDS create() {
|
||||
return new RedisDS();
|
||||
@ -39,7 +41,7 @@ public class RedisDS implements Closeable{
|
||||
* 创建RedisDS,使用默认配置文件
|
||||
*
|
||||
* @param group 配置文件中配置分组
|
||||
* @return {@link RedisDS}
|
||||
* @return RedisDS
|
||||
*/
|
||||
public static RedisDS create(String group) {
|
||||
return new RedisDS(group);
|
||||
@ -50,7 +52,7 @@ public class RedisDS implements Closeable{
|
||||
*
|
||||
* @param setting 配置文件
|
||||
* @param group 配置文件中配置分组
|
||||
* @return {@link RedisDS}
|
||||
* @return RedisDS
|
||||
*/
|
||||
public static RedisDS create(Setting setting, String group) {
|
||||
return new RedisDS(setting, group);
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-dfa</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-extra</artifactId>
|
||||
@ -19,18 +19,18 @@
|
||||
<properties>
|
||||
<!-- versions -->
|
||||
<velocity.version>2.2</velocity.version>
|
||||
<beetl.version>3.2.4.RELEASE</beetl.version>
|
||||
<beetl.version>3.3.1.RELEASE</beetl.version>
|
||||
<rythm.version>1.3.0</rythm.version>
|
||||
<freemarker.version>2.3.30</freemarker.version>
|
||||
<enjoy.version>4.9.03</enjoy.version>
|
||||
<thymeleaf.version>3.0.11.RELEASE</thymeleaf.version>
|
||||
<thymeleaf.version>3.0.12.RELEASE</thymeleaf.version>
|
||||
<mail.version>1.6.2</mail.version>
|
||||
<jsch.version>0.1.55</jsch.version>
|
||||
<zxing.version>3.4.1</zxing.version>
|
||||
<net.version>3.7.2</net.version>
|
||||
<emoji-java.version>5.1.1</emoji-java.version>
|
||||
<servlet-api.version>4.0.1</servlet-api.version>
|
||||
<spring-boot.version>2.4.0</spring-boot.version>
|
||||
<spring-boot.version>2.4.1</spring-boot.version>
|
||||
<cglib.version>3.3.0</cglib.version>
|
||||
</properties>
|
||||
|
||||
@ -406,7 +406,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mvel</groupId>
|
||||
<artifactId>mvel2</artifactId>
|
||||
<version>2.4.10.Final</version>
|
||||
<version>2.4.11.Final</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
@ -420,7 +420,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-expression</artifactId>
|
||||
<version>5.3.1</version>
|
||||
<version>5.3.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
@ -81,7 +81,7 @@ public class Mail {
|
||||
* 创建邮件客户端
|
||||
*
|
||||
* @param mailAccount 邮件帐号
|
||||
* @return {@link Mail}
|
||||
* @return Mail
|
||||
*/
|
||||
public static Mail create(MailAccount mailAccount) {
|
||||
return new Mail(mailAccount);
|
||||
@ -90,7 +90,7 @@ public class Mail {
|
||||
/**
|
||||
* 创建邮件客户端,使用全局邮件帐户
|
||||
*
|
||||
* @return {@link Mail}
|
||||
* @return Mail
|
||||
*/
|
||||
public static Mail create() {
|
||||
return new Mail();
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-http</artifactId>
|
||||
|
@ -9,8 +9,6 @@ import cn.hutool.json.JSONUtil;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.Authenticator;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -142,26 +140,4 @@ public class HttpRequestTest {
|
||||
HttpResponse execute = get.execute();
|
||||
Console.log(execute.body());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getByProxy(){
|
||||
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
|
||||
|
||||
// 用户名密码, 若已添加白名单则不需要添加
|
||||
final String ProxyUser = "t10757311156848";
|
||||
final String ProxyPass = "ikm5uu44";
|
||||
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
public PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(ProxyUser, ProxyPass.toCharArray());
|
||||
}
|
||||
});
|
||||
|
||||
final HttpResponse res = HttpRequest.get("https://httpbin.org/get")
|
||||
.basicAuth(ProxyUser, ProxyPass)
|
||||
.setHttpProxy("tps193.kdlapi.com", 15818).execute();
|
||||
|
||||
Console.log(res.body());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-json</artifactId>
|
||||
|
@ -170,5 +170,4 @@ public class JSONUtilTest {
|
||||
" \"test\": \"\\\\地库地库\",\n" +
|
||||
"}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-log</artifactId>
|
||||
@ -92,7 +92,7 @@
|
||||
<dependency>
|
||||
<groupId>org.tinylog</groupId>
|
||||
<artifactId>tinylog-impl</artifactId>
|
||||
<version>2.1.2</version>
|
||||
<version>2.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-poi</artifactId>
|
||||
|
@ -0,0 +1,70 @@
|
||||
package cn.hutool.poi.excel;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.apache.poi.ss.formula.ConditionalFormattingEvaluator;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.ExcelNumberFormat;
|
||||
|
||||
/**
|
||||
* Excel中日期判断、读取、处理等补充工具类
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public class ExcelDateUtil {
|
||||
|
||||
/**
|
||||
* 某些特殊的自定义日期格式
|
||||
*/
|
||||
private static final int[] customFormats = new int[]{28, 30, 31, 32, 33, 55, 56, 57, 58};
|
||||
|
||||
public static boolean isDateFormat(Cell cell){
|
||||
return isDateFormat(cell, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否日期格式
|
||||
* @param cell 单元格
|
||||
* @param cfEvaluator {@link ConditionalFormattingEvaluator}
|
||||
* @return 是否日期格式
|
||||
*/
|
||||
public static boolean isDateFormat(Cell cell, ConditionalFormattingEvaluator cfEvaluator){
|
||||
final ExcelNumberFormat nf = ExcelNumberFormat.from(cell, cfEvaluator);
|
||||
return isDateFormat(nf);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否日期格式
|
||||
* @param numFmt {@link ExcelNumberFormat}
|
||||
* @return 是否日期格式
|
||||
*/
|
||||
public static boolean isDateFormat(ExcelNumberFormat numFmt) {
|
||||
return isDateFormat(numFmt.getIdx(), numFmt.getFormat());
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断日期格式
|
||||
*
|
||||
* @param formatIndex 格式索引,一般用于内建格式
|
||||
* @param formatString 格式字符串
|
||||
* @return 是否为日期格式
|
||||
* @since 5.5.3
|
||||
*/
|
||||
public static boolean isDateFormat(int formatIndex, String formatString) {
|
||||
// issue#1283@Github
|
||||
if (ArrayUtil.contains(customFormats, formatIndex)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 自定义格式判断
|
||||
if (StrUtil.isNotEmpty(formatString) &&
|
||||
StrUtil.containsAny(formatString, "周", "星期", "aa")) {
|
||||
// aa -> 周一
|
||||
// aaa -> 星期一
|
||||
return true;
|
||||
}
|
||||
|
||||
return org.apache.poi.ss.usermodel.DateUtil.isADateFormat(formatIndex, formatString);
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package cn.hutool.poi.excel.cell;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.poi.excel.ExcelDateUtil;
|
||||
import cn.hutool.poi.excel.ExcelUtil;
|
||||
import cn.hutool.poi.excel.StyleSet;
|
||||
import cn.hutool.poi.excel.editors.TrimEditor;
|
||||
@ -102,7 +103,7 @@ public class CellUtil {
|
||||
if (null == cell) {
|
||||
return null;
|
||||
}
|
||||
if(cell instanceof NullCell){
|
||||
if (cell instanceof NullCell) {
|
||||
return null == cellEditor ? null : cellEditor.edit(cell, null);
|
||||
}
|
||||
if (null == cellType) {
|
||||
@ -111,7 +112,7 @@ public class CellUtil {
|
||||
|
||||
// 尝试获取合并单元格,如果是合并单元格,则重新获取单元格类型
|
||||
final Cell mergedCell = getMergedRegionCell(cell);
|
||||
if(mergedCell != cell){
|
||||
if (mergedCell != cell) {
|
||||
cell = mergedCell;
|
||||
cellType = cell.getCellTypeEnum();
|
||||
}
|
||||
@ -235,7 +236,7 @@ public class CellUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
*获取单元格,如果单元格不存在,返回{@link NullCell}
|
||||
* 获取单元格,如果单元格不存在,返回{@link NullCell}
|
||||
*
|
||||
* @param row Excel表的行
|
||||
* @param cellIndex 列号
|
||||
@ -377,7 +378,7 @@ public class CellUtil {
|
||||
* @since 5.1.5
|
||||
*/
|
||||
public static Cell getMergedRegionCell(Cell cell) {
|
||||
if(null == cell){
|
||||
if (null == cell) {
|
||||
return null;
|
||||
}
|
||||
return ObjectUtil.defaultIfNull(
|
||||
@ -404,10 +405,10 @@ public class CellUtil {
|
||||
/**
|
||||
* 为特定单元格添加批注
|
||||
*
|
||||
* @param cell 单元格
|
||||
* @param commentText 批注内容
|
||||
* @param cell 单元格
|
||||
* @param commentText 批注内容
|
||||
* @param commentAuthor 作者
|
||||
* @param anchor 批注的位置、大小等信息,null表示使用默认
|
||||
* @param anchor 批注的位置、大小等信息,null表示使用默认
|
||||
* @since 5.4.8
|
||||
*/
|
||||
public static void setComment(Cell cell, String commentText, String commentAuthor, ClientAnchor anchor) {
|
||||
@ -431,16 +432,16 @@ public class CellUtil {
|
||||
// -------------------------------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
* 获取合并单元格,非合并单元格返回<code>null</code><br>
|
||||
* 获取合并单元格,非合并单元格返回{@code null}<br>
|
||||
* 传入的x,y坐标(列行数)可以是合并单元格范围内的任意一个单元格
|
||||
*
|
||||
* @param sheet {@link Sheet}
|
||||
* @param x 列号,从0开始,可以是合并单元格范围中的任意一列
|
||||
* @param y 行号,从0开始,可以是合并单元格范围中的任意一行
|
||||
* @return 合并单元格,如果非合并单元格,返回<code>null</code>
|
||||
* @return 合并单元格,如果非合并单元格,返回{@code null}
|
||||
* @since 5.4.5
|
||||
*/
|
||||
private static Cell getCellIfMergedRegion(Sheet sheet, int x, int y){
|
||||
private static Cell getCellIfMergedRegion(Sheet sheet, int x, int y) {
|
||||
final int sheetMergeCount = sheet.getNumMergedRegions();
|
||||
CellRangeAddress ca;
|
||||
for (int i = 0; i < sheetMergeCount; i++) {
|
||||
@ -463,9 +464,8 @@ public class CellUtil {
|
||||
|
||||
final CellStyle style = cell.getCellStyle();
|
||||
if (null != style) {
|
||||
final short formatIndex = style.getDataFormat();
|
||||
// 判断是否为日期
|
||||
if (isDateType(cell, formatIndex)) {
|
||||
if (ExcelDateUtil.isDateFormat(cell)) {
|
||||
return DateUtil.date(cell.getDateCellValue());// 使用Hutool的DateTime包装
|
||||
}
|
||||
|
||||
@ -483,32 +483,5 @@ public class CellUtil {
|
||||
// 某些Excel单元格值为double计算结果,可能导致精度问题,通过转换解决精度问题。
|
||||
return Double.parseDouble(NumberToTextConverter.toText(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为日期格式<br>
|
||||
* 判断方式:
|
||||
*
|
||||
* <pre>
|
||||
* 1、指定序号
|
||||
* 2、org.apache.poi.ss.usermodel.DateUtil.isADateFormat方法判定
|
||||
* </pre>
|
||||
*
|
||||
* @param cell 单元格
|
||||
* @param formatIndex 格式序号
|
||||
* @return 是否为日期格式
|
||||
*/
|
||||
private static boolean isDateType(Cell cell, int formatIndex) {
|
||||
// yyyy-MM-dd----- 14
|
||||
// yyyy年m月d日---- 31
|
||||
// yyyy年m月------- 57
|
||||
// m月d日 ---------- 58
|
||||
// HH:mm----------- 20
|
||||
// h时mm分 -------- 32
|
||||
if (formatIndex == 14 || formatIndex == 31 || formatIndex == 57 || formatIndex == 58 || formatIndex == 20 || formatIndex == 32) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell);
|
||||
}
|
||||
// -------------------------------------------------------------------------------------------------------------- Private method end
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.hutool.poi.excel.sax;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.poi.excel.sax.handler.RowHandler;
|
||||
@ -116,12 +117,12 @@ public class Excel03SaxReader implements HSSFListener, ExcelSaxReader<Excel03Sax
|
||||
* 读取
|
||||
*
|
||||
* @param fs {@link POIFSFileSystem}
|
||||
* @param id sheet序号
|
||||
* @param id sheet序号,从0开始
|
||||
* @return this
|
||||
* @throws POIException IO异常包装
|
||||
*/
|
||||
public Excel03SaxReader read(POIFSFileSystem fs, String id) throws POIException {
|
||||
this.rid = Integer.parseInt(id);
|
||||
this.rid = getSheetIndex(id);
|
||||
|
||||
formatListener = new FormatTrackingHSSFListener(new MissingRecordAwareHSSFListener(this));
|
||||
final HSSFRequest request = new HSSFRequest();
|
||||
@ -341,5 +342,32 @@ public class Excel03SaxReader implements HSSFListener, ExcelSaxReader<Excel03Sax
|
||||
private boolean isProcessCurrentSheet() {
|
||||
return this.rid < 0 || this.curRid == this.rid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取sheet索引,从0开始
|
||||
* <ul>
|
||||
* <li>传入'rId'开头,直接去除rId前缀</li>
|
||||
* <li>传入纯数字,表示sheetIndex,直接转换为rid</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param idOrRidOrSheetName Excel中的sheet id或者rid编号或sheet名称,从0开始,rid必须加rId前缀,例如rId0,如果为-1处理所有编号的sheet
|
||||
* @return sheet索引,从0开始
|
||||
* @since 5.5.5
|
||||
*/
|
||||
private int getSheetIndex(String idOrRidOrSheetName) {
|
||||
Assert.notBlank(idOrRidOrSheetName, "id or rid or sheetName must be not blank!");
|
||||
|
||||
// rid直接处理
|
||||
if (StrUtil.startWithIgnoreCase(idOrRidOrSheetName, RID_PREFIX)) {
|
||||
return Integer.parseInt(StrUtil.removePrefixIgnoreCase(idOrRidOrSheetName, RID_PREFIX));
|
||||
}
|
||||
|
||||
final int sheetIndex;
|
||||
try {
|
||||
return Integer.parseInt(idOrRidOrSheetName);
|
||||
} catch (NumberFormatException ignore) {
|
||||
throw new IllegalArgumentException("Invalid sheet id: " + idOrRidOrSheetName);
|
||||
}
|
||||
}
|
||||
// ---------------------------------------------------------------------------------------------- Private method end
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package cn.hutool.poi.excel.sax;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.poi.excel.sax.handler.RowHandler;
|
||||
import cn.hutool.poi.exceptions.POIException;
|
||||
@ -25,8 +24,6 @@ import java.util.Iterator;
|
||||
*/
|
||||
public class Excel07SaxReader implements ExcelSaxReader<Excel07SaxReader> {
|
||||
|
||||
// sheet r:Id前缀
|
||||
private static final String RID_PREFIX = "rId";
|
||||
private final SheetDataSaxHandler handler;
|
||||
|
||||
/**
|
||||
@ -56,9 +53,9 @@ public class Excel07SaxReader implements ExcelSaxReader<Excel07SaxReader> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Excel07SaxReader read(File file, String idOrRid) throws POIException {
|
||||
public Excel07SaxReader read(File file, String idOrRidOrSheetName) throws POIException {
|
||||
try {
|
||||
return read(OPCPackage.open(file), idOrRid);
|
||||
return read(OPCPackage.open(file), idOrRidOrSheetName);
|
||||
} catch (InvalidFormatException e) {
|
||||
throw new POIException(e);
|
||||
}
|
||||
@ -70,9 +67,9 @@ public class Excel07SaxReader implements ExcelSaxReader<Excel07SaxReader> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Excel07SaxReader read(InputStream in, String idOrRid) throws POIException {
|
||||
public Excel07SaxReader read(InputStream in, String idOrRidOrSheetName) throws POIException {
|
||||
try (final OPCPackage opcPackage = OPCPackage.open(in)) {
|
||||
return read(opcPackage, idOrRid);
|
||||
return read(opcPackage, idOrRidOrSheetName);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
} catch (InvalidFormatException e) {
|
||||
@ -96,13 +93,13 @@ public class Excel07SaxReader implements ExcelSaxReader<Excel07SaxReader> {
|
||||
* 开始读取Excel,Sheet编号从0开始计数
|
||||
*
|
||||
* @param opcPackage {@link OPCPackage},Excel包,读取后不关闭
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @param idOrRidOrSheetName Excel中的sheet id或者rid编号或sheet名,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
*/
|
||||
public Excel07SaxReader read(OPCPackage opcPackage, String idOrRid) throws POIException {
|
||||
public Excel07SaxReader read(OPCPackage opcPackage, String idOrRidOrSheetName) throws POIException {
|
||||
try {
|
||||
return read(new XSSFReader(opcPackage), idOrRid);
|
||||
return read(new XSSFReader(opcPackage), idOrRidOrSheetName);
|
||||
} catch (OpenXML4JException e) {
|
||||
throw new POIException(e);
|
||||
} catch (IOException e) {
|
||||
@ -114,12 +111,12 @@ public class Excel07SaxReader implements ExcelSaxReader<Excel07SaxReader> {
|
||||
* 开始读取Excel,Sheet编号从0开始计数
|
||||
*
|
||||
* @param xssfReader {@link XSSFReader},Excel读取器
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @param idOrRidOrSheetName Excel中的sheet id或者rid编号或sheet名,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public Excel07SaxReader read(XSSFReader xssfReader, String idOrRid) throws POIException {
|
||||
public Excel07SaxReader read(XSSFReader xssfReader, String idOrRidOrSheetName) throws POIException {
|
||||
// 获取共享样式表,样式非必须
|
||||
try {
|
||||
this.handler.stylesTable = xssfReader.getStylesTable();
|
||||
@ -136,7 +133,7 @@ public class Excel07SaxReader implements ExcelSaxReader<Excel07SaxReader> {
|
||||
throw new POIException(e);
|
||||
}
|
||||
|
||||
return readSheets(xssfReader, idOrRid);
|
||||
return readSheets(xssfReader, idOrRidOrSheetName);
|
||||
}
|
||||
// ------------------------------------------------------------------------------ Read end
|
||||
|
||||
@ -145,22 +142,14 @@ public class Excel07SaxReader implements ExcelSaxReader<Excel07SaxReader> {
|
||||
/**
|
||||
* 开始读取Excel,Sheet编号从0开始计数
|
||||
*
|
||||
* @param xssfReader {@link XSSFReader},Excel读取器
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId0,如果为-1处理所有编号的sheet
|
||||
* @param xssfReader {@link XSSFReader},Excel读取器
|
||||
* @param idOrRidOrSheetName Excel中的sheet id或者rid编号或sheet名,从0开始,rid必须加rId前缀,例如rId0,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
* @since 5.4.4
|
||||
*/
|
||||
private Excel07SaxReader readSheets(XSSFReader xssfReader, String idOrRid) throws POIException {
|
||||
// 将sheetId转换为rid
|
||||
if (NumberUtil.isInteger(idOrRid)) {
|
||||
final SheetRidReader ridReader = new SheetRidReader();
|
||||
final String rid = ridReader.read(xssfReader).getRidBySheetId(idOrRid);
|
||||
if (StrUtil.isNotEmpty(rid)) {
|
||||
idOrRid = rid;
|
||||
}
|
||||
}
|
||||
this.handler.sheetIndex = Integer.parseInt(StrUtil.removePrefixIgnoreCase(idOrRid, RID_PREFIX));
|
||||
private Excel07SaxReader readSheets(XSSFReader xssfReader, String idOrRidOrSheetName) throws POIException {
|
||||
this.handler.sheetIndex = getSheetIndex(xssfReader, idOrRidOrSheetName);
|
||||
InputStream sheetInputStream = null;
|
||||
try {
|
||||
if (this.handler.sheetIndex > -1) {
|
||||
@ -190,5 +179,44 @@ public class Excel07SaxReader implements ExcelSaxReader<Excel07SaxReader> {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取sheet索引,从0开始
|
||||
* <ul>
|
||||
* <li>传入'rId'开头,直接去除rId前缀</li>
|
||||
* <li>传入纯数字,表示sheetIndex,通过{@link SheetRidReader}转换为rId</li>
|
||||
* <li>传入其它字符串,表示sheetName,通过{@link SheetRidReader}转换为rId</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param xssfReader {@link XSSFReader},Excel读取器
|
||||
* @param idOrRidOrSheetName Excel中的sheet id或者rid编号或sheet名称,从0开始,rid必须加rId前缀,例如rId0,如果为-1处理所有编号的sheet
|
||||
* @return sheet索引,从0开始
|
||||
* @since 5.5.5
|
||||
*/
|
||||
private int getSheetIndex(XSSFReader xssfReader, String idOrRidOrSheetName) {
|
||||
// rid直接处理
|
||||
if (StrUtil.startWithIgnoreCase(idOrRidOrSheetName, RID_PREFIX)) {
|
||||
return Integer.parseInt(StrUtil.removePrefixIgnoreCase(idOrRidOrSheetName, RID_PREFIX));
|
||||
}
|
||||
|
||||
// sheetIndex需转换为rid
|
||||
final SheetRidReader ridReader = new SheetRidReader().read(xssfReader);
|
||||
|
||||
final int sheetIndex;
|
||||
Integer rid;
|
||||
try {
|
||||
sheetIndex = Integer.parseInt(idOrRidOrSheetName);
|
||||
rid = ridReader.getRidBySheetIdBase0(sheetIndex);
|
||||
return (null != rid) ? rid : sheetIndex;
|
||||
} catch (NumberFormatException ignore) {
|
||||
// 非数字,可能为sheet名称
|
||||
rid = ridReader.getRidByNameBase0(idOrRidOrSheetName);
|
||||
if (null != rid) {
|
||||
return rid;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Invalid rId or id or sheetName: " + idOrRidOrSheetName);
|
||||
}
|
||||
// --------------------------------------------------------------------------------------- Private method end
|
||||
}
|
@ -15,6 +15,9 @@ import java.io.InputStream;
|
||||
*/
|
||||
public interface ExcelSaxReader<T> {
|
||||
|
||||
// sheet r:Id前缀
|
||||
String RID_PREFIX = "rId";
|
||||
|
||||
/**
|
||||
* 开始读取Excel
|
||||
*
|
||||
|
@ -6,6 +6,7 @@ import cn.hutool.core.exceptions.DependencyException;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.poi.excel.ExcelDateUtil;
|
||||
import cn.hutool.poi.excel.sax.handler.RowHandler;
|
||||
import cn.hutool.poi.exceptions.POIException;
|
||||
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
|
||||
@ -209,16 +210,10 @@ public class ExcelSaxUtil {
|
||||
* @param formatString 格式字符串
|
||||
* @return 是否为日期格式
|
||||
* @since 5.5.3
|
||||
* @see ExcelDateUtil#isDateFormat(int, String)
|
||||
*/
|
||||
public static boolean isDateFormat(int formatIndex, String formatString) {
|
||||
// https://blog.csdn.net/u014342130/article/details/50619503
|
||||
// issue#1283@Github
|
||||
if (formatIndex == 28 || formatIndex == 31) {
|
||||
// 28 -> m月d日
|
||||
// 31 -> yyyy年m月d日
|
||||
return true;
|
||||
}
|
||||
return org.apache.poi.ss.usermodel.DateUtil.isADateFormat(formatIndex, formatString);
|
||||
return ExcelDateUtil.isDateFormat(formatIndex, formatString);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,7 +29,7 @@ public class SheetDataSaxHandler extends DefaultHandler {
|
||||
protected StylesTable stylesTable;
|
||||
// excel 2007 的共享字符串表,对应sharedString.xml
|
||||
protected SharedStringsTable sharedStringsTable;
|
||||
// sheet的索引
|
||||
// sheet的索引,从0开始
|
||||
protected int sheetIndex;
|
||||
|
||||
// 当前非空行
|
||||
|
@ -17,7 +17,7 @@ import java.util.Map;
|
||||
/**
|
||||
* 在Sax方式读取Excel时,读取sheet标签中sheetId和rid的对应关系,类似于:
|
||||
* <pre>
|
||||
* <sheet name="Sheet6" sheetId="4" r:id="6"/>
|
||||
* <sheet name="Sheet6" sheetId="4" r:id="rId6"/>
|
||||
* </pre>
|
||||
* <p>
|
||||
* 读取结果为:
|
||||
@ -36,8 +36,8 @@ public class SheetRidReader extends DefaultHandler {
|
||||
private final static String SHEET_ID_ATTR = "sheetId";
|
||||
private final static String NAME_ATTR = "name";
|
||||
|
||||
private final Map<String, String> ID_RID_MAP = new HashMap<>();
|
||||
private final Map<String, String> NAME_RID_MAP = new HashMap<>();
|
||||
private final Map<Integer, Integer> ID_RID_MAP = new HashMap<>();
|
||||
private final Map<String, Integer> NAME_RID_MAP = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 读取Wordkbook的XML中sheet标签中sheetId和rid的对应关系
|
||||
@ -61,50 +61,74 @@ public class SheetRidReader extends DefaultHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据sheetId获取rid
|
||||
* 根据sheetId获取rid,从1开始
|
||||
*
|
||||
* @param sheetId Sheet的ID
|
||||
* @return rid
|
||||
* @param sheetId Sheet的ID,从1开始
|
||||
* @return rid,从1开始
|
||||
*/
|
||||
public String getRidBySheetId(String sheetId) {
|
||||
public Integer getRidBySheetId(int sheetId) {
|
||||
return ID_RID_MAP.get(sheetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据sheet name获取rid
|
||||
* 根据sheetId获取rid,从0开始
|
||||
*
|
||||
* @param sheetId Sheet的ID,从0开始
|
||||
* @return rid,从0开始
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public Integer getRidBySheetIdBase0(int sheetId) {
|
||||
final Integer rid = getRidBySheetId(sheetId + 1);
|
||||
if(null != rid){
|
||||
return rid - 1;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据sheet name获取rid,从1开始
|
||||
*
|
||||
* @param sheetName Sheet的name
|
||||
* @return rid
|
||||
* @return rid,从1开始
|
||||
*/
|
||||
public String getRidByName(String sheetName) {
|
||||
public Integer getRidByName(String sheetName) {
|
||||
return NAME_RID_MAP.get(sheetName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据sheet name获取rid,从0开始
|
||||
*
|
||||
* @param sheetName Sheet的name
|
||||
* @return rid,从0开始
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public Integer getRidByNameBase0(String sheetName) {
|
||||
final Integer rid = getRidByName(sheetName);
|
||||
if(null != rid){
|
||||
return rid - 1;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||
if (TAG_NAME.equalsIgnoreCase(localName)) {
|
||||
final int length = attributes.getLength();
|
||||
String sheetId = null;
|
||||
String rid = null;
|
||||
String name = null;
|
||||
for (int i = 0; i < length; i++) {
|
||||
switch (attributes.getLocalName(i)) {
|
||||
case SHEET_ID_ATTR:
|
||||
sheetId = attributes.getValue(i);
|
||||
break;
|
||||
case RID_ATTR:
|
||||
rid = attributes.getValue(i);
|
||||
break;
|
||||
case NAME_ATTR:
|
||||
name = attributes.getValue(i);
|
||||
break;
|
||||
}
|
||||
if (StrUtil.isNotEmpty(sheetId)) {
|
||||
ID_RID_MAP.put(sheetId, rid);
|
||||
}
|
||||
if (StrUtil.isNotEmpty(name)) {
|
||||
NAME_RID_MAP.put(name, rid);
|
||||
}
|
||||
final String ridStr = attributes.getValue(SHEET_ID_ATTR);
|
||||
if(StrUtil.isEmpty(ridStr)){
|
||||
return;
|
||||
}
|
||||
final int rid = Integer.parseInt(StrUtil.removePrefixIgnoreCase(ridStr, Excel07SaxReader.RID_PREFIX));
|
||||
|
||||
// sheet名和rid映射
|
||||
final String name = attributes.getValue(NAME_ATTR);
|
||||
if (StrUtil.isNotEmpty(name)) {
|
||||
NAME_RID_MAP.put(name, rid);
|
||||
}
|
||||
|
||||
// sheetId和rid映射
|
||||
final String sheetIdStr = attributes.getValue(SHEET_ID_ATTR);
|
||||
if(StrUtil.isNotEmpty(sheetIdStr)){
|
||||
ID_RID_MAP.put(Integer.parseInt(sheetIdStr), rid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package cn.hutool.poi.excel.style;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.DataFormat;
|
||||
import org.apache.poi.ss.usermodel.FillPatternType;
|
||||
import org.apache.poi.ss.usermodel.Font;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
@ -10,20 +12,18 @@ import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
* Excel样式工具类
|
||||
*
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class StyleUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 克隆新的{@link CellStyle}
|
||||
*
|
||||
* @param cell 单元格
|
||||
*
|
||||
* @param cell 单元格
|
||||
* @param cellStyle 被复制的样式
|
||||
* @return {@link CellStyle}
|
||||
*/
|
||||
@ -33,8 +33,8 @@ public class StyleUtil {
|
||||
|
||||
/**
|
||||
* 克隆新的{@link CellStyle}
|
||||
*
|
||||
* @param workbook 工作簿
|
||||
*
|
||||
* @param workbook 工作簿
|
||||
* @param cellStyle 被复制的样式
|
||||
* @return {@link CellStyle}
|
||||
*/
|
||||
@ -43,13 +43,13 @@ public class StyleUtil {
|
||||
newCellStyle.cloneStyleFrom(cellStyle);
|
||||
return newCellStyle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置cell文本对齐样式
|
||||
*
|
||||
*
|
||||
* @param cellStyle {@link CellStyle}
|
||||
* @param halign 横向位置
|
||||
* @param valign 纵向位置
|
||||
* @param halign 横向位置
|
||||
* @param valign 纵向位置
|
||||
* @return {@link CellStyle}
|
||||
*/
|
||||
public static CellStyle setAlign(CellStyle cellStyle, HorizontalAlignment halign, VerticalAlignment valign) {
|
||||
@ -60,8 +60,8 @@ public class StyleUtil {
|
||||
|
||||
/**
|
||||
* 设置cell的四个边框粗细和颜色
|
||||
*
|
||||
* @param cellStyle {@link CellStyle}
|
||||
*
|
||||
* @param cellStyle {@link CellStyle}
|
||||
* @param borderSize 边框粗细{@link BorderStyle}枚举
|
||||
* @param colorIndex 颜色的short值
|
||||
* @return {@link CellStyle}
|
||||
@ -81,12 +81,12 @@ public class StyleUtil {
|
||||
|
||||
return cellStyle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 给cell设置颜色
|
||||
*
|
||||
* @param cellStyle {@link CellStyle}
|
||||
* @param color 背景颜色
|
||||
*
|
||||
* @param cellStyle {@link CellStyle}
|
||||
* @param color 背景颜色
|
||||
* @param fillPattern 填充方式 {@link FillPatternType}枚举
|
||||
* @return {@link CellStyle}
|
||||
*/
|
||||
@ -96,9 +96,9 @@ public class StyleUtil {
|
||||
|
||||
/**
|
||||
* 给cell设置颜色
|
||||
*
|
||||
* @param cellStyle {@link CellStyle}
|
||||
* @param color 背景颜色
|
||||
*
|
||||
* @param cellStyle {@link CellStyle}
|
||||
* @param color 背景颜色
|
||||
* @param fillPattern 填充方式 {@link FillPatternType}枚举
|
||||
* @return {@link CellStyle}
|
||||
*/
|
||||
@ -107,12 +107,12 @@ public class StyleUtil {
|
||||
cellStyle.setFillPattern(fillPattern);
|
||||
return cellStyle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建字体
|
||||
*
|
||||
*
|
||||
* @param workbook {@link Workbook}
|
||||
* @param color 字体颜色
|
||||
* @param color 字体颜色
|
||||
* @param fontSize 字体大小
|
||||
* @param fontName 字体名称,可以为null使用默认字体
|
||||
* @return {@link Font}
|
||||
@ -121,24 +121,24 @@ public class StyleUtil {
|
||||
final Font font = workbook.createFont();
|
||||
return setFontStyle(font, color, fontSize, fontName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置字体样式
|
||||
*
|
||||
* @param font 字体{@link Font}
|
||||
* @param color 字体颜色
|
||||
*
|
||||
* @param font 字体{@link Font}
|
||||
* @param color 字体颜色
|
||||
* @param fontSize 字体大小
|
||||
* @param fontName 字体名称,可以为null使用默认字体
|
||||
* @return {@link Font}
|
||||
*/
|
||||
public static Font setFontStyle(Font font, short color, short fontSize, String fontName) {
|
||||
if(color > 0) {
|
||||
if (color > 0) {
|
||||
font.setColor(color);
|
||||
}
|
||||
if(fontSize > 0) {
|
||||
if (fontSize > 0) {
|
||||
font.setFontHeightInPoints(fontSize);
|
||||
}
|
||||
if(StrUtil.isNotBlank(fontName)) {
|
||||
if (StrUtil.isNotBlank(fontName)) {
|
||||
font.setFontName(fontName);
|
||||
}
|
||||
return font;
|
||||
@ -153,7 +153,7 @@ public class StyleUtil {
|
||||
* @since 5.4.0
|
||||
*/
|
||||
public static CellStyle createCellStyle(Workbook workbook) {
|
||||
if(null == workbook){
|
||||
if (null == workbook) {
|
||||
return null;
|
||||
}
|
||||
return workbook.createCellStyle();
|
||||
@ -161,12 +161,12 @@ public class StyleUtil {
|
||||
|
||||
/**
|
||||
* 创建默认普通单元格样式
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* 1. 文字上下左右居中
|
||||
* 2. 细边框,黑色
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @param workbook {@link Workbook} 工作簿
|
||||
* @return {@link CellStyle}
|
||||
*/
|
||||
@ -179,7 +179,7 @@ public class StyleUtil {
|
||||
|
||||
/**
|
||||
* 创建默认头部样式
|
||||
*
|
||||
*
|
||||
* @param workbook {@link Workbook} 工作簿
|
||||
* @return {@link CellStyle}
|
||||
*/
|
||||
@ -190,15 +190,28 @@ public class StyleUtil {
|
||||
setColor(cellStyle, IndexedColors.GREY_25_PERCENT, FillPatternType.SOLID_FOREGROUND);
|
||||
return cellStyle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 给定样式是否为null(无样式)或默认样式,默认样式为<code>workbook.getCellStyleAt(0)</code>
|
||||
* 给定样式是否为null(无样式)或默认样式,默认样式为{@code workbook.getCellStyleAt(0)}
|
||||
*
|
||||
* @param workbook 工作簿
|
||||
* @param style 被检查的样式
|
||||
* @param style 被检查的样式
|
||||
* @return 是否为null(无样式)或默认样式
|
||||
* @since 4.6.3
|
||||
*/
|
||||
public static boolean isNullOrDefaultStyle(Workbook workbook, CellStyle style) {
|
||||
return (null == style) || style.equals(workbook.getCellStyleAt(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建数据格式并获取格式
|
||||
*
|
||||
* @param format 数据格式
|
||||
* @return 数据格式
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public Short getFormat(Workbook workbook, String format) {
|
||||
final DataFormat dataFormat = workbook.createDataFormat();
|
||||
return dataFormat.getFormat(format);
|
||||
}
|
||||
}
|
||||
|
@ -58,9 +58,19 @@ public class ExcelSaxReadTest {
|
||||
|
||||
@Test
|
||||
public void readBySaxTest() {
|
||||
ExcelUtil.readBySax("blankAndDateTest.xlsx", "0", createRowHandler());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readBySaxByRidTest() {
|
||||
ExcelUtil.readBySax("blankAndDateTest.xlsx", 0, createRowHandler());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readBySaxByNameTest() {
|
||||
ExcelUtil.readBySax("blankAndDateTest.xlsx", "Sheet1", createRowHandler());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void readBySaxTest2() {
|
||||
@ -164,6 +174,14 @@ public class ExcelSaxReadTest {
|
||||
Assert.assertEquals("2012-12-21 00:00:00", rows.get(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void dateReadXlsxTest2() {
|
||||
ExcelUtil.readBySax("d:/test/custom_date_format2.xlsx", 0,
|
||||
(i, i1, list) -> Console.log(list)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void readBlankTest() {
|
||||
|
@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-script</artifactId>
|
||||
@ -18,7 +18,7 @@
|
||||
<properties>
|
||||
<jython.version>2.7.2</jython.version>
|
||||
<luaj.version>3.0.1</luaj.version>
|
||||
<groovy.version>3.0.6</groovy.version>
|
||||
<groovy.version>3.0.7</groovy.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-setting</artifactId>
|
||||
|
@ -40,9 +40,9 @@ public class PropsUtil {
|
||||
|
||||
/**
|
||||
* 获取给定路径找到的第一个配置文件<br>
|
||||
* * name可以为不包括扩展名的文件名(默认.setting为结尾),也可以是文件名全称
|
||||
* * name可以为不包括扩展名的文件名(默认.properties为结尾),也可以是文件名全称
|
||||
*
|
||||
* @param names 文件名,如果没有扩展名,默认为.setting
|
||||
* @param names 文件名,如果没有扩展名,默认为.properties
|
||||
*
|
||||
* @return 当前环境下配置文件
|
||||
*/
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-socket</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-system</artifactId>
|
||||
@ -26,7 +26,7 @@
|
||||
<dependency>
|
||||
<groupId>com.github.oshi</groupId>
|
||||
<artifactId>oshi-core</artifactId>
|
||||
<version>5.3.6</version>
|
||||
<version>5.3.7</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
2
pom.xml
2
pom.xml
@ -8,7 +8,7 @@
|
||||
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.5.4</version>
|
||||
<version>5.5.5</version>
|
||||
<name>hutool</name>
|
||||
<description>Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。</description>
|
||||
<url>https://github.com/looly/hutool</url>
|
||||
|
Loading…
Reference in New Issue
Block a user