mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix code
This commit is contained in:
parent
470e5415f0
commit
f0fb98c584
@ -12,32 +12,21 @@
|
|||||||
|
|
||||||
package cn.hutool.core.annotation;
|
package cn.hutool.core.annotation;
|
||||||
|
|
||||||
|
import cn.hutool.core.array.ArrayUtil;
|
||||||
import cn.hutool.core.classloader.ClassLoaderUtil;
|
import cn.hutool.core.classloader.ClassLoaderUtil;
|
||||||
import cn.hutool.core.exceptions.UtilException;
|
import cn.hutool.core.exceptions.UtilException;
|
||||||
import cn.hutool.core.lang.func.LambdaInfo;
|
import cn.hutool.core.lang.func.LambdaInfo;
|
||||||
import cn.hutool.core.lang.func.LambdaUtil;
|
import cn.hutool.core.lang.func.LambdaUtil;
|
||||||
import cn.hutool.core.lang.func.SerFunction;
|
import cn.hutool.core.lang.func.SerFunction;
|
||||||
import cn.hutool.core.map.MapUtil;
|
|
||||||
import cn.hutool.core.map.WeakConcurrentMap;
|
import cn.hutool.core.map.WeakConcurrentMap;
|
||||||
import cn.hutool.core.reflect.FieldUtil;
|
import cn.hutool.core.reflect.FieldUtil;
|
||||||
import cn.hutool.core.reflect.MethodUtil;
|
import cn.hutool.core.reflect.MethodUtil;
|
||||||
import cn.hutool.core.text.CharSequenceUtil;
|
import cn.hutool.core.text.CharSequenceUtil;
|
||||||
import cn.hutool.core.text.StrUtil;
|
import cn.hutool.core.text.StrUtil;
|
||||||
import cn.hutool.core.array.ArrayUtil;
|
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.*;
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.reflect.*;
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Inherited;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.lang.reflect.AnnotatedElement;
|
|
||||||
import java.lang.reflect.InvocationHandler;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
@ -70,7 +59,7 @@ public class AnnotationUtil {
|
|||||||
* @since 6.0.0
|
* @since 6.0.0
|
||||||
*/
|
*/
|
||||||
public static Annotation[] getDeclaredAnnotations(final AnnotatedElement element) {
|
public static Annotation[] getDeclaredAnnotations(final AnnotatedElement element) {
|
||||||
return MapUtil.computeIfAbsent(DECLARED_ANNOTATIONS_CACHE, element, AnnotatedElement::getDeclaredAnnotations);
|
return DECLARED_ANNOTATIONS_CACHE.computeIfAbsent(element, AnnotatedElement::getDeclaredAnnotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,12 +12,11 @@
|
|||||||
|
|
||||||
package cn.hutool.core.annotation;
|
package cn.hutool.core.annotation;
|
||||||
|
|
||||||
|
import cn.hutool.core.array.ArrayUtil;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
|
||||||
import cn.hutool.core.map.WeakConcurrentMap;
|
import cn.hutool.core.map.WeakConcurrentMap;
|
||||||
import cn.hutool.core.reflect.MethodUtil;
|
import cn.hutool.core.reflect.MethodUtil;
|
||||||
import cn.hutool.core.text.CharSequenceUtil;
|
import cn.hutool.core.text.CharSequenceUtil;
|
||||||
import cn.hutool.core.array.ArrayUtil;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.annotation.Repeatable;
|
import java.lang.annotation.Repeatable;
|
||||||
@ -354,9 +353,7 @@ public interface RepeatableAnnotationCollector {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected List<Method> resolveRepeatableMethod(final Annotation annotation) {
|
protected List<Method> resolveRepeatableMethod(final Annotation annotation) {
|
||||||
final Object cache = MapUtil.computeIfAbsent(
|
final Object cache = repeatableMethodCache.computeIfAbsent(annotation.annotationType(), this::resolveRepeatableMethodFromType);
|
||||||
repeatableMethodCache, annotation.annotationType(), this::resolveRepeatableMethodFromType
|
|
||||||
);
|
|
||||||
return (cache == NONE) ? null : Collections.singletonList((Method)cache);
|
return (cache == NONE) ? null : Collections.singletonList((Method)cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,9 +464,7 @@ public interface RepeatableAnnotationCollector {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
protected List<Method> resolveRepeatableMethod(final Annotation annotation) {
|
protected List<Method> resolveRepeatableMethod(final Annotation annotation) {
|
||||||
final Object cache = MapUtil.computeIfAbsent(
|
final Object cache = repeatableMethodCache.computeIfAbsent(annotation.annotationType(), this::resolveRepeatableMethodFromType);
|
||||||
repeatableMethodCache, annotation.annotationType(), this::resolveRepeatableMethodFromType
|
|
||||||
);
|
|
||||||
return (cache == NONE) ? null : (List<Method>)cache;
|
return (cache == NONE) ? null : (List<Method>)cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cn.hutool.core.compress;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ZipFile} 资源包装
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class ZipFileResource implements ZipResource {
|
||||||
|
|
||||||
|
private final ZipFile zipFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param zipFile {@link ZipFile}
|
||||||
|
*/
|
||||||
|
public ZipFileResource(final ZipFile zipFile) {
|
||||||
|
this.zipFile = zipFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(final Consumer<ZipEntry> consumer, final int maxSizeDiff) {
|
||||||
|
final Enumeration<? extends ZipEntry> em = zipFile.entries();
|
||||||
|
while (em.hasMoreElements()) {
|
||||||
|
consumer.accept(ZipSecurityUtil.checkZipBomb(em.nextElement(), maxSizeDiff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream get(final String path){
|
||||||
|
final ZipFile zipFile = this.zipFile;
|
||||||
|
final ZipEntry entry = zipFile.getEntry(path);
|
||||||
|
if (null != entry) {
|
||||||
|
return ZipUtil.getStream(zipFile, entry);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream get(final ZipEntry entry) {
|
||||||
|
return ZipUtil.getStream(this.zipFile, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
IoUtil.closeQuietly(this.zipFile);
|
||||||
|
}
|
||||||
|
}
|
@ -12,18 +12,15 @@
|
|||||||
|
|
||||||
package cn.hutool.core.compress;
|
package cn.hutool.core.compress;
|
||||||
|
|
||||||
import cn.hutool.core.exceptions.ValidateException;
|
|
||||||
import cn.hutool.core.io.file.FileUtil;
|
|
||||||
import cn.hutool.core.io.IORuntimeException;
|
import cn.hutool.core.io.IORuntimeException;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.io.file.FileUtil;
|
||||||
import cn.hutool.core.text.StrUtil;
|
import cn.hutool.core.text.StrUtil;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
@ -39,10 +36,7 @@ import java.util.zip.ZipInputStream;
|
|||||||
public class ZipReader implements Closeable {
|
public class ZipReader implements Closeable {
|
||||||
|
|
||||||
// size of uncompressed zip entry shouldn't be bigger of compressed in MAX_SIZE_DIFF times
|
// size of uncompressed zip entry shouldn't be bigger of compressed in MAX_SIZE_DIFF times
|
||||||
private static final int MAX_SIZE_DIFF = 100;
|
private static final int DEFAULT_MAX_SIZE_DIFF = 100;
|
||||||
|
|
||||||
private ZipFile zipFile;
|
|
||||||
private ZipInputStream in;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建ZipReader
|
* 创建ZipReader
|
||||||
@ -52,7 +46,7 @@ public class ZipReader implements Closeable {
|
|||||||
* @return ZipReader
|
* @return ZipReader
|
||||||
*/
|
*/
|
||||||
public static ZipReader of(final File zipFile, final Charset charset) {
|
public static ZipReader of(final File zipFile, final Charset charset) {
|
||||||
return new ZipReader(zipFile, charset);
|
return new ZipReader(ZipUtil.toZipFile(zipFile, charset));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,18 +57,14 @@ public class ZipReader implements Closeable {
|
|||||||
* @return ZipReader
|
* @return ZipReader
|
||||||
*/
|
*/
|
||||||
public static ZipReader of(final InputStream in, final Charset charset) {
|
public static ZipReader of(final InputStream in, final Charset charset) {
|
||||||
return new ZipReader(in, charset);
|
return new ZipReader(new ZipInputStream(in, charset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final ZipResource resource;
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 检查ZipBomb文件差异倍数,-1表示不检查ZipBomb
|
||||||
*
|
|
||||||
* @param zipFile 读取的的Zip文件
|
|
||||||
* @param charset 编码
|
|
||||||
*/
|
*/
|
||||||
public ZipReader(final File zipFile, final Charset charset) {
|
private int maxSizeDiff = DEFAULT_MAX_SIZE_DIFF;
|
||||||
this.zipFile = ZipUtil.toZipFile(zipFile, charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
@ -82,17 +72,7 @@ public class ZipReader implements Closeable {
|
|||||||
* @param zipFile 读取的的Zip文件
|
* @param zipFile 读取的的Zip文件
|
||||||
*/
|
*/
|
||||||
public ZipReader(final ZipFile zipFile) {
|
public ZipReader(final ZipFile zipFile) {
|
||||||
this.zipFile = zipFile;
|
this(new ZipFileResource(zipFile));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造
|
|
||||||
*
|
|
||||||
* @param in 读取的的Zip文件流
|
|
||||||
* @param charset 编码
|
|
||||||
*/
|
|
||||||
public ZipReader(final InputStream in, final Charset charset) {
|
|
||||||
this.in = new ZipInputStream(in, charset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,7 +81,28 @@ public class ZipReader implements Closeable {
|
|||||||
* @param zin 读取的的Zip文件流
|
* @param zin 读取的的Zip文件流
|
||||||
*/
|
*/
|
||||||
public ZipReader(final ZipInputStream zin) {
|
public ZipReader(final ZipInputStream zin) {
|
||||||
this.in = zin;
|
this(new ZipStreamResource(zin));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param resource 读取的的Zip文件流
|
||||||
|
*/
|
||||||
|
public ZipReader(final ZipResource resource) {
|
||||||
|
this.resource = resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置检查ZipBomb文件差异倍数,-1表示不检查ZipBomb
|
||||||
|
*
|
||||||
|
* @param maxSizeDiff 检查ZipBomb文件差异倍数,-1表示不检查ZipBomb
|
||||||
|
* @return this
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public ZipReader setMaxSizeDiff(final int maxSizeDiff) {
|
||||||
|
this.maxSizeDiff = maxSizeDiff;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,27 +113,7 @@ public class ZipReader implements Closeable {
|
|||||||
* @return 文件流
|
* @return 文件流
|
||||||
*/
|
*/
|
||||||
public InputStream get(final String path) {
|
public InputStream get(final String path) {
|
||||||
if (null != this.zipFile) {
|
return this.resource.get(path);
|
||||||
final ZipFile zipFile = this.zipFile;
|
|
||||||
final ZipEntry entry = zipFile.getEntry(path);
|
|
||||||
if (null != entry) {
|
|
||||||
return ZipUtil.getStream(zipFile, entry);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
this.in.reset();
|
|
||||||
ZipEntry zipEntry;
|
|
||||||
while (null != (zipEntry = in.getNextEntry())) {
|
|
||||||
if (zipEntry.getName().equals(path)) {
|
|
||||||
return this.in;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (final IOException e) {
|
|
||||||
throw new IORuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,31 +136,11 @@ public class ZipReader implements Closeable {
|
|||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
* @since 5.7.12
|
* @since 5.7.12
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("resource")
|
||||||
public File readTo(final File outFile, final Predicate<ZipEntry> entryFilter) throws IORuntimeException {
|
public File readTo(final File outFile, final Predicate<ZipEntry> entryFilter) throws IORuntimeException {
|
||||||
read((zipEntry) -> {
|
read((zipEntry) -> {
|
||||||
if (null == entryFilter || entryFilter.test(zipEntry)) {
|
if (null == entryFilter || entryFilter.test(zipEntry)) {
|
||||||
//gitee issue #I4ZDQI
|
readEntry(zipEntry, outFile);
|
||||||
String path = zipEntry.getName();
|
|
||||||
if (FileUtil.isWindows()) {
|
|
||||||
// Win系统下
|
|
||||||
path = StrUtil.replace(path, "*", "_");
|
|
||||||
}
|
|
||||||
// FileUtil.file会检查slip漏洞,漏洞说明见http://blog.nsfocus.net/zip-slip-2/
|
|
||||||
final File outItemFile = FileUtil.file(outFile, path);
|
|
||||||
if (zipEntry.isDirectory()) {
|
|
||||||
// 目录
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
outItemFile.mkdirs();
|
|
||||||
} else {
|
|
||||||
final InputStream in;
|
|
||||||
if (null != this.zipFile) {
|
|
||||||
in = ZipUtil.getStream(this.zipFile, zipEntry);
|
|
||||||
} else {
|
|
||||||
in = this.in;
|
|
||||||
}
|
|
||||||
// 文件
|
|
||||||
FileUtil.writeFromStream(in, outItemFile, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return outFile;
|
return outFile;
|
||||||
@ -193,70 +154,37 @@ public class ZipReader implements Closeable {
|
|||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
*/
|
*/
|
||||||
public ZipReader read(final Consumer<ZipEntry> consumer) throws IORuntimeException {
|
public ZipReader read(final Consumer<ZipEntry> consumer) throws IORuntimeException {
|
||||||
if (null != this.zipFile) {
|
resource.read(consumer, this.maxSizeDiff);
|
||||||
readFromZipFile(consumer);
|
|
||||||
} else {
|
|
||||||
readFromStream(consumer);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IORuntimeException {
|
public void close() throws IORuntimeException {
|
||||||
if (null != this.zipFile) {
|
IoUtil.closeQuietly(this.resource);
|
||||||
IoUtil.closeQuietly(this.zipFile);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取一个ZipEntry的数据到目标目录下,如果entry是个目录,则创建对应目录,否则解压并写出到文件
|
||||||
|
*
|
||||||
|
* @param zipEntry entry
|
||||||
|
* @param outFile 写出到的目录
|
||||||
|
*/
|
||||||
|
private void readEntry(final ZipEntry zipEntry, final File outFile) {
|
||||||
|
//gitee issue #I4ZDQI
|
||||||
|
String path = zipEntry.getName();
|
||||||
|
if (FileUtil.isWindows()) {
|
||||||
|
// Win系统下
|
||||||
|
path = StrUtil.replace(path, "*", "_");
|
||||||
|
}
|
||||||
|
// FileUtil.file会检查slip漏洞,漏洞说明见http://blog.nsfocus.net/zip-slip-2/
|
||||||
|
final File outItemFile = FileUtil.file(outFile, path);
|
||||||
|
if (zipEntry.isDirectory()) {
|
||||||
|
// 目录
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
|
outItemFile.mkdirs();
|
||||||
} else {
|
} else {
|
||||||
IoUtil.closeQuietly(this.in);
|
// 文件
|
||||||
|
FileUtil.writeFromStream(this.resource.get(zipEntry), outItemFile, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取并处理Zip文件中的每一个{@link ZipEntry}
|
|
||||||
*
|
|
||||||
* @param consumer {@link ZipEntry}处理器
|
|
||||||
*/
|
|
||||||
private void readFromZipFile(final Consumer<ZipEntry> consumer) {
|
|
||||||
final Enumeration<? extends ZipEntry> em = zipFile.entries();
|
|
||||||
while (em.hasMoreElements()) {
|
|
||||||
consumer.accept(checkZipBomb(em.nextElement()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取并处理Zip流中的每一个{@link ZipEntry}
|
|
||||||
*
|
|
||||||
* @param consumer {@link ZipEntry}处理器
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
private void readFromStream(final Consumer<ZipEntry> consumer) throws IORuntimeException {
|
|
||||||
try {
|
|
||||||
ZipEntry zipEntry;
|
|
||||||
while (null != (zipEntry = checkZipBomb(in.getNextEntry()))) {
|
|
||||||
consumer.accept(zipEntry);
|
|
||||||
}
|
|
||||||
} catch (final IOException e) {
|
|
||||||
throw new IORuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查Zip bomb漏洞
|
|
||||||
*
|
|
||||||
* @param entry {@link ZipEntry}
|
|
||||||
* @return 检查后的{@link ZipEntry}
|
|
||||||
*/
|
|
||||||
private static ZipEntry checkZipBomb(final ZipEntry entry) {
|
|
||||||
if (null == entry) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final long compressedSize = entry.getCompressedSize();
|
|
||||||
final long uncompressedSize = entry.getSize();
|
|
||||||
if (compressedSize < 0 || uncompressedSize < 0 ||
|
|
||||||
// 默认压缩比例是100倍,一旦发现压缩率超过这个阈值,被认为是Zip bomb
|
|
||||||
compressedSize * MAX_SIZE_DIFF < uncompressedSize) {
|
|
||||||
throw new ValidateException("Zip bomb attack detected, invalid sizes: compressed {}, uncompressed {}, name {}",
|
|
||||||
compressedSize, uncompressedSize, entry.getName());
|
|
||||||
}
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cn.hutool.core.compress;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zip资源表示,如Zip流资源或Zip文件资源
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public interface ZipResource extends Closeable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取并处理Zip文件中的每一个{@link ZipEntry}
|
||||||
|
*
|
||||||
|
* @param consumer {@link ZipEntry}处理器
|
||||||
|
* @param maxSizeDiff 检查ZipBomb文件差异倍数,-1表示不检查ZipBomb
|
||||||
|
*/
|
||||||
|
void read(final Consumer<ZipEntry> consumer, final int maxSizeDiff);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定路径的文件流<br>
|
||||||
|
* 如果是文件模式,则直接获取Entry对应的流,如果是流模式,则遍历entry后,找到对应流返回
|
||||||
|
*
|
||||||
|
* @param path 路径
|
||||||
|
* @return 文件流
|
||||||
|
*/
|
||||||
|
InputStream get(String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定{@link ZipEntry}对应的文件流
|
||||||
|
*
|
||||||
|
* @param entry @link ZipEntry}
|
||||||
|
* @return 文件流
|
||||||
|
*/
|
||||||
|
InputStream get(ZipEntry entry);
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cn.hutool.core.compress;
|
||||||
|
|
||||||
|
import cn.hutool.core.exceptions.ValidateException;
|
||||||
|
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zip安全相关工具类,如检查Zip bomb漏洞等
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class ZipSecurityUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查Zip bomb漏洞
|
||||||
|
*
|
||||||
|
* @param entry {@link ZipEntry}
|
||||||
|
* @param maxSizeDiff 检查ZipBomb文件差异倍数,-1表示不检查ZipBomb
|
||||||
|
* @return 检查后的{@link ZipEntry}
|
||||||
|
*/
|
||||||
|
public static ZipEntry checkZipBomb(final ZipEntry entry, final int maxSizeDiff) {
|
||||||
|
if (null == entry) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (maxSizeDiff < 0 || entry.isDirectory()) {
|
||||||
|
// 目录不检查
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
final long compressedSize = entry.getCompressedSize();
|
||||||
|
final long uncompressedSize = entry.getSize();
|
||||||
|
//Console.log(entry.getName(), compressedSize, uncompressedSize);
|
||||||
|
if (compressedSize < 0 || uncompressedSize < 0 ||
|
||||||
|
// 默认压缩比例是100倍,一旦发现压缩率超过这个阈值,被认为是Zip bomb
|
||||||
|
compressedSize * maxSizeDiff < uncompressedSize) {
|
||||||
|
throw new ValidateException("Zip bomb attack detected, invalid sizes: compressed {}, uncompressed {}, name {}",
|
||||||
|
compressedSize, uncompressedSize, entry.getName());
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cn.hutool.core.compress;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IORuntimeException;
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ZipInputStream} 资源包装
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class ZipStreamResource implements ZipResource {
|
||||||
|
|
||||||
|
private final ZipInputStream in;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param in {@link ZipInputStream}
|
||||||
|
*/
|
||||||
|
public ZipStreamResource(final ZipInputStream in) {
|
||||||
|
this.in = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(final Consumer<ZipEntry> consumer, final int maxSizeDiff) {
|
||||||
|
try {
|
||||||
|
ZipEntry zipEntry;
|
||||||
|
while (null != (zipEntry = in.getNextEntry())) {
|
||||||
|
consumer.accept(zipEntry);
|
||||||
|
// 检查ZipBomb放在读取内容之后,以便entry中的信息正常读取
|
||||||
|
ZipSecurityUtil.checkZipBomb(zipEntry, maxSizeDiff);
|
||||||
|
}
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new IORuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream get(final String path) {
|
||||||
|
try {
|
||||||
|
this.in.reset();
|
||||||
|
ZipEntry zipEntry;
|
||||||
|
while (null != (zipEntry = in.getNextEntry())) {
|
||||||
|
if (zipEntry.getName().equals(path)) {
|
||||||
|
return this.in;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new IORuntimeException(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream get(final ZipEntry entry) {
|
||||||
|
return this.in;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
IoUtil.closeQuietly(this.in);
|
||||||
|
}
|
||||||
|
}
|
@ -794,7 +794,7 @@ public class ZipUtil {
|
|||||||
* @return 解压后的字符串
|
* @return 解压后的字符串
|
||||||
* @throws UtilException IO异常
|
* @throws UtilException IO异常
|
||||||
*/
|
*/
|
||||||
public static String unGzip(final byte[] buf, final String charset) throws UtilException {
|
public static String unGzip(final byte[] buf, final Charset charset) throws UtilException {
|
||||||
return StrUtil.str(unGzip(buf), charset);
|
return StrUtil.str(unGzip(buf), charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -915,7 +915,7 @@ public class ZipUtil {
|
|||||||
* @return 解压后的字符串
|
* @return 解压后的字符串
|
||||||
* @since 4.1.4
|
* @since 4.1.4
|
||||||
*/
|
*/
|
||||||
public static String unZlib(final byte[] buf, final String charset) {
|
public static String unZlib(final byte[] buf, final Charset charset) {
|
||||||
return StrUtil.str(unZlib(buf), charset);
|
return StrUtil.str(unZlib(buf), charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,8 +292,9 @@ public class ZipWriter implements Closeable {
|
|||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
*/
|
*/
|
||||||
private ZipWriter putEntry(final String path, final InputStream in) throws IORuntimeException {
|
private ZipWriter putEntry(final String path, final InputStream in) throws IORuntimeException {
|
||||||
|
final ZipEntry entry = new ZipEntry(path);
|
||||||
try {
|
try {
|
||||||
out.putNextEntry(new ZipEntry(path));
|
out.putNextEntry(entry);
|
||||||
if (null != in) {
|
if (null != in) {
|
||||||
IoUtil.copy(in, out);
|
IoUtil.copy(in, out);
|
||||||
}
|
}
|
||||||
|
@ -204,18 +204,6 @@ public class NioUtil {
|
|||||||
return read(fileChannel, CharsetUtil.UTF_8);
|
return read(fileChannel, CharsetUtil.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 从FileChannel中读取内容,读取完毕后并不关闭Channel
|
|
||||||
*
|
|
||||||
* @param fileChannel 文件管道
|
|
||||||
* @param charsetName 字符集
|
|
||||||
* @return 内容
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static String read(final FileChannel fileChannel, final String charsetName) throws IORuntimeException {
|
|
||||||
return read(fileChannel, CharsetUtil.charset(charsetName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从FileChannel中读取内容
|
* 从FileChannel中读取内容
|
||||||
*
|
*
|
||||||
|
@ -29,7 +29,10 @@ import cn.hutool.core.regex.ReUtil;
|
|||||||
import cn.hutool.core.text.StrUtil;
|
import cn.hutool.core.text.StrUtil;
|
||||||
import cn.hutool.core.text.split.SplitUtil;
|
import cn.hutool.core.text.split.SplitUtil;
|
||||||
import cn.hutool.core.thread.ThreadUtil;
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
import cn.hutool.core.util.*;
|
import cn.hutool.core.util.CharUtil;
|
||||||
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import cn.hutool.core.util.SystemUtil;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
@ -137,6 +140,7 @@ public class FileUtil extends PathUtil {
|
|||||||
return isDirEmpty(dir.toPath());
|
return isDirEmpty(dir.toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// region ----- loop and walk
|
||||||
/**
|
/**
|
||||||
* 递归遍历目录以及子目录中的所有文件<br>
|
* 递归遍历目录以及子目录中的所有文件<br>
|
||||||
* 如果提供file为文件,直接返回过滤结果
|
* 如果提供file为文件,直接返回过滤结果
|
||||||
@ -265,6 +269,7 @@ public class FileUtil extends PathUtil {
|
|||||||
IoUtil.closeQuietly(jarFile);
|
IoUtil.closeQuietly(jarFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
// region ----- file and newFile
|
// region ----- file and newFile
|
||||||
/**
|
/**
|
||||||
@ -1707,20 +1712,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return readLines(path, CharsetUtil.UTF_8, collection);
|
return readLines(path, CharsetUtil.UTF_8, collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 从文件中读取每一行数据
|
|
||||||
*
|
|
||||||
* @param <T> 集合类型
|
|
||||||
* @param path 文件路径
|
|
||||||
* @param charset 字符集
|
|
||||||
* @param collection 集合
|
|
||||||
* @return 文件中的每行内容的集合
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static <T extends Collection<String>> T readLines(final String path, final String charset, final T collection) throws IORuntimeException {
|
|
||||||
return readLines(file(path), charset, collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从文件中读取每一行数据
|
* 从文件中读取每一行数据
|
||||||
*
|
*
|
||||||
@ -1749,20 +1740,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return readLines(file, CharsetUtil.UTF_8, collection);
|
return readLines(file, CharsetUtil.UTF_8, collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 从文件中读取每一行数据
|
|
||||||
*
|
|
||||||
* @param <T> 集合类型
|
|
||||||
* @param file 文件路径
|
|
||||||
* @param charset 字符集
|
|
||||||
* @param collection 集合
|
|
||||||
* @return 文件中的每行内容的集合
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static <T extends Collection<String>> T readLines(final File file, final String charset, final T collection) throws IORuntimeException {
|
|
||||||
return FileReader.of(file, CharsetUtil.charset(charset)).readLines(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从文件中读取每一行数据
|
* 从文件中读取每一行数据
|
||||||
*
|
*
|
||||||
@ -1848,18 +1825,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return readLines(path, CharsetUtil.UTF_8);
|
return readLines(path, CharsetUtil.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 从文件中读取每一行数据
|
|
||||||
*
|
|
||||||
* @param path 文件路径
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 文件中的每行内容的集合List
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static List<String> readLines(final String path, final String charset) throws IORuntimeException {
|
|
||||||
return readLines(path, charset, new ArrayList<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从文件中读取每一行数据
|
* 从文件中读取每一行数据
|
||||||
*
|
*
|
||||||
@ -1885,18 +1850,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return readLines(file, CharsetUtil.UTF_8);
|
return readLines(file, CharsetUtil.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 从文件中读取每一行数据
|
|
||||||
*
|
|
||||||
* @param file 文件
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 文件中的每行内容的集合List
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static List<String> readLines(final File file, final String charset) throws IORuntimeException {
|
|
||||||
return readLines(file, charset, new ArrayList<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从文件中读取每一行数据
|
* 从文件中读取每一行数据
|
||||||
*
|
*
|
||||||
@ -2176,19 +2129,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return writeString(content, file, CharsetUtil.UTF_8);
|
return writeString(content, file, CharsetUtil.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将String写入文件,覆盖模式
|
|
||||||
*
|
|
||||||
* @param content 写入的内容
|
|
||||||
* @param path 文件路径
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 写入的文件
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static File writeString(final String content, final String path, final String charset) throws IORuntimeException {
|
|
||||||
return writeString(content, touch(path), charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将String写入文件,覆盖模式
|
* 将String写入文件,覆盖模式
|
||||||
*
|
*
|
||||||
@ -2202,19 +2142,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return writeString(content, touch(path), charset);
|
return writeString(content, touch(path), charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将String写入文件,覆盖模式
|
|
||||||
*
|
|
||||||
* @param content 写入的内容
|
|
||||||
* @param file 文件
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 被写入的文件
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static File writeString(final String content, final File file, final String charset) throws IORuntimeException {
|
|
||||||
return FileWriter.of(file, CharsetUtil.charset(charset)).write(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将String写入文件,覆盖模式
|
* 将String写入文件,覆盖模式
|
||||||
*
|
*
|
||||||
@ -2241,19 +2168,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return appendString(content, path, CharsetUtil.UTF_8);
|
return appendString(content, path, CharsetUtil.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将String写入文件,追加模式
|
|
||||||
*
|
|
||||||
* @param content 写入的内容
|
|
||||||
* @param path 文件路径
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 写入的文件
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static File appendString(final String content, final String path, final String charset) throws IORuntimeException {
|
|
||||||
return appendString(content, touch(path), charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将String写入文件,追加模式
|
* 将String写入文件,追加模式
|
||||||
*
|
*
|
||||||
@ -2280,19 +2194,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return appendString(content, file, CharsetUtil.UTF_8);
|
return appendString(content, file, CharsetUtil.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将String写入文件,追加模式
|
|
||||||
*
|
|
||||||
* @param content 写入的内容
|
|
||||||
* @param file 文件
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 写入的文件
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static File appendString(final String content, final File file, final String charset) throws IORuntimeException {
|
|
||||||
return FileWriter.of(file, CharsetUtil.charset(charset)).append(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将String写入文件,追加模式
|
* 将String写入文件,追加模式
|
||||||
*
|
*
|
||||||
@ -2334,20 +2235,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return writeLines(list, file, CharsetUtil.UTF_8);
|
return writeLines(list, file, CharsetUtil.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将列表写入文件,覆盖模式
|
|
||||||
*
|
|
||||||
* @param <T> 集合元素类型
|
|
||||||
* @param list 列表
|
|
||||||
* @param path 绝对路径
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 目标文件
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static <T> File writeLines(final Collection<T> list, final String path, final String charset) throws IORuntimeException {
|
|
||||||
return writeLines(list, path, charset, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将列表写入文件,覆盖模式
|
* 将列表写入文件,覆盖模式
|
||||||
*
|
*
|
||||||
@ -2362,21 +2249,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return writeLines(list, path, charset, false);
|
return writeLines(list, path, charset, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将列表写入文件,覆盖模式
|
|
||||||
*
|
|
||||||
* @param <T> 集合元素类型
|
|
||||||
* @param list 列表
|
|
||||||
* @param file 文件
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 目标文件
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
* @since 4.2.0
|
|
||||||
*/
|
|
||||||
public static <T> File writeLines(final Collection<T> list, final File file, final String charset) throws IORuntimeException {
|
|
||||||
return writeLines(list, file, charset, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将列表写入文件,覆盖模式
|
* 将列表写入文件,覆盖模式
|
||||||
*
|
*
|
||||||
@ -2420,35 +2292,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return appendLines(list, path, CharsetUtil.UTF_8);
|
return appendLines(list, path, CharsetUtil.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将列表写入文件,追加模式
|
|
||||||
*
|
|
||||||
* @param <T> 集合元素类型
|
|
||||||
* @param list 列表
|
|
||||||
* @param path 绝对路径
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 目标文件
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static <T> File appendLines(final Collection<T> list, final String path, final String charset) throws IORuntimeException {
|
|
||||||
return writeLines(list, path, charset, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将列表写入文件,追加模式
|
|
||||||
*
|
|
||||||
* @param <T> 集合元素类型
|
|
||||||
* @param list 列表
|
|
||||||
* @param file 文件
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 目标文件
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
* @since 3.1.2
|
|
||||||
*/
|
|
||||||
public static <T> File appendLines(final Collection<T> list, final File file, final String charset) throws IORuntimeException {
|
|
||||||
return writeLines(list, file, charset, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将列表写入文件,追加模式
|
* 将列表写入文件,追加模式
|
||||||
*
|
*
|
||||||
@ -2483,21 +2326,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return writeLines(list, file, charset, true);
|
return writeLines(list, file, charset, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将列表写入文件
|
|
||||||
*
|
|
||||||
* @param <T> 集合元素类型
|
|
||||||
* @param list 列表
|
|
||||||
* @param path 文件路径
|
|
||||||
* @param charset 字符集
|
|
||||||
* @param isAppend 是否追加
|
|
||||||
* @return 目标文件
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static <T> File writeLines(final Collection<T> list, final String path, final String charset, final boolean isAppend) throws IORuntimeException {
|
|
||||||
return writeLines(list, file(path), charset, isAppend);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将列表写入文件
|
* 将列表写入文件
|
||||||
*
|
*
|
||||||
@ -2513,21 +2341,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return writeLines(list, file(path), charset, isAppend);
|
return writeLines(list, file(path), charset, isAppend);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将列表写入文件
|
|
||||||
*
|
|
||||||
* @param <T> 集合元素类型
|
|
||||||
* @param list 列表
|
|
||||||
* @param file 文件
|
|
||||||
* @param charset 字符集
|
|
||||||
* @param isAppend 是否追加
|
|
||||||
* @return 目标文件
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
*/
|
|
||||||
public static <T> File writeLines(final Collection<T> list, final File file, final String charset, final boolean isAppend) throws IORuntimeException {
|
|
||||||
return FileWriter.of(file, CharsetUtil.charset(charset)).writeLines(list, isAppend);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将列表写入文件
|
* 将列表写入文件
|
||||||
*
|
*
|
||||||
|
@ -74,16 +74,6 @@ public class FileWriter extends FileWrapper {
|
|||||||
checkFile();
|
checkFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造
|
|
||||||
*
|
|
||||||
* @param file 文件
|
|
||||||
* @param charset 编码,使用 {@link CharsetUtil#charset(String)}
|
|
||||||
*/
|
|
||||||
public FileWriter(final File file, final String charset) {
|
|
||||||
this(file, CharsetUtil.charset(charset));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
*
|
*
|
||||||
|
@ -1285,8 +1285,12 @@ public class MapUtil extends MapGetUtil {
|
|||||||
if (JdkUtil.IS_JDK8) {
|
if (JdkUtil.IS_JDK8) {
|
||||||
V value = map.get(key);
|
V value = map.get(key);
|
||||||
if (null == value) {
|
if (null == value) {
|
||||||
//map.putIfAbsent(key, mappingFunction.apply(key));
|
map.putIfAbsent(key, mappingFunction.apply(key));
|
||||||
value = map.computeIfAbsent(key, mappingFunction);
|
value = map.get(key);
|
||||||
|
|
||||||
|
// 判空后调用依旧无法解决死循环问题
|
||||||
|
// 见:Issue2349Test
|
||||||
|
//value = map.computeIfAbsent(key, mappingFunction);
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
} else {
|
} else {
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
package cn.hutool.core.map;
|
package cn.hutool.core.map;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.JdkUtil;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@ -43,7 +45,7 @@ public class SafeConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {
|
|||||||
*
|
*
|
||||||
* @param initialCapacity 预估初始大小
|
* @param initialCapacity 预估初始大小
|
||||||
*/
|
*/
|
||||||
public SafeConcurrentHashMap(int initialCapacity) {
|
public SafeConcurrentHashMap(final int initialCapacity) {
|
||||||
super(initialCapacity);
|
super(initialCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +54,7 @@ public class SafeConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {
|
|||||||
*
|
*
|
||||||
* @param m 初始键值对
|
* @param m 初始键值对
|
||||||
*/
|
*/
|
||||||
public SafeConcurrentHashMap(Map<? extends K, ? extends V> m) {
|
public SafeConcurrentHashMap(final Map<? extends K, ? extends V> m) {
|
||||||
super(m);
|
super(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +64,7 @@ public class SafeConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {
|
|||||||
* @param initialCapacity 初始容量
|
* @param initialCapacity 初始容量
|
||||||
* @param loadFactor 增长系数
|
* @param loadFactor 增长系数
|
||||||
*/
|
*/
|
||||||
public SafeConcurrentHashMap(int initialCapacity, float loadFactor) {
|
public SafeConcurrentHashMap(final int initialCapacity, final float loadFactor) {
|
||||||
super(initialCapacity, loadFactor);
|
super(initialCapacity, loadFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,14 +75,27 @@ public class SafeConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {
|
|||||||
* @param loadFactor 增长系数
|
* @param loadFactor 增长系数
|
||||||
* @param concurrencyLevel 并发级别,即Segment的个数
|
* @param concurrencyLevel 并发级别,即Segment的个数
|
||||||
*/
|
*/
|
||||||
public SafeConcurrentHashMap(int initialCapacity,
|
public SafeConcurrentHashMap(final int initialCapacity,
|
||||||
float loadFactor, int concurrencyLevel) {
|
final float loadFactor, final int concurrencyLevel) {
|
||||||
super(initialCapacity, loadFactor, concurrencyLevel);
|
super(initialCapacity, loadFactor, concurrencyLevel);
|
||||||
}
|
}
|
||||||
// endregion == 构造 ==
|
// endregion == 构造 ==
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
|
public V computeIfAbsent(final K key, final Function<? super K, ? extends V> mappingFunction) {
|
||||||
return MapUtil.computeIfAbsent(this, key, mappingFunction);
|
if (JdkUtil.IS_JDK8) {
|
||||||
|
V value = get(key);
|
||||||
|
if (null == value) {
|
||||||
|
putIfAbsent(key, mappingFunction.apply(key));
|
||||||
|
value = get(key);
|
||||||
|
|
||||||
|
// 判空后调用依旧无法解决死循环问题
|
||||||
|
// 见:Issue2349Test
|
||||||
|
//value = map.computeIfAbsent(key, mappingFunction);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return super.computeIfAbsent(key, mappingFunction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,17 +191,6 @@ public class UrlQueryUtil {
|
|||||||
return Convert.toMap(String.class, String.class, queryMap);
|
return Convert.toMap(String.class, String.class, queryMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将URL参数解析为Map(也可以解析Post中的键值对参数)
|
|
||||||
*
|
|
||||||
* @param paramsStr 参数字符串(或者带参数的Path)
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 参数Map
|
|
||||||
*/
|
|
||||||
public static Map<String, List<String>> decodeQuery(final String paramsStr, final String charset) {
|
|
||||||
return decodeQueryList(paramsStr, CharsetUtil.charset(charset));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将URL参数解析为Map(也可以解析Post中的键值对参数)
|
* 将URL参数解析为Map(也可以解析Post中的键值对参数)
|
||||||
*
|
*
|
||||||
|
@ -164,17 +164,6 @@ public class StrUtil extends CharSequenceUtil implements StrPool {
|
|||||||
return obj.toString();
|
return obj.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将byte数组转为字符串
|
|
||||||
*
|
|
||||||
* @param bytes byte数组
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String str(final byte[] bytes, final String charset) {
|
|
||||||
return str(bytes, CharsetUtil.charset(charset));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解码字节码
|
* 解码字节码
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cn.hutool.core.compress;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.file.FileUtil;
|
||||||
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class Issue3018Test {
|
||||||
|
@Test
|
||||||
|
void unzipTest() {
|
||||||
|
ZipUtil.unzip(FileUtil.getInputStream("d:/test/default.zip"),
|
||||||
|
FileUtil.file("d:/test/"),
|
||||||
|
CharsetUtil.UTF_8
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void unzipFromFileTest() {
|
||||||
|
ZipUtil.unzip("d:/test/default.zip");
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@ public class UrlQueryUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void decodeQueryTest() {
|
public void decodeQueryTest() {
|
||||||
final String paramsStr = "uuuu=0&a=b&c=%3F%23%40!%24%25%5E%26%3Ddsssss555555";
|
final String paramsStr = "uuuu=0&a=b&c=%3F%23%40!%24%25%5E%26%3Ddsssss555555";
|
||||||
final Map<String, List<String>> map = UrlQueryUtil.decodeQuery(paramsStr, CharsetUtil.NAME_UTF_8);
|
final Map<String, List<String>> map = UrlQueryUtil.decodeQueryList(paramsStr, CharsetUtil.UTF_8);
|
||||||
Assertions.assertEquals("0", map.get("uuuu").get(0));
|
Assertions.assertEquals("0", map.get("uuuu").get(0));
|
||||||
Assertions.assertEquals("b", map.get("a").get(0));
|
Assertions.assertEquals("b", map.get("a").get(0));
|
||||||
Assertions.assertEquals("?#@!$%^&=dsssss555555", map.get("c").get(0));
|
Assertions.assertEquals("?#@!$%^&=dsssss555555", map.get("c").get(0));
|
||||||
@ -28,7 +28,7 @@ public class UrlQueryUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void toQueryTest() {
|
public void toQueryTest() {
|
||||||
final String paramsStr = "uuuu=0&a=b&c=3Ddsssss555555";
|
final String paramsStr = "uuuu=0&a=b&c=3Ddsssss555555";
|
||||||
final Map<String, List<String>> map = UrlQueryUtil.decodeQuery(paramsStr, CharsetUtil.NAME_UTF_8);
|
final Map<String, List<String>> map = UrlQueryUtil.decodeQueryList(paramsStr, CharsetUtil.UTF_8);
|
||||||
|
|
||||||
final String encodedParams = UrlQueryUtil.toQuery(map);
|
final String encodedParams = UrlQueryUtil.toQuery(map);
|
||||||
Assertions.assertEquals(paramsStr, encodedParams);
|
Assertions.assertEquals(paramsStr, encodedParams);
|
||||||
@ -91,41 +91,41 @@ public class UrlQueryUtilTest {
|
|||||||
public void decodeParamTest() {
|
public void decodeParamTest() {
|
||||||
// 开头的?被去除
|
// 开头的?被去除
|
||||||
String a = "?a=b&c=d&";
|
String a = "?a=b&c=d&";
|
||||||
Map<String, List<String>> map = UrlQueryUtil.decodeQuery(a, CharsetUtil.NAME_UTF_8);
|
Map<String, List<String>> map = UrlQueryUtil.decodeQueryList(a, CharsetUtil.UTF_8);
|
||||||
Assertions.assertEquals("b", map.get("a").get(0));
|
Assertions.assertEquals("b", map.get("a").get(0));
|
||||||
Assertions.assertEquals("d", map.get("c").get(0));
|
Assertions.assertEquals("d", map.get("c").get(0));
|
||||||
|
|
||||||
// =e被当作空为key,e为value
|
// =e被当作空为key,e为value
|
||||||
a = "?a=b&c=d&=e";
|
a = "?a=b&c=d&=e";
|
||||||
map = UrlQueryUtil.decodeQuery(a, CharsetUtil.NAME_UTF_8);
|
map = UrlQueryUtil.decodeQueryList(a, CharsetUtil.UTF_8);
|
||||||
Assertions.assertEquals("b", map.get("a").get(0));
|
Assertions.assertEquals("b", map.get("a").get(0));
|
||||||
Assertions.assertEquals("d", map.get("c").get(0));
|
Assertions.assertEquals("d", map.get("c").get(0));
|
||||||
Assertions.assertEquals("e", map.get("").get(0));
|
Assertions.assertEquals("e", map.get("").get(0));
|
||||||
|
|
||||||
// 多余的&去除
|
// 多余的&去除
|
||||||
a = "?a=b&c=d&=e&&&&";
|
a = "?a=b&c=d&=e&&&&";
|
||||||
map = UrlQueryUtil.decodeQuery(a, CharsetUtil.NAME_UTF_8);
|
map = UrlQueryUtil.decodeQueryList(a, CharsetUtil.UTF_8);
|
||||||
Assertions.assertEquals("b", map.get("a").get(0));
|
Assertions.assertEquals("b", map.get("a").get(0));
|
||||||
Assertions.assertEquals("d", map.get("c").get(0));
|
Assertions.assertEquals("d", map.get("c").get(0));
|
||||||
Assertions.assertEquals("e", map.get("").get(0));
|
Assertions.assertEquals("e", map.get("").get(0));
|
||||||
|
|
||||||
// 值为空
|
// 值为空
|
||||||
a = "?a=b&c=d&e=";
|
a = "?a=b&c=d&e=";
|
||||||
map = UrlQueryUtil.decodeQuery(a, CharsetUtil.NAME_UTF_8);
|
map = UrlQueryUtil.decodeQueryList(a, CharsetUtil.UTF_8);
|
||||||
Assertions.assertEquals("b", map.get("a").get(0));
|
Assertions.assertEquals("b", map.get("a").get(0));
|
||||||
Assertions.assertEquals("d", map.get("c").get(0));
|
Assertions.assertEquals("d", map.get("c").get(0));
|
||||||
Assertions.assertEquals("", map.get("e").get(0));
|
Assertions.assertEquals("", map.get("e").get(0));
|
||||||
|
|
||||||
// &=被作为键和值都为空
|
// &=被作为键和值都为空
|
||||||
a = "a=b&c=d&=";
|
a = "a=b&c=d&=";
|
||||||
map = UrlQueryUtil.decodeQuery(a, CharsetUtil.NAME_UTF_8);
|
map = UrlQueryUtil.decodeQueryList(a, CharsetUtil.UTF_8);
|
||||||
Assertions.assertEquals("b", map.get("a").get(0));
|
Assertions.assertEquals("b", map.get("a").get(0));
|
||||||
Assertions.assertEquals("d", map.get("c").get(0));
|
Assertions.assertEquals("d", map.get("c").get(0));
|
||||||
Assertions.assertEquals("", map.get("").get(0));
|
Assertions.assertEquals("", map.get("").get(0));
|
||||||
|
|
||||||
// &e&这类单独的字符串被当作key
|
// &e&这类单独的字符串被当作key
|
||||||
a = "a=b&c=d&e&";
|
a = "a=b&c=d&e&";
|
||||||
map = UrlQueryUtil.decodeQuery(a, CharsetUtil.NAME_UTF_8);
|
map = UrlQueryUtil.decodeQueryList(a, CharsetUtil.UTF_8);
|
||||||
Assertions.assertEquals("b", map.get("a").get(0));
|
Assertions.assertEquals("b", map.get("a").get(0));
|
||||||
Assertions.assertEquals("d", map.get("c").get(0));
|
Assertions.assertEquals("d", map.get("c").get(0));
|
||||||
Assertions.assertNull(map.get("e").get(0));
|
Assertions.assertNull(map.get("e").get(0));
|
||||||
@ -133,7 +133,7 @@ public class UrlQueryUtilTest {
|
|||||||
|
|
||||||
// 被编码的键和值被还原
|
// 被编码的键和值被还原
|
||||||
a = "a=bbb&c=%E4%BD%A0%E5%A5%BD&%E5%93%88%E5%96%BD=";
|
a = "a=bbb&c=%E4%BD%A0%E5%A5%BD&%E5%93%88%E5%96%BD=";
|
||||||
map = UrlQueryUtil.decodeQuery(a, CharsetUtil.NAME_UTF_8);
|
map = UrlQueryUtil.decodeQueryList(a, CharsetUtil.UTF_8);
|
||||||
Assertions.assertEquals("bbb", map.get("a").get(0));
|
Assertions.assertEquals("bbb", map.get("a").get(0));
|
||||||
Assertions.assertEquals("你好", map.get("c").get(0));
|
Assertions.assertEquals("你好", map.get("c").get(0));
|
||||||
Assertions.assertEquals("", map.get("哈喽").get(0));
|
Assertions.assertEquals("", map.get("哈喽").get(0));
|
||||||
|
@ -43,7 +43,6 @@
|
|||||||
<zxing.version>3.5.1</zxing.version>
|
<zxing.version>3.5.1</zxing.version>
|
||||||
<net.version>3.9.0</net.version>
|
<net.version>3.9.0</net.version>
|
||||||
<emoji-java.version>5.1.1</emoji-java.version>
|
<emoji-java.version>5.1.1</emoji-java.version>
|
||||||
<servlet-api.version>4.0.1</servlet-api.version>
|
|
||||||
<spring-boot.version>2.7.5</spring-boot.version>
|
<spring-boot.version>2.7.5</spring-boot.version>
|
||||||
<cglib.version>3.3.0</cglib.version>
|
<cglib.version>3.3.0</cglib.version>
|
||||||
</properties>
|
</properties>
|
||||||
@ -64,21 +63,6 @@
|
|||||||
<artifactId>hutool-setting</artifactId>
|
<artifactId>hutool-setting</artifactId>
|
||||||
<version>${project.parent.version}</version>
|
<version>${project.parent.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>javax.servlet</groupId>
|
|
||||||
<artifactId>javax.servlet-api</artifactId>
|
|
||||||
<version>${servlet-api.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>jakarta.servlet</groupId>
|
|
||||||
<artifactId>jakarta.servlet-api</artifactId>
|
|
||||||
<!-- 版本固定5.0.0,可以支持jdk8 -->
|
|
||||||
<version>5.0.0</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 模板引擎 -->
|
<!-- 模板引擎 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -50,6 +50,21 @@
|
|||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Servlet -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.servlet</groupId>
|
||||||
|
<artifactId>jakarta.servlet-api</artifactId>
|
||||||
|
<!-- 版本固定5.0.0,可以支持jdk8 -->
|
||||||
|
<version>5.0.0</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 第三方HTTP客户端库 -->
|
<!-- 第三方HTTP客户端库 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cn.hutool.extra.servlet;
|
package cn.hutool.http.server.servlet;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.bean.copier.CopyOptions;
|
import cn.hutool.core.bean.copier.CopyOptions;
|
||||||
@ -33,6 +33,7 @@ import cn.hutool.core.array.ArrayUtil;
|
|||||||
import cn.hutool.core.util.CharsetUtil;
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
|
||||||
|
import cn.hutool.http.meta.Method;
|
||||||
import jakarta.servlet.ServletOutputStream;
|
import jakarta.servlet.ServletOutputStream;
|
||||||
import jakarta.servlet.ServletRequest;
|
import jakarta.servlet.ServletRequest;
|
||||||
import jakarta.servlet.http.Cookie;
|
import jakarta.servlet.http.Cookie;
|
||||||
@ -66,14 +67,6 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class JakartaServletUtil {
|
public class JakartaServletUtil {
|
||||||
|
|
||||||
public static final String METHOD_DELETE = "DELETE";
|
|
||||||
public static final String METHOD_HEAD = "HEAD";
|
|
||||||
public static final String METHOD_GET = "GET";
|
|
||||||
public static final String METHOD_OPTIONS = "OPTIONS";
|
|
||||||
public static final String METHOD_POST = "POST";
|
|
||||||
public static final String METHOD_PUT = "PUT";
|
|
||||||
public static final String METHOD_TRACE = "TRACE";
|
|
||||||
|
|
||||||
// --------------------------------------------------------- getParam start
|
// --------------------------------------------------------- getParam start
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -373,18 +366,6 @@ public class JakartaServletUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得请求header中的信息
|
|
||||||
*
|
|
||||||
* @param request 请求对象{@link HttpServletRequest}
|
|
||||||
* @param name 头信息的KEY
|
|
||||||
* @param charsetName 字符集
|
|
||||||
* @return header值
|
|
||||||
*/
|
|
||||||
public static String getHeader(final HttpServletRequest request, final String name, final String charsetName) {
|
|
||||||
return getHeader(request, name, CharsetUtil.charset(charsetName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得请求header中的信息
|
* 获得请求header中的信息
|
||||||
*
|
*
|
||||||
@ -425,7 +406,7 @@ public class JakartaServletUtil {
|
|||||||
* @return 是否为GET请求
|
* @return 是否为GET请求
|
||||||
*/
|
*/
|
||||||
public static boolean isGetMethod(final HttpServletRequest request) {
|
public static boolean isGetMethod(final HttpServletRequest request) {
|
||||||
return METHOD_GET.equalsIgnoreCase(request.getMethod());
|
return Method.GET.name().equalsIgnoreCase(request.getMethod());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -435,7 +416,7 @@ public class JakartaServletUtil {
|
|||||||
* @return 是否为POST请求
|
* @return 是否为POST请求
|
||||||
*/
|
*/
|
||||||
public static boolean isPostMethod(final HttpServletRequest request) {
|
public static boolean isPostMethod(final HttpServletRequest request) {
|
||||||
return METHOD_POST.equalsIgnoreCase(request.getMethod());
|
return Method.POST.name().equalsIgnoreCase(request.getMethod());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
@ -10,7 +10,7 @@
|
|||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cn.hutool.extra.servlet;
|
package cn.hutool.http.server.servlet;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.bean.copier.CopyOptions;
|
import cn.hutool.core.bean.copier.CopyOptions;
|
||||||
@ -32,6 +32,7 @@ import cn.hutool.core.text.StrUtil;
|
|||||||
import cn.hutool.core.array.ArrayUtil;
|
import cn.hutool.core.array.ArrayUtil;
|
||||||
import cn.hutool.core.util.CharsetUtil;
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import cn.hutool.http.meta.Method;
|
||||||
|
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
@ -65,14 +66,6 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class ServletUtil {
|
public class ServletUtil {
|
||||||
|
|
||||||
public static final String METHOD_DELETE = "DELETE";
|
|
||||||
public static final String METHOD_HEAD = "HEAD";
|
|
||||||
public static final String METHOD_GET = "GET";
|
|
||||||
public static final String METHOD_OPTIONS = "OPTIONS";
|
|
||||||
public static final String METHOD_POST = "POST";
|
|
||||||
public static final String METHOD_PUT = "PUT";
|
|
||||||
public static final String METHOD_TRACE = "TRACE";
|
|
||||||
|
|
||||||
// --------------------------------------------------------- getParam start
|
// --------------------------------------------------------- getParam start
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -424,7 +417,7 @@ public class ServletUtil {
|
|||||||
* @return 是否为GET请求
|
* @return 是否为GET请求
|
||||||
*/
|
*/
|
||||||
public static boolean isGetMethod(final HttpServletRequest request) {
|
public static boolean isGetMethod(final HttpServletRequest request) {
|
||||||
return METHOD_GET.equalsIgnoreCase(request.getMethod());
|
return Method.GET.name().equalsIgnoreCase(request.getMethod());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -434,7 +427,7 @@ public class ServletUtil {
|
|||||||
* @return 是否为POST请求
|
* @return 是否为POST请求
|
||||||
*/
|
*/
|
||||||
public static boolean isPostMethod(final HttpServletRequest request) {
|
public static boolean isPostMethod(final HttpServletRequest request) {
|
||||||
return METHOD_POST.equalsIgnoreCase(request.getMethod());
|
return Method.POST.name().equalsIgnoreCase(request.getMethod());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Servlet封装,包括Servlet参数获取、文件上传、Response写出等,入口为ServletUtil
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package cn.hutool.http.server.servlet;
|
@ -1,4 +1,16 @@
|
|||||||
package cn.hutool.extra.servlet;
|
/*
|
||||||
|
* Copyright (c) 2023 looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cn.hutool.http.server.servlet;
|
||||||
|
|
||||||
import cn.hutool.core.util.ByteUtil;
|
import cn.hutool.core.util.ByteUtil;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
Loading…
x
Reference in New Issue
Block a user