mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-08-18 20:38:02 +08:00
merge conflict
This commit is contained in:
17
CHANGELOG.md
17
CHANGELOG.md
@@ -3,15 +3,30 @@
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.6.7 (2021-06-02)
|
||||
# 5.6.8 (2021-06-09)
|
||||
|
||||
### 🐣新特性
|
||||
|
||||
### 🐞Bug修复
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.6.7 (2021-06-08)
|
||||
|
||||
### 🐣新特性
|
||||
* 【core 】 CharSequenceUtil增加join重载(issue#I3TFJ5@Gitee)
|
||||
* 【http 】 HttpRequest增加form方法重载(pr#337@Gitee)
|
||||
* 【http 】 ImgUtil增加getMainColor方法(pr#338@Gitee)
|
||||
* 【core 】 改进TreeUtil.buid算法性能(pr#1594@Github)
|
||||
* 【core 】 CsvConfig的setXXX返回this(issue#I3UIQF@Gitee)
|
||||
* 【all 】 增加jmh基准测试
|
||||
* 【core 】 增加StreamUtil和CollectorUtil
|
||||
* 【poi 】 增加content-type(pr#1639@Github)
|
||||
|
||||
### 🐞Bug修复
|
||||
* 【core 】 修复FileUtil.normalize去掉末尾空格问题(issue#1603@Github)
|
||||
* 【core 】 修复CharsetDetector流关闭问题(issue#1603@Github)
|
||||
* 【core 】 修复RuntimeUtil.exec引号内空格被切分的问题(issue#I3UAYB@Gitee)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@@ -122,18 +122,18 @@ Each module can be introduced individually, or all modules can be introduced by
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.6.7</version>
|
||||
<version>5.6.8</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### 🍐Gradle
|
||||
```
|
||||
compile 'cn.hutool:hutool-all:5.6.7'
|
||||
compile 'cn.hutool:hutool-all:5.6.8'
|
||||
```
|
||||
|
||||
## 📥Download
|
||||
|
||||
- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.7/)
|
||||
- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.8/)
|
||||
|
||||
> 🔔️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.
|
||||
|
@@ -120,20 +120,20 @@ Hutool的存在就是为了减少代码搜索成本,避免网络上参差不
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.6.7</version>
|
||||
<version>5.6.8</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### 🍐Gradle
|
||||
```
|
||||
compile 'cn.hutool:hutool-all:5.6.7'
|
||||
compile 'cn.hutool:hutool-all:5.6.8'
|
||||
```
|
||||
|
||||
### 📥下载jar
|
||||
|
||||
点击以下链接,下载`hutool-all-X.X.X.jar`即可:
|
||||
|
||||
- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.7/)
|
||||
- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.6.8/)
|
||||
|
||||
> 🔔️注意
|
||||
> Hutool 5.x支持JDK8+,对Android平台没有测试,不能保证所有工具类或工具方法可用。
|
||||
|
@@ -1 +1 @@
|
||||
5.6.7
|
||||
5.6.8
|
||||
|
@@ -1 +1 @@
|
||||
var version = '5.6.7'
|
||||
var version = '5.6.8'
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-all</artifactId>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-aop</artifactId>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-bloomFilter</artifactId>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-bom</artifactId>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-cache</artifactId>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-captcha</artifactId>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-core</artifactId>
|
||||
|
@@ -273,19 +273,19 @@ public class BeanDesc implements Serializable {
|
||||
if (fieldName.startsWith("is")) {
|
||||
// 字段已经是is开头
|
||||
if (methodName.equals(fieldName) // isName -》 isName
|
||||
|| methodName.equals("get" + handledFieldName)// isName -》 getIsName
|
||||
|| methodName.equals("is" + handledFieldName)// isName -》 isIsName
|
||||
|| ("get" + handledFieldName).equals(methodName)// isName -》 getIsName
|
||||
|| ("is" + handledFieldName).equals(methodName)// isName -》 isIsName
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
} else if (methodName.equals("is" + handledFieldName)) {
|
||||
} else if (("is" + handledFieldName).equals(methodName)) {
|
||||
// 字段非is开头, name -》 isName
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 包括boolean的任何类型只有一种匹配情况:name -》 getName
|
||||
return methodName.equals("get" + handledFieldName);
|
||||
return ("get" + handledFieldName).equals(methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,15 +324,15 @@ public class BeanDesc implements Serializable {
|
||||
// 针对Boolean类型特殊检查
|
||||
if (isBooleanField && fieldName.startsWith("is")) {
|
||||
// 字段是is开头
|
||||
if (methodName.equals("set" + StrUtil.removePrefix(fieldName, "is"))// isName -》 setName
|
||||
|| methodName.equals("set" + handledFieldName)// isName -》 setIsName
|
||||
if (("set" + StrUtil.removePrefix(fieldName, "is")).equals(methodName)// isName -》 setName
|
||||
|| ("set" + handledFieldName).equals(methodName)// isName -》 setIsName
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 包括boolean的任何类型只有一种匹配情况:name -》 setName
|
||||
return methodName.equals("set" + fieldName);
|
||||
return ("set" + fieldName).equals(methodName);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------------ Private method end
|
||||
}
|
||||
|
@@ -938,7 +938,7 @@ public class HashCodeBuilder implements Builder<Integer> {
|
||||
*/
|
||||
@Override
|
||||
public Integer build() {
|
||||
return Integer.valueOf(toHashCode());
|
||||
return toHashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -132,7 +132,7 @@ public class Base64Encoder {
|
||||
*
|
||||
* @param arr 被编码的数组
|
||||
* @param isMultiLine 在76个char之后是CRLF还是EOF
|
||||
* @param isUrlSafe 是否使用URL安全字符,一般为{@code false}
|
||||
* @param isUrlSafe 是否使用URL安全字符,在URL Safe模式下,=为URL中的关键字符,不需要补充。空余的byte位要去掉,一般为{@code false}
|
||||
* @return 编码后的bytes
|
||||
*/
|
||||
public static byte[] encode(byte[] arr, boolean isMultiLine, boolean isUrlSafe) {
|
||||
|
@@ -27,8 +27,8 @@ public class Morse {
|
||||
* @param dict 二进制
|
||||
*/
|
||||
private static void registerMorse(Character abc, String dict) {
|
||||
ALPHABETS.put(Integer.valueOf(abc), dict);
|
||||
DICTIONARIES.put(dict, Integer.valueOf(abc));
|
||||
ALPHABETS.put((int) abc, dict);
|
||||
DICTIONARIES.put(dict, (int) abc);
|
||||
}
|
||||
|
||||
static {
|
||||
|
@@ -510,6 +510,24 @@ public class CollUtil {
|
||||
return IterUtil.countMap(null == collection ? null : collection.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* 以 conjunction 为分隔符将集合转换为字符串
|
||||
*
|
||||
* @param <T> 集合元素类型
|
||||
* @param iterable {@link Iterable}
|
||||
* @param conjunction 分隔符
|
||||
* @param func 集合元素转换器,将元素转换为字符串
|
||||
* @return 连接后的字符串
|
||||
* @see IterUtil#join(Iterator, CharSequence, Function)
|
||||
* @since 5.6.7
|
||||
*/
|
||||
public static <T> String join(Iterable<T> iterable, CharSequence conjunction, Function<T, ? extends CharSequence> func) {
|
||||
if (null == iterable) {
|
||||
return null;
|
||||
}
|
||||
return IterUtil.join(iterable.iterator(), conjunction, func);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以 conjunction 为分隔符将集合转换为字符串<br>
|
||||
* 如果集合元素为数组、{@link Iterable}或{@link Iterator},则递归组合其为字符串
|
||||
@@ -1617,9 +1635,9 @@ public class CollUtil {
|
||||
* @since 5.6.6
|
||||
*/
|
||||
public static <T> int lastIndexOf(Collection<T> collection, Matcher<T> matcher) {
|
||||
if(collection instanceof List){
|
||||
if (collection instanceof List) {
|
||||
// List的查找最后一个有优化算法
|
||||
return ListUtil.lastIndexOf((List<T>)collection, matcher);
|
||||
return ListUtil.lastIndexOf((List<T>) collection, matcher);
|
||||
}
|
||||
int matchIndex = -1;
|
||||
if (isNotEmpty(collection)) {
|
||||
@@ -2612,7 +2630,7 @@ public class CollUtil {
|
||||
* @since 5.4.7
|
||||
*/
|
||||
public static <T> void forEach(Iterable<T> iterable, Consumer<T> consumer) {
|
||||
if(iterable == null){
|
||||
if (iterable == null) {
|
||||
return;
|
||||
}
|
||||
forEach(iterable.iterator(), consumer);
|
||||
@@ -2626,7 +2644,7 @@ public class CollUtil {
|
||||
* @param consumer {@link Consumer} 遍历的每条数据处理器
|
||||
*/
|
||||
public static <T> void forEach(Iterator<T> iterator, Consumer<T> consumer) {
|
||||
if(iterator == null){
|
||||
if (iterator == null) {
|
||||
return;
|
||||
}
|
||||
int index = 0;
|
||||
@@ -2644,7 +2662,7 @@ public class CollUtil {
|
||||
* @param consumer {@link Consumer} 遍历的每条数据处理器
|
||||
*/
|
||||
public static <T> void forEach(Enumeration<T> enumeration, Consumer<T> consumer) {
|
||||
if(enumeration == null){
|
||||
if (enumeration == null) {
|
||||
return;
|
||||
}
|
||||
int index = 0;
|
||||
@@ -2664,7 +2682,7 @@ public class CollUtil {
|
||||
* @param kvConsumer {@link KVConsumer} 遍历的每条数据处理器
|
||||
*/
|
||||
public static <K, V> void forEach(Map<K, V> map, KVConsumer<K, V> kvConsumer) {
|
||||
if(map == null){
|
||||
if (map == null) {
|
||||
return;
|
||||
}
|
||||
int index = 0;
|
||||
@@ -2986,7 +3004,7 @@ public class CollUtil {
|
||||
* @author Looly
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface KVConsumer<K, V> extends Serializable{
|
||||
public interface KVConsumer<K, V> extends Serializable {
|
||||
/**
|
||||
* 接受并处理一对参数
|
||||
*
|
||||
|
@@ -337,6 +337,31 @@ public class IterUtil {
|
||||
* @since 4.0.10
|
||||
*/
|
||||
public static <T> String join(Iterator<T> iterator, CharSequence conjunction, String prefix, String suffix) {
|
||||
return join(iterator, conjunction, (item)->{
|
||||
if (ArrayUtil.isArray(item)) {
|
||||
return ArrayUtil.join(ArrayUtil.wrap(item), conjunction, prefix, suffix);
|
||||
} else if (item instanceof Iterable<?>) {
|
||||
return join((Iterable<?>) item, conjunction, prefix, suffix);
|
||||
} else if (item instanceof Iterator<?>) {
|
||||
return join((Iterator<?>) item, conjunction, prefix, suffix);
|
||||
} else {
|
||||
return StrUtil.wrap(String.valueOf(item), prefix, suffix);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 以 conjunction 为分隔符将集合转换为字符串<br>
|
||||
* 如果集合元素为数组、{@link Iterable}或{@link Iterator},则递归组合其为字符串
|
||||
*
|
||||
* @param <T> 集合元素类型
|
||||
* @param iterator 集合
|
||||
* @param conjunction 分隔符
|
||||
* @param func 集合元素转换器,将元素转换为字符串
|
||||
* @return 连接后的字符串
|
||||
* @since 5.6.7
|
||||
*/
|
||||
public static <T> String join(Iterator<T> iterator, CharSequence conjunction, Function<T, ? extends CharSequence> func) {
|
||||
if (null == iterator) {
|
||||
return null;
|
||||
}
|
||||
@@ -352,15 +377,7 @@ public class IterUtil {
|
||||
}
|
||||
|
||||
item = iterator.next();
|
||||
if (ArrayUtil.isArray(item)) {
|
||||
sb.append(ArrayUtil.join(ArrayUtil.wrap(item), conjunction, prefix, suffix));
|
||||
} else if (item instanceof Iterable<?>) {
|
||||
sb.append(join((Iterable<?>) item, conjunction, prefix, suffix));
|
||||
} else if (item instanceof Iterator<?>) {
|
||||
sb.append(join((Iterator<?>) item, conjunction, prefix, suffix));
|
||||
} else {
|
||||
sb.append(StrUtil.wrap(String.valueOf(item), prefix, suffix));
|
||||
}
|
||||
sb.append(func.apply(item));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -826,7 +843,7 @@ public class IterUtil {
|
||||
* @since 5.5.0
|
||||
*/
|
||||
public static int size(final Iterable<?> iterable) {
|
||||
if(null == iterable){
|
||||
if (null == iterable) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -27,7 +27,6 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
/**
|
||||
* 时间工具类
|
||||
@@ -931,7 +930,6 @@ public class DateUtil extends CalendarUtil {
|
||||
|
||||
//标准日期格式(包括单个数字的日期时间)
|
||||
dateStr = normalize(dateStr);
|
||||
final Matcher matcher = DatePattern.REGEX_NORM.matcher(dateStr);
|
||||
if (ReUtil.isMatch(DatePattern.REGEX_NORM, dateStr)) {
|
||||
final int colonCount = StrUtil.count(dateStr, CharUtil.COLON);
|
||||
switch (colonCount) {
|
||||
|
@@ -299,7 +299,7 @@ public class FastDatePrinter extends AbstractDateBasic implements DatePrinter {
|
||||
} else if (obj instanceof Calendar) {
|
||||
return format((Calendar) obj);
|
||||
} else if (obj instanceof Long) {
|
||||
return format(((Long) obj).longValue());
|
||||
return format(((Long) obj));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown class: " + (obj == null ? "<null>" : obj.getClass().getName()));
|
||||
}
|
||||
|
@@ -113,7 +113,7 @@ abstract class FormatCache<F extends Format> {
|
||||
*/
|
||||
// package protected, for access from FastDateFormat; do not make public or protected
|
||||
F getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
|
||||
return getDateTimeInstance(Integer.valueOf(dateStyle), Integer.valueOf(timeStyle), timeZone, locale);
|
||||
return getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -43,8 +43,10 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
@@ -1164,7 +1166,7 @@ public class ImgUtil {
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public static BufferedImage toBufferedImage(Image image, String imageType) {
|
||||
final int type = imageType.equalsIgnoreCase(IMAGE_TYPE_PNG)
|
||||
final int type = IMAGE_TYPE_PNG.equalsIgnoreCase(imageType)
|
||||
? BufferedImage.TYPE_INT_ARGB
|
||||
: BufferedImage.TYPE_INT_RGB;
|
||||
return toBufferedImage(image, type);
|
||||
@@ -1724,7 +1726,7 @@ public class ImgUtil {
|
||||
}
|
||||
|
||||
if (null == result) {
|
||||
throw new IllegalArgumentException("Image type of [" + imageUrl.toString() + "] is not supported!");
|
||||
throw new IllegalArgumentException("Image type of [" + imageUrl + "] is not supported!");
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -2002,6 +2004,57 @@ public class ImgUtil {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取给定图片的主色调,背景填充用
|
||||
*
|
||||
* @param image {@link BufferedImage}
|
||||
* @param rgbFilters 过滤多种颜色
|
||||
* @return {@link String} #ffffff
|
||||
* @since 5.6.7
|
||||
*/
|
||||
public static String getMainColor(BufferedImage image, int[]... rgbFilters) {
|
||||
int r, g, b;
|
||||
Map<String, Long> countMap = new HashMap<>();
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
int minx = image.getMinX();
|
||||
int miny = image.getMinY();
|
||||
for (int i = minx; i < width; i++) {
|
||||
for (int j = miny; j < height; j++) {
|
||||
int pixel = image.getRGB(i, j);
|
||||
r = (pixel & 0xff0000) >> 16;
|
||||
g = (pixel & 0xff00) >> 8;
|
||||
b = (pixel & 0xff);
|
||||
if (rgbFilters != null && rgbFilters.length > 0) {
|
||||
for (int[] rgbFilter : rgbFilters) {
|
||||
if (r == rgbFilter[0] && g == rgbFilter[1] && b == rgbFilter[2]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
countMap.merge(r + "-" + g + "-" + b, 1L, Long::sum);
|
||||
}
|
||||
}
|
||||
String maxColor = null;
|
||||
long maxCount = 0;
|
||||
for (Map.Entry<String, Long> entry : countMap.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Long count = entry.getValue();
|
||||
if (count > maxCount) {
|
||||
maxColor = key;
|
||||
maxCount = count;
|
||||
}
|
||||
}
|
||||
final String[] splitRgbStr = StrUtil.splitToArray(maxColor, '-');
|
||||
String rHex = Integer.toHexString(Integer.parseInt(splitRgbStr[0]));
|
||||
String gHex = Integer.toHexString(Integer.parseInt(splitRgbStr[1]));
|
||||
String bHex = Integer.toHexString(Integer.parseInt(splitRgbStr[2]));
|
||||
rHex = rHex.length() == 1 ? "0" + rHex : rHex;
|
||||
gHex = gHex.length() == 1 ? "0" + gHex : gHex;
|
||||
bHex = bHex.length() == 1 ? "0" + bHex : bHex;
|
||||
return "#" + rHex + gHex + bHex;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------ 背景图换算
|
||||
|
||||
/**
|
||||
|
@@ -778,9 +778,6 @@ public class GifDecoder {
|
||||
lastRect = new Rectangle(ix, iy, iw, ih);
|
||||
lastImage = image;
|
||||
lastBgColor = bgColor;
|
||||
int dispose = 0;
|
||||
boolean transparency = false;
|
||||
int delay = 0;
|
||||
lct = null;
|
||||
}
|
||||
|
||||
|
@@ -350,10 +350,7 @@ public class NeuQuant {
|
||||
/* Unbias network to give byte values 0..255 and record position i to prepare for sort
|
||||
----------------------------------------------------------------------------------- */
|
||||
public void unbiasnet() {
|
||||
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < NETSIZE; i++) {
|
||||
for (int i = 0; i < NETSIZE; i++) {
|
||||
network[i][0] >>= NETBIASSHIFT;
|
||||
network[i][1] >>= NETBIASSHIFT;
|
||||
network[i][2] >>= NETBIASSHIFT;
|
||||
|
@@ -38,7 +38,7 @@ public class MutableBool implements Comparable<MutableBool>, Mutable<Boolean>, S
|
||||
|
||||
@Override
|
||||
public Boolean get() {
|
||||
return Boolean.valueOf(this.value);
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +51,7 @@ public class MutableBool implements Comparable<MutableBool>, Mutable<Boolean>, S
|
||||
|
||||
@Override
|
||||
public void set(final Boolean value) {
|
||||
this.value = value.booleanValue();
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
@@ -46,7 +46,7 @@ public class MutableByte extends Number implements Comparable<MutableByte>, Muta
|
||||
|
||||
@Override
|
||||
public Byte get() {
|
||||
return Byte.valueOf(this.value);
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -46,7 +46,7 @@ public class MutableDouble extends Number implements Comparable<MutableDouble>,
|
||||
|
||||
@Override
|
||||
public Double get() {
|
||||
return Double.valueOf(this.value);
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -46,7 +46,7 @@ public class MutableFloat extends Number implements Comparable<MutableFloat>, Mu
|
||||
|
||||
@Override
|
||||
public Float get() {
|
||||
return Float.valueOf(this.value);
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -46,7 +46,7 @@ public class MutableInt extends Number implements Comparable<MutableInt>, Mutabl
|
||||
|
||||
@Override
|
||||
public Integer get() {
|
||||
return Integer.valueOf(this.value);
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -46,7 +46,7 @@ public class MutableLong extends Number implements Comparable<MutableLong>, Muta
|
||||
|
||||
@Override
|
||||
public Long get() {
|
||||
return Long.valueOf(this.value);
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -46,7 +46,7 @@ public class MutableShort extends Number implements Comparable<MutableShort>, Mu
|
||||
|
||||
@Override
|
||||
public Short get() {
|
||||
return Short.valueOf(this.value);
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,8 +1,15 @@
|
||||
package cn.hutool.core.lang.tree;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
@@ -152,8 +159,32 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
|
||||
return (List<Tree<T>>) this.get(treeNodeConfig.getChildrenKey());
|
||||
}
|
||||
|
||||
public void setChildren(List<Tree<T>> children) {
|
||||
public Tree<T> setChildren(List<Tree<T>> children) {
|
||||
this.put(treeNodeConfig.getChildrenKey(), children);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加子节点,同时关联子节点的父节点为当前节点
|
||||
*
|
||||
* @param children 子节点列表
|
||||
* @return this
|
||||
* @since 5.6.7
|
||||
*/
|
||||
@SafeVarargs
|
||||
public final Tree<T> addChildren(Tree<T>... children){
|
||||
if(ArrayUtil.isNotEmpty(children)){
|
||||
List<Tree<T>> childrenList = this.getChildren();
|
||||
if(null == childrenList){
|
||||
childrenList = new ArrayList<>();
|
||||
setChildren(childrenList);
|
||||
}
|
||||
for (Tree<T> child : children) {
|
||||
child.setParent(this);
|
||||
childrenList.add(child);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,4 +197,29 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
|
||||
Assert.notEmpty(key, "Key must be not empty !");
|
||||
this.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringWriter stringWriter = new StringWriter();
|
||||
printTree(this, new PrintWriter(stringWriter), 0);
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印
|
||||
* @param tree 树
|
||||
* @param writer Writer
|
||||
* @param intent 缩进量
|
||||
*/
|
||||
private static void printTree(Tree<?> tree, PrintWriter writer, int intent){
|
||||
writer.println(StrUtil.format("{}{}[{}]", StrUtil.repeat(CharUtil.SPACE, intent), tree.getName(), tree.getId()));
|
||||
writer.flush();
|
||||
|
||||
final List<? extends Tree<?>> children = tree.getChildren();
|
||||
if(CollUtil.isNotEmpty(children)){
|
||||
for (Tree<?> child : children) {
|
||||
printTree(child, writer, intent + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,11 +3,13 @@ package cn.hutool.core.lang.tree;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.tree.parser.DefaultNodeParser;
|
||||
import cn.hutool.core.lang.tree.parser.NodeParser;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 树工具类
|
||||
@@ -58,65 +60,49 @@ public class TreeUtil {
|
||||
* @param <T> 转换的实体 为数据源里的对象类型
|
||||
* @param <E> ID类型
|
||||
* @param list 源数据集合
|
||||
* @param parentId 最顶层父id值 一般为 0 之类
|
||||
* @param rootId 最顶层父id值 一般为 0 之类
|
||||
* @param treeNodeConfig 配置
|
||||
* @param nodeParser 转换器
|
||||
* @return List
|
||||
*/
|
||||
public static <T, E> List<Tree<E>> build(List<T> list, E parentId, TreeNodeConfig treeNodeConfig, NodeParser<T, E> nodeParser) {
|
||||
final List<Tree<E>> treeList = CollUtil.newArrayList();
|
||||
Tree<E> tree;
|
||||
for (T obj : list) {
|
||||
tree = new Tree<>(treeNodeConfig);
|
||||
nodeParser.parse(obj, tree);
|
||||
treeList.add(tree);
|
||||
public static <T, E> List<Tree<E>> build(List<T> list, E rootId, TreeNodeConfig treeNodeConfig, NodeParser<T, E> nodeParser) {
|
||||
final Map<E, Tree<E>> map = new LinkedHashMap<>(list.size(), 1);
|
||||
Tree<E> node;
|
||||
for (T t : list) {
|
||||
node = new Tree<>(treeNodeConfig);
|
||||
nodeParser.parse(t, node);
|
||||
map.put(node.getId(), node);
|
||||
}
|
||||
|
||||
List<Tree<E>> finalTreeList = CollUtil.newArrayList();
|
||||
for (Tree<E> node : treeList) {
|
||||
if (ObjectUtil.equals(parentId,node.getParentId())) {
|
||||
finalTreeList.add(node);
|
||||
innerBuild(treeList, node, 0, treeNodeConfig.getDeep());
|
||||
}
|
||||
}
|
||||
// 内存每层已经排过了 这是最外层排序
|
||||
finalTreeList = finalTreeList.stream().sorted().collect(Collectors.toList());
|
||||
return finalTreeList;
|
||||
return build(map, rootId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归处理
|
||||
* 树构建,按照权重排序
|
||||
*
|
||||
* @param treeNodes 数据集合
|
||||
* @param parentNode 当前节点
|
||||
* @param deep 已递归深度
|
||||
* @param maxDeep 最大递归深度 可能为null即不限制
|
||||
* @param <E> ID类型
|
||||
* @param map 源数据Map
|
||||
* @param rootId 最顶层父id值 一般为 0 之类
|
||||
* @return List
|
||||
* @since 5.6.7
|
||||
*/
|
||||
private static <T> void innerBuild(List<Tree<T>> treeNodes, Tree<T> parentNode, int deep, Integer maxDeep) {
|
||||
public static <E> List<Tree<E>> build(Map<E, Tree<E>> map, E rootId) {
|
||||
final Map<E, Tree<E>> eTreeMap = MapUtil.sortByValue(map, false);
|
||||
List<Tree<E>> rootTreeList = CollUtil.newArrayList();
|
||||
E parentId;
|
||||
for (Tree<E> node : eTreeMap.values()) {
|
||||
parentId = node.getParentId();
|
||||
if(ObjectUtil.equals(rootId, parentId)){
|
||||
rootTreeList.add(node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CollUtil.isEmpty(treeNodes)) {
|
||||
return;
|
||||
}
|
||||
//maxDeep 可能为空
|
||||
if (maxDeep != null && deep >= maxDeep) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 每层排序 TreeNodeMap 实现了Comparable接口
|
||||
treeNodes = treeNodes.stream().sorted().collect(Collectors.toList());
|
||||
for (Tree<T> childNode : treeNodes) {
|
||||
if (parentNode.getId().equals(childNode.getParentId())) {
|
||||
List<Tree<T>> children = parentNode.getChildren();
|
||||
if (children == null) {
|
||||
children = CollUtil.newArrayList();
|
||||
parentNode.setChildren(children);
|
||||
}
|
||||
children.add(childNode);
|
||||
// childNode.setParentId(parentNode.getId());
|
||||
childNode.setParent(parentNode);
|
||||
innerBuild(treeNodes, childNode, deep + 1, maxDeep);
|
||||
final Tree<E> parentNode = map.get(parentId);
|
||||
if(null != parentNode){
|
||||
parentNode.addChildren(node);
|
||||
}
|
||||
}
|
||||
return rootTreeList;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,5 +168,4 @@ public class TreeUtil {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -243,7 +243,7 @@ public class NetUtil {
|
||||
long cBegin = NetUtil.ipv4ToLong("192.168.0.0");
|
||||
long cEnd = NetUtil.ipv4ToLong("192.168.255.255");
|
||||
|
||||
isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || ipAddress.equals(LOCAL_IP);
|
||||
isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || LOCAL_IP.equals(ipAddress);
|
||||
return isInnerIp;
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,64 @@
|
||||
package cn.hutool.core.stream;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collector;
|
||||
|
||||
/**
|
||||
* 可变的汇聚操作{@link Collector} 相关工具封装
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.6.7
|
||||
*/
|
||||
public class CollectorUtil {
|
||||
|
||||
/**
|
||||
* 提供任意对象的Join操作的{@link Collector}实现,对象默认调用toString方法
|
||||
*
|
||||
* @param delimiter 分隔符
|
||||
* @param <T> 对象类型
|
||||
* @return {@link Collector}
|
||||
*/
|
||||
public static <T> Collector<T, ?, String> joining(CharSequence delimiter) {
|
||||
return joining(delimiter, Object::toString);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供任意对象的Join操作的{@link Collector}实现
|
||||
*
|
||||
* @param delimiter 分隔符
|
||||
* @param toStringFunc 自定义指定对象转换为字符串的方法
|
||||
* @param <T> 对象类型
|
||||
* @return {@link Collector}
|
||||
*/
|
||||
public static <T> Collector<T, ?, String> joining(CharSequence delimiter,
|
||||
Function<T, ? extends CharSequence> toStringFunc) {
|
||||
return joining(delimiter, StrUtil.EMPTY, StrUtil.EMPTY, toStringFunc);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供任意对象的Join操作的{@link Collector}实现
|
||||
*
|
||||
* @param delimiter 分隔符
|
||||
* @param prefix 前缀
|
||||
* @param suffix 后缀
|
||||
* @param toStringFunc 自定义指定对象转换为字符串的方法
|
||||
* @param <T> 对象类型
|
||||
* @return {@link Collector}
|
||||
*/
|
||||
public static <T> Collector<T, ?, String> joining(CharSequence delimiter,
|
||||
CharSequence prefix,
|
||||
CharSequence suffix,
|
||||
Function<T, ? extends CharSequence> toStringFunc) {
|
||||
return new SimpleCollector<>(
|
||||
() -> new StringJoiner(delimiter, prefix, suffix),
|
||||
(joiner, ele) -> joiner.add(toStringFunc.apply(ele)),
|
||||
StringJoiner::merge,
|
||||
StringJoiner::toString,
|
||||
Collections.emptySet()
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,109 @@
|
||||
package cn.hutool.core.stream;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collector;
|
||||
|
||||
/**
|
||||
* 简单{@link Collector}接口实现
|
||||
*
|
||||
* @param <T> 输入数据类型
|
||||
* @param <A> 累积结果的容器类型
|
||||
* @param <R> 数据结果类型
|
||||
* @since 5.6.7
|
||||
*/
|
||||
public class SimpleCollector<T, A, R> implements Collector<T, A, R> {
|
||||
/**
|
||||
* 创建新的结果容器,容器类型为A
|
||||
*/
|
||||
private final Supplier<A> supplier;
|
||||
/**
|
||||
* 将输入元素合并到结果容器中
|
||||
*/
|
||||
private final BiConsumer<A, T> accumulator;
|
||||
/**
|
||||
* 合并两个结果容器(并行流使用,将多个线程产生的结果容器合并)
|
||||
*/
|
||||
private final BinaryOperator<A> combiner;
|
||||
/**
|
||||
* 将结果容器转换成最终的表示
|
||||
*/
|
||||
private final Function<A, R> finisher;
|
||||
/**
|
||||
* 特征值枚举,见{@link Characteristics}
|
||||
* <ul>
|
||||
* <li>CONCURRENT: 表示结果容器只有一个(即使是在并行流的情况下)。
|
||||
* 只有在并行流且收集器不具备此特性的情况下,combiner()返回的lambda表达式才会执行(中间结果容器只有一个就无需合并)。
|
||||
* 设置此特性时意味着多个线程可以对同一个结果容器调用,因此结果容器必须是线程安全的。</li>
|
||||
* <li>UNORDERED: 表示流中的元素无序</li>
|
||||
* <li>IDENTITY_FINISH:表示中间结果容器类型与最终结果类型一致。设置此特性时finiser()方法不会被调用</li>
|
||||
* </ul>
|
||||
*/
|
||||
private final Set<Characteristics> characteristics;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param supplier 创建新的结果容器函数
|
||||
* @param accumulator 将输入元素合并到结果容器中函数
|
||||
* @param combiner 合并两个结果容器函数(并行流使用,将多个线程产生的结果容器合并)
|
||||
* @param finisher 将结果容器转换成最终的表示函数
|
||||
* @param characteristics 特征值枚举
|
||||
*/
|
||||
public SimpleCollector(Supplier<A> supplier,
|
||||
BiConsumer<A, T> accumulator,
|
||||
BinaryOperator<A> combiner,
|
||||
Function<A, R> finisher,
|
||||
Set<Characteristics> characteristics) {
|
||||
this.supplier = supplier;
|
||||
this.accumulator = accumulator;
|
||||
this.combiner = combiner;
|
||||
this.finisher = finisher;
|
||||
this.characteristics = characteristics;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param supplier 创建新的结果容器函数
|
||||
* @param accumulator 将输入元素合并到结果容器中函数
|
||||
* @param combiner 合并两个结果容器函数(并行流使用,将多个线程产生的结果容器合并)
|
||||
* @param characteristics 特征值枚举
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public SimpleCollector(Supplier<A> supplier,
|
||||
BiConsumer<A, T> accumulator,
|
||||
BinaryOperator<A> combiner,
|
||||
Set<Characteristics> characteristics) {
|
||||
this(supplier, accumulator, combiner, i -> (R) i, characteristics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiConsumer<A, T> accumulator() {
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<A> supplier() {
|
||||
return supplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryOperator<A> combiner() {
|
||||
return combiner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<A, R> finisher() {
|
||||
return finisher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Characteristics> characteristics() {
|
||||
return characteristics;
|
||||
}
|
||||
|
||||
}
|
144
hutool-core/src/main/java/cn/hutool/core/stream/StreamUtil.java
Normal file
144
hutool-core/src/main/java/cn/hutool/core/stream/StreamUtil.java
Normal file
@@ -0,0 +1,144 @@
|
||||
package cn.hutool.core.stream;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
* {@link Stream} 工具类
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.6.7
|
||||
*/
|
||||
public class StreamUtil {
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> Stream<T> of(T... array) {
|
||||
Assert.notNull(array, "Array must be not null!");
|
||||
return Stream.of(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Iterable}转换为{@link Stream},默认非并行
|
||||
*
|
||||
* @param iterable 集合
|
||||
* @param <T> 集合元素类型
|
||||
* @return {@link Stream}
|
||||
*/
|
||||
public static <T> Stream<T> of(Iterable<T> iterable) {
|
||||
return of(iterable, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Iterable}转换为{@link Stream}
|
||||
*
|
||||
* @param iterable 集合
|
||||
* @param parallel 是否并行
|
||||
* @param <T> 集合元素类型
|
||||
* @return {@link Stream}
|
||||
*/
|
||||
public static <T> Stream<T> of(Iterable<T> iterable, boolean parallel) {
|
||||
Assert.notNull(iterable, "Iterable must be not null!");
|
||||
return StreamSupport.stream(
|
||||
Spliterators.spliterator(CollUtil.toCollection(iterable), 0),
|
||||
parallel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按行读取文件为{@link Stream}
|
||||
*
|
||||
* @param file 文件
|
||||
* @return {@link Stream}
|
||||
*/
|
||||
public static Stream<String> of(File file) {
|
||||
return of(file, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按行读取文件为{@link Stream}
|
||||
*
|
||||
* @param path 路径
|
||||
* @return {@link Stream}
|
||||
*/
|
||||
public static Stream<String> of(Path path) {
|
||||
return of(path, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按行读取文件为{@link Stream}
|
||||
*
|
||||
* @param file 文件
|
||||
* @param charset 编码
|
||||
* @return {@link Stream}
|
||||
*/
|
||||
public static Stream<String> of(File file, Charset charset) {
|
||||
Assert.notNull(file, "File must be not null!");
|
||||
return of(file.toPath(), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按行读取文件为{@link Stream}
|
||||
*
|
||||
* @param path 路径
|
||||
* @param charset 编码
|
||||
* @return {@link Stream}
|
||||
*/
|
||||
public static Stream<String> of(Path path, Charset charset) {
|
||||
try {
|
||||
return Files.lines(path, charset);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过函数创建Stream
|
||||
*
|
||||
* @param seed 初始值
|
||||
* @param elementCreator 递进函数,每次调用此函数获取下一个值
|
||||
* @param limit 限制个数
|
||||
* @param <T> 创建元素类型
|
||||
* @return {@link Stream}
|
||||
*/
|
||||
public static <T> Stream<T> of(T seed, UnaryOperator<T> elementCreator, int limit) {
|
||||
return Stream.iterate(seed, elementCreator).limit(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Stream中所有元素以指定分隔符,合并为一个字符串,对象默认调用toString方法
|
||||
*
|
||||
* @param stream {@link Stream}
|
||||
* @param delimiter 分隔符
|
||||
* @param <T> 元素类型
|
||||
* @return 字符串
|
||||
*/
|
||||
public static <T> String join(Stream<T> stream, CharSequence delimiter) {
|
||||
return stream.collect(CollectorUtil.joining(delimiter));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Stream中所有元素以指定分隔符,合并为一个字符串
|
||||
*
|
||||
* @param stream {@link Stream}
|
||||
* @param delimiter 分隔符
|
||||
* @param toStringFunc 元素转换为字符串的函数
|
||||
* @param <T> 元素类型
|
||||
* @return 字符串
|
||||
*/
|
||||
public static <T> String join(Stream<T> stream, CharSequence delimiter,
|
||||
Function<T, ? extends CharSequence> toStringFunc) {
|
||||
return stream.collect(CollectorUtil.joining(delimiter, toStringFunc));
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Java8的stream相关封装
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
package cn.hutool.core.stream;
|
@@ -1628,17 +1628,6 @@ public class CharSequenceUtil {
|
||||
|
||||
// ------------------------------------------------------------------------ split
|
||||
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @return 切分后的数组
|
||||
*/
|
||||
public static String[] splitToArray(CharSequence str, char separator) {
|
||||
return splitToArray(str, separator, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串为long数组
|
||||
*
|
||||
@@ -1700,6 +1689,33 @@ public class CharSequenceUtil {
|
||||
return split(str, separator, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串,如果分隔符不存在则返回原字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符
|
||||
* @return 字符串
|
||||
* @since 5.6.7
|
||||
*/
|
||||
public static String[] splitToArray(CharSequence str, CharSequence separator) {
|
||||
if (str == null) {
|
||||
return new String[]{};
|
||||
}
|
||||
|
||||
return StrSpliter.splitToArray(str.toString(), str(separator), 0, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @return 切分后的数组
|
||||
*/
|
||||
public static String[] splitToArray(CharSequence str, char separator) {
|
||||
return splitToArray(str, separator, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
@@ -1809,6 +1825,20 @@ public class CharSequenceUtil {
|
||||
return StrSpliter.split(str.toString(), separator, limit, isTrim, ignoreEmpty);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 5.6.7
|
||||
*/
|
||||
public static List<String> split(CharSequence str, CharSequence separator, boolean isTrim, boolean ignoreEmpty) {
|
||||
return split(str, separator, 0, isTrim, ignoreEmpty);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
@@ -1834,14 +1864,11 @@ public class CharSequenceUtil {
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符
|
||||
* @return 字符串
|
||||
* @deprecated 请使用 {@link #splitToArray(CharSequence, char)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static String[] split(CharSequence str, CharSequence separator) {
|
||||
if (str == null) {
|
||||
return new String[]{};
|
||||
}
|
||||
|
||||
final String separatorStr = (null == separator) ? null : separator.toString();
|
||||
return StrSpliter.splitToArray(str.toString(), separatorStr, 0, false, false);
|
||||
return splitToArray(str, separator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4237,6 +4264,7 @@ public class CharSequenceUtil {
|
||||
/**
|
||||
* 以 conjunction 为分隔符将多个对象转换为字符串
|
||||
*
|
||||
* @param <T> 元素类型
|
||||
* @param conjunction 分隔符
|
||||
* @param iterable 集合
|
||||
* @return 连接后的字符串
|
||||
|
@@ -12,7 +12,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 字符串切分器
|
||||
*
|
||||
*x
|
||||
* @author Looly
|
||||
*/
|
||||
public class StrSpliter {
|
||||
|
@@ -30,27 +30,33 @@ public class CsvConfig implements Serializable {
|
||||
* 设置字段分隔符,默认逗号','
|
||||
*
|
||||
* @param fieldSeparator 字段分隔符,默认逗号','
|
||||
* @return this
|
||||
*/
|
||||
public void setFieldSeparator(final char fieldSeparator) {
|
||||
public CsvConfig setFieldSeparator(final char fieldSeparator) {
|
||||
this.fieldSeparator = fieldSeparator;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 文本分隔符,文本包装符,默认双引号'"'
|
||||
*
|
||||
* @param textDelimiter 文本分隔符,文本包装符,默认双引号'"'
|
||||
* @return this
|
||||
*/
|
||||
public void setTextDelimiter(char textDelimiter) {
|
||||
public CsvConfig setTextDelimiter(char textDelimiter) {
|
||||
this.textDelimiter = textDelimiter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 注释符号,用于区分注释行
|
||||
*
|
||||
* @param commentCharacter 注释符号,用于区分注释行
|
||||
* @return this
|
||||
* @since 5.5.7
|
||||
*/
|
||||
public void setCommentCharacter(char commentCharacter) {
|
||||
public CsvConfig setCommentCharacter(char commentCharacter) {
|
||||
this.commentCharacter = commentCharacter;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@@ -31,26 +31,32 @@ public class CsvReadConfig extends CsvConfig implements Serializable {
|
||||
* 设置是否首行做为标题行,默认false
|
||||
*
|
||||
* @param containsHeader 是否首行做为标题行,默认false
|
||||
* @return this
|
||||
*/
|
||||
public void setContainsHeader(boolean containsHeader) {
|
||||
public CsvReadConfig setContainsHeader(boolean containsHeader) {
|
||||
this.containsHeader = containsHeader;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否跳过空白行,默认true
|
||||
*
|
||||
* @param skipEmptyRows 是否跳过空白行,默认true
|
||||
* @return this
|
||||
*/
|
||||
public void setSkipEmptyRows(boolean skipEmptyRows) {
|
||||
public CsvReadConfig setSkipEmptyRows(boolean skipEmptyRows) {
|
||||
this.skipEmptyRows = skipEmptyRows;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置每行字段个数不同时是否抛出异常,默认false
|
||||
*
|
||||
* @param errorOnDifferentFieldCount 每行字段个数不同时是否抛出异常,默认false
|
||||
* @return this
|
||||
*/
|
||||
public void setErrorOnDifferentFieldCount(boolean errorOnDifferentFieldCount) {
|
||||
public CsvReadConfig setErrorOnDifferentFieldCount(boolean errorOnDifferentFieldCount) {
|
||||
this.errorOnDifferentFieldCount = errorOnDifferentFieldCount;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@@ -1,21 +1,24 @@
|
||||
package cn.hutool.core.text.csv;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* CSV写出配置项
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
public class CsvWriteConfig extends CsvConfig implements Serializable {
|
||||
private static final long serialVersionUID = 5396453565371560052L;
|
||||
|
||||
/** 是否始终使用文本分隔符,文本包装符,默认false,按需添加 */
|
||||
/**
|
||||
* 是否始终使用文本分隔符,文本包装符,默认false,按需添加
|
||||
*/
|
||||
protected boolean alwaysDelimitText;
|
||||
/** 换行符 */
|
||||
/**
|
||||
* 换行符
|
||||
*/
|
||||
protected char[] lineDelimiter = {CharUtil.CR, CharUtil.LF};
|
||||
|
||||
/**
|
||||
@@ -31,17 +34,21 @@ public class CsvWriteConfig extends CsvConfig implements Serializable {
|
||||
* 设置是否始终使用文本分隔符,文本包装符,默认false,按需添加
|
||||
*
|
||||
* @param alwaysDelimitText 是否始终使用文本分隔符,文本包装符,默认false,按需添加
|
||||
* @return this
|
||||
*/
|
||||
public void setAlwaysDelimitText(boolean alwaysDelimitText) {
|
||||
public CsvWriteConfig setAlwaysDelimitText(boolean alwaysDelimitText) {
|
||||
this.alwaysDelimitText = alwaysDelimitText;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置换行符
|
||||
*
|
||||
* @param lineDelimiter 换行符
|
||||
* @return this
|
||||
*/
|
||||
public void setLineDelimiter(char[] lineDelimiter) {
|
||||
public CsvWriteConfig setLineDelimiter(char[] lineDelimiter) {
|
||||
this.lineDelimiter = lineDelimiter;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* 线程池工具
|
||||
@@ -366,6 +367,19 @@ public class ThreadUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建本地线程对象
|
||||
*
|
||||
* @param <T> 持有对象类型
|
||||
* @param supplier 初始化线程对象函数
|
||||
* @return 本地线程
|
||||
* @see ThreadLocal#withInitial(Supplier)
|
||||
* @since 5.6.7
|
||||
*/
|
||||
public static <T> ThreadLocal<T> createThreadLocal(Supplier<? extends T> supplier) {
|
||||
return ThreadLocal.withInitial(supplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建ThreadFactoryBuilder
|
||||
*
|
||||
@@ -562,20 +576,19 @@ public class ThreadUtil {
|
||||
* <li>fixedDelay模式:下一次任务不等待上一次任务,到周期自动执行。</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* @param executor 定时任务线程池,{@code null}新建一个默认线程池
|
||||
* @param command 需要定时执行的逻辑
|
||||
* @param initialDelay 初始延迟,单位毫秒
|
||||
* @param period 执行周期,单位毫秒
|
||||
* @param executor 定时任务线程池,{@code null}新建一个默认线程池
|
||||
* @param command 需要定时执行的逻辑
|
||||
* @param initialDelay 初始延迟,单位毫秒
|
||||
* @param period 执行周期,单位毫秒
|
||||
* @param fixedRateOrFixedDelay {@code true}表示fixedRate模式,{@code false}表示fixedDelay模式
|
||||
* @return {@link ScheduledThreadPoolExecutor}
|
||||
* @since 5.5.8
|
||||
*/
|
||||
public static ScheduledThreadPoolExecutor schedule(ScheduledThreadPoolExecutor executor,
|
||||
Runnable command,
|
||||
long initialDelay,
|
||||
long period,
|
||||
boolean fixedRateOrFixedDelay){
|
||||
Runnable command,
|
||||
long initialDelay,
|
||||
long period,
|
||||
boolean fixedRateOrFixedDelay) {
|
||||
return schedule(executor, command, initialDelay, period, TimeUnit.MILLISECONDS, fixedRateOrFixedDelay);
|
||||
}
|
||||
|
||||
@@ -587,12 +600,11 @@ public class ThreadUtil {
|
||||
* <li>fixedDelay模式:下一次任务不等待上一次任务,到周期自动执行。</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* @param executor 定时任务线程池,{@code null}新建一个默认线程池
|
||||
* @param command 需要定时执行的逻辑
|
||||
* @param initialDelay 初始延迟
|
||||
* @param period 执行周期
|
||||
* @param timeUnit 时间单位
|
||||
* @param executor 定时任务线程池,{@code null}新建一个默认线程池
|
||||
* @param command 需要定时执行的逻辑
|
||||
* @param initialDelay 初始延迟
|
||||
* @param period 执行周期
|
||||
* @param timeUnit 时间单位
|
||||
* @param fixedRateOrFixedDelay {@code true}表示fixedRate模式,{@code false}表示fixedDelay模式
|
||||
* @return {@link ScheduledThreadPoolExecutor}
|
||||
* @since 5.6.5
|
||||
@@ -602,13 +614,13 @@ public class ThreadUtil {
|
||||
long initialDelay,
|
||||
long period,
|
||||
TimeUnit timeUnit,
|
||||
boolean fixedRateOrFixedDelay){
|
||||
if(null == executor){
|
||||
boolean fixedRateOrFixedDelay) {
|
||||
if (null == executor) {
|
||||
executor = createScheduledExecutor(2);
|
||||
}
|
||||
if(fixedRateOrFixedDelay){
|
||||
if (fixedRateOrFixedDelay) {
|
||||
executor.scheduleAtFixedRate(command, initialDelay, period, timeUnit);
|
||||
} else{
|
||||
} else {
|
||||
executor.scheduleWithFixedDelay(command, initialDelay, period, timeUnit);
|
||||
}
|
||||
|
||||
|
@@ -1203,31 +1203,6 @@ public class ArrayUtil extends PrimitiveArrayUtil {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 以 conjunction 为分隔符将数组转换为字符串
|
||||
*
|
||||
* @param array 数组
|
||||
* @param conjunction 分隔符
|
||||
* @return 连接后的字符串
|
||||
*/
|
||||
public static String join(long[] array, CharSequence conjunction) {
|
||||
if (null == array) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
boolean isFirst = true;
|
||||
for (long item : array) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
sb.append(conjunction);
|
||||
}
|
||||
sb.append(item);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 以 conjunction 为分隔符将数组转换为字符串
|
||||
*
|
||||
|
@@ -387,7 +387,6 @@ public class IdcardUtil {
|
||||
|
||||
// 首字母A-Z,A表示1,以此类推
|
||||
char start = idcard.charAt(0);
|
||||
int iStart = start - 'A' + 1;
|
||||
String mid = card.substring(1, 7);
|
||||
String end = card.substring(7, 8);
|
||||
char[] chars = mid.toCharArray();
|
||||
|
@@ -356,11 +356,11 @@ public class ObjectUtil {
|
||||
* 如果给定对象为{@code null}或者""或者空白符返回默认值
|
||||
*
|
||||
* <pre>
|
||||
* ObjectUtil.defaultIfEmpty(null, null) = null
|
||||
* ObjectUtil.defaultIfEmpty(null, "") = ""
|
||||
* ObjectUtil.defaultIfEmpty("", "zz") = "zz"
|
||||
* ObjectUtil.defaultIfEmpty(" ", "zz") = "zz"
|
||||
* ObjectUtil.defaultIfEmpty("abc", *) = "abc"
|
||||
* ObjectUtil.defaultIfBlank(null, null) = null
|
||||
* ObjectUtil.defaultIfBlank(null, "") = ""
|
||||
* ObjectUtil.defaultIfBlank("", "zz") = "zz"
|
||||
* ObjectUtil.defaultIfBlank(" ", "zz") = "zz"
|
||||
* ObjectUtil.defaultIfBlank("abc", *) = "abc"
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> 对象类型(必须实现CharSequence接口)
|
||||
|
@@ -1613,6 +1613,31 @@ public class PrimitiveArrayUtil {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 以 conjunction 为分隔符将数组转换为字符串
|
||||
*
|
||||
* @param array 数组
|
||||
* @param conjunction 分隔符
|
||||
* @return 连接后的字符串
|
||||
*/
|
||||
public static String join(long[] array, CharSequence conjunction) {
|
||||
if (null == array) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
boolean isFirst = true;
|
||||
for (long item : array) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
sb.append(conjunction);
|
||||
}
|
||||
sb.append(item);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 以 conjunction 为分隔符将数组转换为字符串
|
||||
*
|
||||
@@ -2038,7 +2063,6 @@ public class PrimitiveArrayUtil {
|
||||
}
|
||||
int i = Math.max(startIndexInclusive, 0);
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
long tmp;
|
||||
while (j > i) {
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
@@ -2073,7 +2097,6 @@ public class PrimitiveArrayUtil {
|
||||
}
|
||||
int i = Math.max(startIndexInclusive, 0);
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
int tmp;
|
||||
while (j > i) {
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
@@ -2108,7 +2131,6 @@ public class PrimitiveArrayUtil {
|
||||
}
|
||||
int i = Math.max(startIndexInclusive, 0);
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
short tmp;
|
||||
while (j > i) {
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
@@ -2143,7 +2165,6 @@ public class PrimitiveArrayUtil {
|
||||
}
|
||||
int i = Math.max(startIndexInclusive, 0);
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
char tmp;
|
||||
while (j > i) {
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
@@ -2178,7 +2199,6 @@ public class PrimitiveArrayUtil {
|
||||
}
|
||||
int i = Math.max(startIndexInclusive, 0);
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
byte tmp;
|
||||
while (j > i) {
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
@@ -2213,7 +2233,6 @@ public class PrimitiveArrayUtil {
|
||||
}
|
||||
int i = Math.max(startIndexInclusive, 0);
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
double tmp;
|
||||
while (j > i) {
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
@@ -2248,7 +2267,6 @@ public class PrimitiveArrayUtil {
|
||||
}
|
||||
int i = Math.max(startIndexInclusive, 0);
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
float tmp;
|
||||
while (j > i) {
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
@@ -2283,7 +2301,6 @@ public class PrimitiveArrayUtil {
|
||||
}
|
||||
int i = Math.max(startIndexInclusive, 0);
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
boolean tmp;
|
||||
while (j > i) {
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
|
@@ -54,8 +54,7 @@ public class RadixUtil {
|
||||
public static String encode(final String radixs, final int num) {
|
||||
//考虑到负数问题
|
||||
long tmpNum = (num >= 0 ? num : (0x100000000L - (~num + 1)));
|
||||
|
||||
return encode(radixs, num, 32);
|
||||
return encode(radixs, tmpNum, 32);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,7 +72,7 @@ public class RadixUtil {
|
||||
return encode(radixs, num, 64);
|
||||
}
|
||||
|
||||
private static String encode(final String radixs, final long num, int maxLength) {
|
||||
private static String encode(final String radixs, long num, int maxLength) {
|
||||
if (radixs.length() < 2) {
|
||||
throw new RuntimeException("自定义进制最少两个字符哦!");
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package cn.hutool.core.util;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.text.StrBuilder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -9,6 +10,7 @@ import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* 系统运行时工具类,用于执行系统命令的工具
|
||||
@@ -74,22 +76,9 @@ public class RuntimeUtil {
|
||||
* @return {@link Process}
|
||||
*/
|
||||
public static Process exec(String... cmds) {
|
||||
if (ArrayUtil.isEmpty(cmds)) {
|
||||
throw new NullPointerException("Command is empty !");
|
||||
}
|
||||
|
||||
// 单条命令的情况
|
||||
if (1 == cmds.length) {
|
||||
final String cmd = cmds[0];
|
||||
if (StrUtil.isBlank(cmd)) {
|
||||
throw new NullPointerException("Command is empty !");
|
||||
}
|
||||
cmds = StrUtil.splitToArray(cmd, StrUtil.C_SPACE);
|
||||
}
|
||||
|
||||
Process process;
|
||||
try {
|
||||
process = new ProcessBuilder(cmds).redirectErrorStream(true).start();
|
||||
process = new ProcessBuilder(handleCmds(cmds)).redirectErrorStream(true).start();
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
@@ -120,20 +109,8 @@ public class RuntimeUtil {
|
||||
* @since 4.1.6
|
||||
*/
|
||||
public static Process exec(String[] envp, File dir, String... cmds) {
|
||||
if (ArrayUtil.isEmpty(cmds)) {
|
||||
throw new NullPointerException("Command is empty !");
|
||||
}
|
||||
|
||||
// 单条命令的情况
|
||||
if (1 == cmds.length) {
|
||||
final String cmd = cmds[0];
|
||||
if (StrUtil.isBlank(cmd)) {
|
||||
throw new NullPointerException("Command is empty !");
|
||||
}
|
||||
cmds = StrUtil.splitToArray(cmd, StrUtil.C_SPACE);
|
||||
}
|
||||
try {
|
||||
return Runtime.getRuntime().exec(cmds, envp, dir);
|
||||
return Runtime.getRuntime().exec(handleCmds(cmds), envp, dir);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
@@ -301,4 +278,80 @@ public class RuntimeUtil {
|
||||
public static long getUsableMemory() {
|
||||
return getMaxMemory() - getTotalMemory() + getFreeMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理命令,多行命令原样返回,单行命令拆分处理
|
||||
* @param cmds 命令
|
||||
* @return 处理后的命令
|
||||
*/
|
||||
private static String[] handleCmds(String... cmds){
|
||||
if (ArrayUtil.isEmpty(cmds)) {
|
||||
throw new NullPointerException("Command is empty !");
|
||||
}
|
||||
|
||||
// 单条命令的情况
|
||||
if (1 == cmds.length) {
|
||||
final String cmd = cmds[0];
|
||||
if (StrUtil.isBlank(cmd)) {
|
||||
throw new NullPointerException("Command is blank !");
|
||||
}
|
||||
cmds = cmdSplit(cmd);
|
||||
}
|
||||
return cmds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 命令分割,使用空格分割,考虑双引号和单引号的情况
|
||||
*
|
||||
* @param cmd 命令,如 git commit -m 'test commit'
|
||||
* @return 分割后的命令
|
||||
*/
|
||||
private static String[] cmdSplit(String cmd){
|
||||
final List<String> cmds = new ArrayList<>();
|
||||
|
||||
final int length = cmd.length();
|
||||
final Stack<Character> stack = new Stack<>();
|
||||
boolean inWrap = false;
|
||||
final StrBuilder cache = StrUtil.strBuilder();
|
||||
|
||||
char c;
|
||||
for (int i = 0; i < length; i++) {
|
||||
c = cmd.charAt(i);
|
||||
switch (c){
|
||||
case CharUtil.SINGLE_QUOTE:
|
||||
case CharUtil.DOUBLE_QUOTES:
|
||||
if(inWrap){
|
||||
if(c == stack.peek()){
|
||||
//结束包装
|
||||
stack.pop();
|
||||
inWrap = false;
|
||||
}
|
||||
cache.append(c);
|
||||
} else{
|
||||
stack.push(c);
|
||||
cache.append(c);
|
||||
inWrap = true;
|
||||
}
|
||||
break;
|
||||
case CharUtil.SPACE:
|
||||
if(inWrap){
|
||||
// 处于包装内
|
||||
cache.append(c);
|
||||
} else{
|
||||
cmds.add(cache.toString());
|
||||
cache.reset();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cache.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(cache.hasContent()){
|
||||
cmds.add(cache.toString());
|
||||
}
|
||||
|
||||
return cmds.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
|
@@ -1508,7 +1508,7 @@ public class XmlUtil {
|
||||
*/
|
||||
@Override
|
||||
public String getNamespaceURI(String prefix) {
|
||||
if (prefix == null || prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
|
||||
if (prefix == null || XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
|
||||
return prefixUri.get(DEFAULT_NS);
|
||||
} else {
|
||||
return prefixUri.get(prefix);
|
||||
|
@@ -660,7 +660,6 @@ public class ZipUtil {
|
||||
public static void read(ZipInputStream zipStream, Consumer<ZipEntry> consumer) {
|
||||
try {
|
||||
ZipEntry zipEntry;
|
||||
File outItemFile;
|
||||
while (null != (zipEntry = zipStream.getNextEntry())) {
|
||||
consumer.accept(zipEntry);
|
||||
}
|
||||
|
@@ -164,7 +164,7 @@ public class BeanUtilTest {
|
||||
public void mapToBeanWinErrorTest() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("age", "哈哈");
|
||||
Person user = BeanUtil.toBean(map, Person.class);
|
||||
BeanUtil.toBean(map, Person.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -559,7 +559,6 @@ public class BeanUtilTest {
|
||||
@Test
|
||||
public void toMapTest() {
|
||||
// 测试转map的时候返回key
|
||||
String name = null;
|
||||
PrivilegeIClassification a = new PrivilegeIClassification();
|
||||
a.setId("1");
|
||||
a.setName("2");
|
||||
|
@@ -23,6 +23,16 @@ public class Base64Test {
|
||||
Assert.assertEquals(a, decodeStr);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeAndDecodeWithoutPaddingTest() {
|
||||
String a = "伦家是一个非常长的字符串66";
|
||||
String encode = Base64.encodeWithoutPadding(StrUtil.utf8Bytes(a));
|
||||
Assert.assertEquals("5Lym5a625piv5LiA5Liq6Z2e5bi46ZW/55qE5a2X56ym5LiyNjY", encode);
|
||||
|
||||
String decodeStr = Base64.decodeStr(encode);
|
||||
Assert.assertEquals(a, decodeStr);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeAndDecodeTest2() {
|
||||
String a = "a61a5db5a67c01445ca2-HZ20181120172058/pdf/中国电信影像云单体网关Docker版-V1.2.pdf";
|
||||
|
@@ -102,7 +102,7 @@ public class CollUtilTest {
|
||||
|
||||
Collection<String> union = CollUtil.union(list1, list2);
|
||||
|
||||
Assert.assertEquals(3, CollUtil.count(union, t -> t.equals("b")));
|
||||
Assert.assertEquals(3, CollUtil.count(union, t -> "b".equals(t)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -111,7 +111,7 @@ public class CollUtilTest {
|
||||
ArrayList<String> list2 = CollUtil.newArrayList("a", "b", "b", "b", "c", "d");
|
||||
|
||||
Collection<String> intersection = CollUtil.intersection(list1, list2);
|
||||
Assert.assertEquals(2, CollUtil.count(intersection, t -> t.equals("b")));
|
||||
Assert.assertEquals(2, CollUtil.count(intersection, t -> "b".equals(t)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -236,7 +236,7 @@ public class CollUtilTest {
|
||||
|
||||
final String[] result = new String[1];
|
||||
CollUtil.forEach(map, (key, value, index) -> {
|
||||
if (key.equals("a")) {
|
||||
if ("a".equals(key)) {
|
||||
result[0] = value;
|
||||
}
|
||||
});
|
||||
|
@@ -3,7 +3,6 @@ package cn.hutool.core.date;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.BetweenFormatter.Level;
|
||||
import cn.hutool.core.date.format.FastDateFormat;
|
||||
import cn.hutool.core.lang.Console;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
@@ -13,6 +13,8 @@ import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
public class ImgUtilTest {
|
||||
|
||||
@@ -136,4 +138,11 @@ public class ImgUtilTest {
|
||||
new File("d:/test/3.jpg"),
|
||||
new Color(200, 0, 0), 10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMainColor() throws MalformedURLException {
|
||||
BufferedImage read = ImgUtil.read(new URL("https://pic2.zhimg.com/v2-94f5552f2b142ff575306850c5bab65d_b.png"));
|
||||
String mainColor = ImgUtil.getMainColor(read, new int[]{64,84,116});
|
||||
System.out.println(mainColor);
|
||||
}
|
||||
}
|
||||
|
@@ -18,8 +18,8 @@ public class TreeTest {
|
||||
static {
|
||||
// 模拟数据
|
||||
nodeList.add(new TreeNode<>("1", "0", "系统管理", 5));
|
||||
nodeList.add(new TreeNode<>("11", "1", "用户管理", 222222));
|
||||
nodeList.add(new TreeNode<>("111", "11", "用户添加", 0));
|
||||
nodeList.add(new TreeNode<>("11", "1", "用户管理", 222222));
|
||||
|
||||
nodeList.add(new TreeNode<>("2", "0", "店铺管理", 1));
|
||||
nodeList.add(new TreeNode<>("21", "2", "商品管理", 44));
|
||||
@@ -33,6 +33,7 @@ public class TreeTest {
|
||||
for (Tree<String> tree : treeList) {
|
||||
Assert.assertNotNull(tree);
|
||||
Assert.assertEquals("0", tree.getParentId());
|
||||
// Console.log(tree);
|
||||
}
|
||||
|
||||
// 测试通过子节点查找父节点
|
||||
|
@@ -0,0 +1,16 @@
|
||||
package cn.hutool.core.stream;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class StreamUtilTest {
|
||||
|
||||
@Test
|
||||
public void ofTest(){
|
||||
final Stream<Integer> stream = StreamUtil.of(2, x -> x * 2, 4);
|
||||
final String result = stream.collect(CollectorUtil.joining(","));
|
||||
Assert.assertEquals("2,4,8,16", result);
|
||||
}
|
||||
}
|
@@ -85,4 +85,16 @@ public class CsvReaderTest {
|
||||
Console.log(strings);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void readTest3(){
|
||||
final CsvReadConfig csvReadConfig = CsvReadConfig.defaultConfig();
|
||||
csvReadConfig.setContainsHeader(true);
|
||||
final CsvReader reader = CsvUtil.getReader(csvReadConfig);
|
||||
final CsvData read = reader.read(FileUtil.file("d:/test/ceshi.csv"));
|
||||
for (CsvRow row : read) {
|
||||
Console.log(row.getByName("案件ID"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ public class RuntimeUtilTest {
|
||||
@Test
|
||||
@Ignore
|
||||
public void execCmdTest2() {
|
||||
String str = RuntimeUtil.execForStr("cmd /c cd C:\\Program Files (x86)");
|
||||
String str = RuntimeUtil.execForStr("cmd /c", "cd \"C:\\Program Files (x86)\"", "chdir");
|
||||
Console.log(str);
|
||||
}
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-cron</artifactId>
|
||||
|
@@ -47,7 +47,6 @@ public class TaskListenerManager implements Serializable {
|
||||
*/
|
||||
public void notifyTaskStart(TaskExecutor executor) {
|
||||
synchronized (listeners) {
|
||||
int size = listeners.size();
|
||||
TaskListener listener;
|
||||
for (TaskListener taskListener : listeners) {
|
||||
listener = taskListener;
|
||||
@@ -64,7 +63,6 @@ public class TaskListenerManager implements Serializable {
|
||||
*/
|
||||
public void notifyTaskSucceeded(TaskExecutor executor) {
|
||||
synchronized (listeners) {
|
||||
int size = listeners.size();
|
||||
for (TaskListener listener : listeners) {
|
||||
listener.onSucceeded(executor);
|
||||
}
|
||||
|
@@ -76,7 +76,7 @@ public class TimerTaskList implements Delayed {
|
||||
*/
|
||||
public void removeTask(TimerTask timerTask) {
|
||||
synchronized (this) {
|
||||
if (timerTask.timerTaskList.equals(this)) {
|
||||
if (this.equals(timerTask.timerTaskList)) {
|
||||
timerTask.next.prev = timerTask.prev;
|
||||
timerTask.prev.next = timerTask.next;
|
||||
timerTask.timerTaskList = null;
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
|
@@ -247,7 +247,7 @@ public class SymmetricCrypto implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密,针对大数据量,结束后不关闭流
|
||||
* 加密,针对大数据量,可选结束后是否关闭流
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param out 输出流,可以是文件或网络位置
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-db</artifactId>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-dfa</artifactId>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-extra</artifactId>
|
||||
|
@@ -42,10 +42,11 @@ public enum BeanCopierCache {
|
||||
* @return 属性名和Map映射的key
|
||||
*/
|
||||
private String genKey(Class<?> srcClass, Class<?> targetClass, Converter converter) {
|
||||
String key = StrUtil.format("{}#{}", srcClass.getName(), targetClass.getName());
|
||||
final StringBuilder key = StrUtil.builder()
|
||||
.append(srcClass.getName()).append('#').append(targetClass.getName());
|
||||
if(null != converter){
|
||||
key += "#" + converter.getClass().getName();
|
||||
key.append('#').append(converter.getClass().getName());
|
||||
}
|
||||
return key;
|
||||
return key.toString();
|
||||
}
|
||||
}
|
||||
|
@@ -339,7 +339,7 @@ public class Sftp extends AbstractFtp {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
channel.cd(directory.replaceAll("\\\\", "/"));
|
||||
channel.cd(directory.replace('\\', '/'));
|
||||
return true;
|
||||
} catch (SftpException e) {
|
||||
throw new FtpException(e);
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-http</artifactId>
|
||||
|
@@ -387,7 +387,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
public boolean isKeepAlive() {
|
||||
String connection = header(Header.CONNECTION);
|
||||
if (connection == null) {
|
||||
return !httpVersion.equalsIgnoreCase(HTTP_1_0);
|
||||
return !HTTP_1_0.equalsIgnoreCase(httpVersion);
|
||||
}
|
||||
|
||||
return false == "close".equalsIgnoreCase(connection);
|
||||
@@ -552,7 +552,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置map<String, String>类型表单数据
|
||||
* 设置map<String, String>类型表单数据
|
||||
*
|
||||
* @param formMapStr 表单内容
|
||||
* @return this
|
||||
|
@@ -109,7 +109,7 @@ public class Platform extends UserAgentInfo {
|
||||
* @since 5.2.3
|
||||
*/
|
||||
public boolean isIPhoneOrIPod() {
|
||||
return IPHONE.equals(this) || IPOD.equals(this);
|
||||
return this.equals(IPHONE) || this.equals(IPOD);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +119,7 @@ public class Platform extends UserAgentInfo {
|
||||
* @since 5.2.3
|
||||
*/
|
||||
public boolean isIPad() {
|
||||
return IPAD.equals(this);
|
||||
return this.equals(IPAD);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,7 +139,7 @@ public class Platform extends UserAgentInfo {
|
||||
* @since 5.2.3
|
||||
*/
|
||||
public boolean isAndroid() {
|
||||
return ANDROID.equals(this) || GOOGLE_TV.equals(this);
|
||||
return this.equals(ANDROID) || this.equals(GOOGLE_TV);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-json</artifactId>
|
||||
|
@@ -675,14 +675,12 @@ public class JSONUtil {
|
||||
return writer;
|
||||
}
|
||||
|
||||
char b; // 前一个字符
|
||||
char c; // 当前字符
|
||||
int len = str.length();
|
||||
if (isWrap) {
|
||||
writer.write('"');
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
// b = c;
|
||||
c = str.charAt(i);
|
||||
switch (c) {
|
||||
case '\\':
|
||||
@@ -690,13 +688,6 @@ public class JSONUtil {
|
||||
writer.write("\\");
|
||||
writer.write(c);
|
||||
break;
|
||||
//此处转义导致输出不和预期一致
|
||||
// case '/':
|
||||
// if (b == '<') {
|
||||
// writer.write('\\');
|
||||
// }
|
||||
// writer.write(c);
|
||||
// break;
|
||||
default:
|
||||
writer.write(escape(c));
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-log</artifactId>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-poi</artifactId>
|
||||
|
@@ -21,16 +21,26 @@ import java.io.InputStream;
|
||||
* Excel工具类,不建议直接使用index直接操作sheet,在wps/excel中sheet显示顺序与index无关,还有隐藏sheet
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class ExcelUtil {
|
||||
|
||||
/**
|
||||
* xlx的ContentType
|
||||
*/
|
||||
public static final String XLS_CONTENT_TYPE = "application/vnd.ms-excel";
|
||||
|
||||
/**
|
||||
* xlsx的ContentType
|
||||
*/
|
||||
public static final String XLSX_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
|
||||
// ------------------------------------------------------------------------------------ Read by Sax start
|
||||
|
||||
/**
|
||||
* 通过Sax方式读取Excel,同时支持03和07格式
|
||||
*
|
||||
* @param path Excel文件路径
|
||||
* @param rid sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param path Excel文件路径
|
||||
* @param rid sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @since 3.2.0
|
||||
*/
|
||||
@@ -41,8 +51,8 @@ public class ExcelUtil {
|
||||
/**
|
||||
* 通过Sax方式读取Excel,同时支持03和07格式
|
||||
*
|
||||
* @param path Excel文件路径
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @param path Excel文件路径
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @since 5.4.4
|
||||
*/
|
||||
@@ -53,8 +63,8 @@ public class ExcelUtil {
|
||||
/**
|
||||
* 通过Sax方式读取Excel,同时支持03和07格式
|
||||
*
|
||||
* @param file Excel文件
|
||||
* @param rid sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param file Excel文件
|
||||
* @param rid sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @since 3.2.0
|
||||
*/
|
||||
@@ -66,8 +76,8 @@ public class ExcelUtil {
|
||||
/**
|
||||
* 通过Sax方式读取Excel,同时支持03和07格式
|
||||
*
|
||||
* @param file Excel文件
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @param file Excel文件
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @since 5.4.4
|
||||
*/
|
||||
@@ -79,8 +89,8 @@ public class ExcelUtil {
|
||||
/**
|
||||
* 通过Sax方式读取Excel,同时支持03和07格式
|
||||
*
|
||||
* @param in Excel流
|
||||
* @param rid sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param in Excel流
|
||||
* @param rid sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @since 3.2.0
|
||||
*/
|
||||
@@ -93,8 +103,8 @@ public class ExcelUtil {
|
||||
/**
|
||||
* 通过Sax方式读取Excel,同时支持03和07格式
|
||||
*
|
||||
* @param in Excel流
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @param in Excel流
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @since 5.4.4
|
||||
*/
|
||||
@@ -107,8 +117,8 @@ public class ExcelUtil {
|
||||
/**
|
||||
* Sax方式读取Excel07
|
||||
*
|
||||
* @param in 输入流
|
||||
* @param rid Sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param in 输入流
|
||||
* @param rid Sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link Excel07SaxReader}
|
||||
* @since 3.2.0
|
||||
@@ -126,8 +136,8 @@ public class ExcelUtil {
|
||||
/**
|
||||
* Sax方式读取Excel07
|
||||
*
|
||||
* @param file 文件
|
||||
* @param rid Sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param file 文件
|
||||
* @param rid Sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link Excel07SaxReader}
|
||||
* @since 3.2.0
|
||||
@@ -145,8 +155,8 @@ public class ExcelUtil {
|
||||
/**
|
||||
* Sax方式读取Excel07
|
||||
*
|
||||
* @param path 路径
|
||||
* @param rid Sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param path 路径
|
||||
* @param rid Sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link Excel07SaxReader}
|
||||
* @since 3.2.0
|
||||
@@ -164,7 +174,7 @@ public class ExcelUtil {
|
||||
/**
|
||||
* Sax方式读取Excel03
|
||||
*
|
||||
* @param in 输入流
|
||||
* @param in 输入流
|
||||
* @param sheetIndex Sheet索引,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link Excel03SaxReader}
|
||||
@@ -183,7 +193,7 @@ public class ExcelUtil {
|
||||
/**
|
||||
* Sax方式读取Excel03
|
||||
*
|
||||
* @param file 文件
|
||||
* @param file 文件
|
||||
* @param sheetIndex Sheet索引,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link Excel03SaxReader}
|
||||
@@ -202,7 +212,7 @@ public class ExcelUtil {
|
||||
/**
|
||||
* Sax方式读取Excel03
|
||||
*
|
||||
* @param path 路径
|
||||
* @param path 路径
|
||||
* @param sheetIndex Sheet索引,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link Excel03SaxReader}
|
||||
@@ -220,6 +230,7 @@ public class ExcelUtil {
|
||||
// ------------------------------------------------------------------------------------ Read by Sax end
|
||||
|
||||
// ------------------------------------------------------------------------------------------------ getReader
|
||||
|
||||
/**
|
||||
* 获取Excel读取器,通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容<br>
|
||||
* 默认调用第一个sheet
|
||||
@@ -247,7 +258,7 @@ public class ExcelUtil {
|
||||
* 获取Excel读取器,通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容
|
||||
*
|
||||
* @param bookFilePath Excel文件路径,绝对路径或相对于ClassPath路径
|
||||
* @param sheetIndex sheet序号,0表示第一个sheet
|
||||
* @param sheetIndex sheet序号,0表示第一个sheet
|
||||
* @return {@link ExcelReader}
|
||||
* @since 3.1.1
|
||||
*/
|
||||
@@ -262,7 +273,7 @@ public class ExcelUtil {
|
||||
/**
|
||||
* 获取Excel读取器,通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容
|
||||
*
|
||||
* @param bookFile Excel文件
|
||||
* @param bookFile Excel文件
|
||||
* @param sheetIndex sheet序号,0表示第一个sheet
|
||||
* @return {@link ExcelReader}
|
||||
*/
|
||||
@@ -277,7 +288,7 @@ public class ExcelUtil {
|
||||
/**
|
||||
* 获取Excel读取器,通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容
|
||||
*
|
||||
* @param bookFile Excel文件
|
||||
* @param bookFile Excel文件
|
||||
* @param sheetName sheet名,第一个默认是sheet1
|
||||
* @return {@link ExcelReader}
|
||||
*/
|
||||
@@ -304,7 +315,7 @@ public class ExcelUtil {
|
||||
* 获取Excel读取器,通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容<br>
|
||||
* 默认调用第一个sheet
|
||||
*
|
||||
* @param bookStream Excel文件的流
|
||||
* @param bookStream Excel文件的流
|
||||
* @param closeAfterRead 读取结束是否关闭流
|
||||
* @return {@link ExcelReader}
|
||||
* @since 4.0.3
|
||||
@@ -336,8 +347,8 @@ public class ExcelUtil {
|
||||
/**
|
||||
* 获取Excel读取器,通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容
|
||||
*
|
||||
* @param bookStream Excel文件的流
|
||||
* @param sheetIndex sheet序号,0表示第一个sheet
|
||||
* @param bookStream Excel文件的流
|
||||
* @param sheetIndex sheet序号,0表示第一个sheet
|
||||
* @param closeAfterRead 读取结束是否关闭流
|
||||
* @return {@link ExcelReader}
|
||||
* @since 4.0.3
|
||||
@@ -357,7 +368,7 @@ public class ExcelUtil {
|
||||
* 读取结束自动关闭流
|
||||
*
|
||||
* @param bookStream Excel文件的流
|
||||
* @param sheetName sheet名,第一个默认是sheet1
|
||||
* @param sheetName sheet名,第一个默认是sheet1
|
||||
* @return {@link ExcelReader}
|
||||
*/
|
||||
public static ExcelReader getReader(InputStream bookStream, String sheetName) {
|
||||
@@ -371,8 +382,8 @@ public class ExcelUtil {
|
||||
/**
|
||||
* 获取Excel读取器,通过调用{@link ExcelReader}的read或readXXX方法读取Excel内容
|
||||
*
|
||||
* @param bookStream Excel文件的流
|
||||
* @param sheetName sheet名,第一个默认是sheet1
|
||||
* @param bookStream Excel文件的流
|
||||
* @param sheetName sheet名,第一个默认是sheet1
|
||||
* @param closeAfterRead 读取结束是否关闭流
|
||||
* @return {@link ExcelReader}
|
||||
* @deprecated 使用完毕无论是否closeAfterRead,poi会关闭流,此参数无意义。
|
||||
@@ -387,6 +398,7 @@ public class ExcelUtil {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------ getWriter
|
||||
|
||||
/**
|
||||
* 获得{@link ExcelWriter},默认写出到第一个sheet<br>
|
||||
* 不传入写出的Excel文件路径,只能调用ExcelWriter#flush(OutputStream)方法写出到流<br>
|
||||
@@ -443,7 +455,7 @@ public class ExcelUtil {
|
||||
*/
|
||||
public static ExcelWriter getWriterWithSheet(String sheetName) {
|
||||
try {
|
||||
return new ExcelWriter((File)null, sheetName);
|
||||
return new ExcelWriter((File) null, sheetName);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
throw new DependencyException(ObjectUtil.defaultIfNull(e.getCause(), e), PoiChecker.NO_POI_ERROR_MSG);
|
||||
}
|
||||
@@ -467,7 +479,7 @@ public class ExcelUtil {
|
||||
* 获得{@link ExcelWriter}
|
||||
*
|
||||
* @param destFilePath 目标文件路径
|
||||
* @param sheetName sheet表名
|
||||
* @param sheetName sheet表名
|
||||
* @return {@link ExcelWriter}
|
||||
*/
|
||||
public static ExcelWriter getWriter(String destFilePath, String sheetName) {
|
||||
@@ -481,7 +493,7 @@ public class ExcelUtil {
|
||||
/**
|
||||
* 获得{@link ExcelWriter}
|
||||
*
|
||||
* @param destFile 目标文件
|
||||
* @param destFile 目标文件
|
||||
* @param sheetName sheet表名
|
||||
* @return {@link ExcelWriter}
|
||||
*/
|
||||
@@ -494,6 +506,7 @@ public class ExcelUtil {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------ getBigWriter
|
||||
|
||||
/**
|
||||
* 获得{@link BigExcelWriter},默认写出到第一个sheet<br>
|
||||
* 不传入写出的Excel文件路径,只能调用ExcelWriter#flush(OutputStream)方法写出到流<br>
|
||||
@@ -559,7 +572,7 @@ public class ExcelUtil {
|
||||
* 获得{@link BigExcelWriter}
|
||||
*
|
||||
* @param destFilePath 目标文件路径
|
||||
* @param sheetName sheet表名
|
||||
* @param sheetName sheet表名
|
||||
* @return {@link BigExcelWriter}
|
||||
*/
|
||||
public static BigExcelWriter getBigWriter(String destFilePath, String sheetName) {
|
||||
@@ -573,7 +586,7 @@ public class ExcelUtil {
|
||||
/**
|
||||
* 获得{@link BigExcelWriter}
|
||||
*
|
||||
* @param destFile 目标文件
|
||||
* @param destFile 目标文件
|
||||
* @param sheetName sheet表名
|
||||
* @return {@link BigExcelWriter}
|
||||
*/
|
||||
@@ -637,9 +650,9 @@ public class ExcelUtil {
|
||||
* @return 坐标点,x表示行,从0开始,y表示列,从0开始
|
||||
* @since 5.1.4
|
||||
*/
|
||||
public static CellLocation toLocation(String locationRef){
|
||||
public static CellLocation toLocation(String locationRef) {
|
||||
final int x = colNameToIndex(locationRef);
|
||||
final int y = ReUtil.getFirstNumber(locationRef) -1;
|
||||
final int y = ReUtil.getFirstNumber(locationRef) - 1;
|
||||
return new CellLocation(x, y);
|
||||
}
|
||||
}
|
||||
|
@@ -382,6 +382,20 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
|
||||
return StrUtil.format("attachment; filename=\"{}\"; filename*={}''{}", fileName, charset.name(), fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Content-Type头对应的值,可以通过调用以下方法快速设置下载Excel的头信息:
|
||||
*
|
||||
* <pre>
|
||||
* response.setContentType(excelWriter.getContentType());
|
||||
* </pre>
|
||||
*
|
||||
* @return Content-Type值
|
||||
* @since 5.6.7
|
||||
*/
|
||||
public String getContentType() {
|
||||
return isXlsx() ? ExcelUtil.XLSX_CONTENT_TYPE : ExcelUtil.XLS_CONTENT_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前所在行
|
||||
*
|
||||
@@ -395,10 +409,11 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
|
||||
|
||||
/**
|
||||
* 定位到最后一行的后边,用于追加数据
|
||||
*
|
||||
* @return this
|
||||
* @since 5.5.0
|
||||
*/
|
||||
public ExcelWriter setCurrentRowToEnd(){
|
||||
public ExcelWriter setCurrentRowToEnd() {
|
||||
return setCurrentRow(getRowCount());
|
||||
}
|
||||
|
||||
@@ -730,12 +745,12 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
|
||||
* 合并单元格,并写入对象到单元格,使用指定的样式<br>
|
||||
* 指定样式传入null,则不使用任何样式
|
||||
*
|
||||
* @param firstRow 起始行,0开始
|
||||
* @param lastRow 结束行,0开始
|
||||
* @param firstColumn 起始列,0开始
|
||||
* @param lastColumn 结束列,0开始
|
||||
* @param content 合并单元格后的内容
|
||||
* @param cellStyle 合并后单元格使用的样式,可以为null
|
||||
* @param firstRow 起始行,0开始
|
||||
* @param lastRow 结束行,0开始
|
||||
* @param firstColumn 起始列,0开始
|
||||
* @param lastColumn 结束列,0开始
|
||||
* @param content 合并单元格后的内容
|
||||
* @param cellStyle 合并后单元格使用的样式,可以为null
|
||||
* @return this
|
||||
* @since 5.6.5
|
||||
*/
|
||||
@@ -873,14 +888,14 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
|
||||
* 样式为默认标题样式,可使用{@link #getHeadCellStyle()}方法调用后自定义默认样式
|
||||
*
|
||||
* <p>
|
||||
* 此方法的逻辑是:将一行数据写出到当前行,遇到已存在的单元格跳过,不存在的创建并赋值。
|
||||
* 此方法的逻辑是:将一行数据写出到当前行,遇到已存在的单元格跳过,不存在的创建并赋值。
|
||||
* </p>
|
||||
*
|
||||
* @param rowData 一行的数据
|
||||
* @return this
|
||||
*/
|
||||
public ExcelWriter writeSecHeadRow(Iterable<?> rowData){
|
||||
final Row row = RowUtil.getOrCreateRow(this.sheet,this.currentRow.getAndIncrement());
|
||||
public ExcelWriter writeSecHeadRow(Iterable<?> rowData) {
|
||||
final Row row = RowUtil.getOrCreateRow(this.sheet, this.currentRow.getAndIncrement());
|
||||
Iterator<?> iterator = rowData.iterator();
|
||||
//如果获取的row存在单元格,则执行复杂表头逻辑,否则直接调用writeHeadRow(Iterable<?> rowData)
|
||||
if (row.getLastCellNum() != 0) {
|
||||
@@ -1093,12 +1108,12 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
|
||||
/**
|
||||
* 设置列的默认样式
|
||||
*
|
||||
* @param x 列号,从0开始
|
||||
* @param x 列号,从0开始
|
||||
* @param style 样式
|
||||
* @return this
|
||||
* @since 5.6.4
|
||||
*/
|
||||
public ExcelWriter setColumnStyle(int x, CellStyle style){
|
||||
public ExcelWriter setColumnStyle(int x, CellStyle style) {
|
||||
this.sheet.setDefaultColumnStyle(x, style);
|
||||
return this;
|
||||
}
|
||||
|
@@ -385,7 +385,6 @@ public class Excel03SaxReader implements HSSFListener, ExcelSaxReader<Excel03Sax
|
||||
return Integer.parseInt(StrUtil.removePrefixIgnoreCase(idOrRidOrSheetName, RID_PREFIX));
|
||||
}
|
||||
|
||||
final int sheetIndex;
|
||||
try {
|
||||
return Integer.parseInt(idOrRidOrSheetName);
|
||||
} catch (NumberFormatException ignore) {
|
||||
|
@@ -247,7 +247,6 @@ public class ExcelSaxUtil {
|
||||
* @since 5.5.0
|
||||
*/
|
||||
public static Object getNumberOrDateValue(CellValueRecordInterface cell, double value, FormatTrackingHSSFListener formatListener) {
|
||||
Object result;
|
||||
if (isDateFormat(cell, formatListener)) {
|
||||
// 可能为日期格式
|
||||
return getDateValue(value);
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-script</artifactId>
|
||||
|
@@ -81,19 +81,19 @@ public class ScriptRuntimeException extends RuntimeException {
|
||||
*/
|
||||
@Override
|
||||
public String getMessage() {
|
||||
String ret = super.getMessage();
|
||||
StringBuilder ret = new StringBuilder().append(super.getMessage());
|
||||
if (fileName != null) {
|
||||
ret += (" in " + fileName);
|
||||
ret.append(" in ").append(fileName);
|
||||
if (lineNumber != -1) {
|
||||
ret += " at line number " + lineNumber;
|
||||
ret.append(" at line number ").append(lineNumber);
|
||||
}
|
||||
|
||||
if (columnNumber != -1) {
|
||||
ret += " at column number " + columnNumber;
|
||||
ret.append(" at column number ").append(columnNumber);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-setting</artifactId>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-socket</artifactId>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-system</artifactId>
|
||||
|
2
pom.xml
2
pom.xml
@@ -8,7 +8,7 @@
|
||||
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.6.7-SNAPSHOT</version>
|
||||
<version>5.6.8-SNAPSHOT</version>
|
||||
<name>hutool</name>
|
||||
<description>Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。</description>
|
||||
<url>https://github.com/looly/hutool</url>
|
||||
|
Reference in New Issue
Block a user