From f0fb98c5840612b4cf7fe3d240b8e8dcb195ea17 Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 1 Apr 2023 01:04:54 +0800 Subject: [PATCH] fix code --- .../core/annotation/AnnotationUtil.java | 19 +- .../RepeatableAnnotationCollector.java | 11 +- .../hutool/core/compress/ZipFileResource.java | 70 ++++++ .../cn/hutool/core/compress/ZipReader.java | 188 +++++------------ .../cn/hutool/core/compress/ZipResource.java | 52 +++++ .../hutool/core/compress/ZipSecurityUtil.java | 54 +++++ .../core/compress/ZipStreamResource.java | 82 ++++++++ .../java/cn/hutool/core/compress/ZipUtil.java | 4 +- .../cn/hutool/core/compress/ZipWriter.java | 3 +- .../main/java/cn/hutool/core/io/NioUtil.java | 12 -- .../java/cn/hutool/core/io/file/FileUtil.java | 199 +----------------- .../cn/hutool/core/io/file/FileWriter.java | 10 - .../main/java/cn/hutool/core/map/MapUtil.java | 8 +- .../core/map/SafeConcurrentHashMap.java | 29 ++- .../cn/hutool/core/net/url/UrlQueryUtil.java | 11 - .../java/cn/hutool/core/text/StrUtil.java | 11 - .../hutool/core/compress/Issue3018Test.java | 32 +++ .../hutool/core/net/url/UrlQueryUtilTest.java | 18 +- hutool-extra/pom.xml | 16 -- hutool-http/pom.xml | 15 ++ .../server}/servlet/JakartaServletUtil.java | 27 +-- .../http/server}/servlet/ServletUtil.java | 15 +- .../http/server/servlet/package-info.java | 19 ++ .../http/server}/servlet/ServletUtilTest.java | 14 +- 24 files changed, 457 insertions(+), 462 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/compress/ZipFileResource.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/compress/ZipResource.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/compress/ZipSecurityUtil.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/compress/ZipStreamResource.java create mode 100644 hutool-core/src/test/java/cn/hutool/core/compress/Issue3018Test.java rename {hutool-extra/src/main/java/cn/hutool/extra => hutool-http/src/main/java/cn/hutool/http/server}/servlet/JakartaServletUtil.java (96%) mode change 100755 => 100644 rename {hutool-extra/src/main/java/cn/hutool/extra => hutool-http/src/main/java/cn/hutool/http/server}/servlet/ServletUtil.java (97%) mode change 100755 => 100644 create mode 100644 hutool-http/src/main/java/cn/hutool/http/server/servlet/package-info.java rename {hutool-extra/src/test/java/cn/hutool/extra => hutool-http/src/test/java/cn/hutool/http/server}/servlet/ServletUtilTest.java (75%) mode change 100755 => 100644 diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java index 77c81417c..42aa0c887 100755 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java @@ -12,32 +12,21 @@ package cn.hutool.core.annotation; +import cn.hutool.core.array.ArrayUtil; import cn.hutool.core.classloader.ClassLoaderUtil; import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.lang.func.LambdaInfo; import cn.hutool.core.lang.func.LambdaUtil; import cn.hutool.core.lang.func.SerFunction; -import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.WeakConcurrentMap; import cn.hutool.core.reflect.FieldUtil; import cn.hutool.core.reflect.MethodUtil; import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.StrUtil; -import cn.hutool.core.array.ArrayUtil; import cn.hutool.core.util.ObjUtil; -import java.lang.annotation.Annotation; -import java.lang.annotation.Documented; -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.lang.annotation.*; +import java.lang.reflect.*; import java.util.HashMap; import java.util.Map; import java.util.function.Predicate; @@ -70,7 +59,7 @@ public class AnnotationUtil { * @since 6.0.0 */ public static Annotation[] getDeclaredAnnotations(final AnnotatedElement element) { - return MapUtil.computeIfAbsent(DECLARED_ANNOTATIONS_CACHE, element, AnnotatedElement::getDeclaredAnnotations); + return DECLARED_ANNOTATIONS_CACHE.computeIfAbsent(element, AnnotatedElement::getDeclaredAnnotations); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java index 17ef4956a..b1cb813f5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java @@ -12,12 +12,11 @@ package cn.hutool.core.annotation; +import cn.hutool.core.array.ArrayUtil; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.WeakConcurrentMap; import cn.hutool.core.reflect.MethodUtil; import cn.hutool.core.text.CharSequenceUtil; -import cn.hutool.core.array.ArrayUtil; import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; @@ -354,9 +353,7 @@ public interface RepeatableAnnotationCollector { */ @Override protected List resolveRepeatableMethod(final Annotation annotation) { - final Object cache = MapUtil.computeIfAbsent( - repeatableMethodCache, annotation.annotationType(), this::resolveRepeatableMethodFromType - ); + final Object cache = repeatableMethodCache.computeIfAbsent(annotation.annotationType(), this::resolveRepeatableMethodFromType); return (cache == NONE) ? null : Collections.singletonList((Method)cache); } @@ -467,9 +464,7 @@ public interface RepeatableAnnotationCollector { @SuppressWarnings("unchecked") @Override protected List resolveRepeatableMethod(final Annotation annotation) { - final Object cache = MapUtil.computeIfAbsent( - repeatableMethodCache, annotation.annotationType(), this::resolveRepeatableMethodFromType - ); + final Object cache = repeatableMethodCache.computeIfAbsent(annotation.annotationType(), this::resolveRepeatableMethodFromType); return (cache == NONE) ? null : (List)cache; } diff --git a/hutool-core/src/main/java/cn/hutool/core/compress/ZipFileResource.java b/hutool-core/src/main/java/cn/hutool/core/compress/ZipFileResource.java new file mode 100644 index 000000000..8f7c3a4c8 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/compress/ZipFileResource.java @@ -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 consumer, final int maxSizeDiff) { + final Enumeration 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); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/compress/ZipReader.java b/hutool-core/src/main/java/cn/hutool/core/compress/ZipReader.java index 5ae9445bc..c3c7848a8 100755 --- a/hutool-core/src/main/java/cn/hutool/core/compress/ZipReader.java +++ b/hutool-core/src/main/java/cn/hutool/core/compress/ZipReader.java @@ -12,18 +12,15 @@ 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.IoUtil; +import cn.hutool.core.io.file.FileUtil; import cn.hutool.core.text.StrUtil; import java.io.Closeable; import java.io.File; -import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; -import java.util.Enumeration; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.zip.ZipEntry; @@ -39,10 +36,7 @@ import java.util.zip.ZipInputStream; public class ZipReader implements Closeable { // 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 ZipFile zipFile; - private ZipInputStream in; + private static final int DEFAULT_MAX_SIZE_DIFF = 100; /** * 创建ZipReader @@ -52,7 +46,7 @@ public class ZipReader implements Closeable { * @return ZipReader */ 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 */ 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; /** - * 构造 - * - * @param zipFile 读取的的Zip文件 - * @param charset 编码 + * 检查ZipBomb文件差异倍数,-1表示不检查ZipBomb */ - public ZipReader(final File zipFile, final Charset charset) { - this.zipFile = ZipUtil.toZipFile(zipFile, charset); - } + private int maxSizeDiff = DEFAULT_MAX_SIZE_DIFF; /** * 构造 @@ -82,17 +72,7 @@ public class ZipReader implements Closeable { * @param zipFile 读取的的Zip文件 */ public ZipReader(final ZipFile zipFile) { - this.zipFile = zipFile; - } - - /** - * 构造 - * - * @param in 读取的的Zip文件流 - * @param charset 编码 - */ - public ZipReader(final InputStream in, final Charset charset) { - this.in = new ZipInputStream(in, charset); + this(new ZipFileResource(zipFile)); } /** @@ -101,7 +81,28 @@ public class ZipReader implements Closeable { * @param zin 读取的的Zip文件流 */ 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 文件流 */ public InputStream get(final String path) { - if (null != this.zipFile) { - 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; + return this.resource.get(path); } /** @@ -155,31 +136,11 @@ public class ZipReader implements Closeable { * @throws IORuntimeException IO异常 * @since 5.7.12 */ + @SuppressWarnings("resource") public File readTo(final File outFile, final Predicate entryFilter) throws IORuntimeException { read((zipEntry) -> { if (null == entryFilter || entryFilter.test(zipEntry)) { - //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 { - final InputStream in; - if (null != this.zipFile) { - in = ZipUtil.getStream(this.zipFile, zipEntry); - } else { - in = this.in; - } - // 文件 - FileUtil.writeFromStream(in, outItemFile, false); - } + readEntry(zipEntry, outFile); } }); return outFile; @@ -193,70 +154,37 @@ public class ZipReader implements Closeable { * @throws IORuntimeException IO异常 */ public ZipReader read(final Consumer consumer) throws IORuntimeException { - if (null != this.zipFile) { - readFromZipFile(consumer); - } else { - readFromStream(consumer); - } + resource.read(consumer, this.maxSizeDiff); return this; } @Override public void close() throws IORuntimeException { - if (null != this.zipFile) { - IoUtil.closeQuietly(this.zipFile); + IoUtil.closeQuietly(this.resource); + } + + /** + * 读取一个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 { - IoUtil.closeQuietly(this.in); + // 文件 + FileUtil.writeFromStream(this.resource.get(zipEntry), outItemFile, false); } } - - /** - * 读取并处理Zip文件中的每一个{@link ZipEntry} - * - * @param consumer {@link ZipEntry}处理器 - */ - private void readFromZipFile(final Consumer consumer) { - final Enumeration 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 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; - } } diff --git a/hutool-core/src/main/java/cn/hutool/core/compress/ZipResource.java b/hutool-core/src/main/java/cn/hutool/core/compress/ZipResource.java new file mode 100644 index 000000000..a93c00bbc --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/compress/ZipResource.java @@ -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 consumer, final int maxSizeDiff); + + /** + * 获取指定路径的文件流
+ * 如果是文件模式,则直接获取Entry对应的流,如果是流模式,则遍历entry后,找到对应流返回 + * + * @param path 路径 + * @return 文件流 + */ + InputStream get(String path); + + /** + * 获取指定{@link ZipEntry}对应的文件流 + * + * @param entry @link ZipEntry} + * @return 文件流 + */ + InputStream get(ZipEntry entry); +} diff --git a/hutool-core/src/main/java/cn/hutool/core/compress/ZipSecurityUtil.java b/hutool-core/src/main/java/cn/hutool/core/compress/ZipSecurityUtil.java new file mode 100644 index 000000000..2fb488896 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/compress/ZipSecurityUtil.java @@ -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; + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/compress/ZipStreamResource.java b/hutool-core/src/main/java/cn/hutool/core/compress/ZipStreamResource.java new file mode 100644 index 000000000..06853af74 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/compress/ZipStreamResource.java @@ -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 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); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/compress/ZipUtil.java b/hutool-core/src/main/java/cn/hutool/core/compress/ZipUtil.java index 11d1b6d84..1337a6bd3 100644 --- a/hutool-core/src/main/java/cn/hutool/core/compress/ZipUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/compress/ZipUtil.java @@ -794,7 +794,7 @@ public class ZipUtil { * @return 解压后的字符串 * @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); } @@ -915,7 +915,7 @@ public class ZipUtil { * @return 解压后的字符串 * @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); } diff --git a/hutool-core/src/main/java/cn/hutool/core/compress/ZipWriter.java b/hutool-core/src/main/java/cn/hutool/core/compress/ZipWriter.java index cc49e5bb8..9f23eb88e 100755 --- a/hutool-core/src/main/java/cn/hutool/core/compress/ZipWriter.java +++ b/hutool-core/src/main/java/cn/hutool/core/compress/ZipWriter.java @@ -292,8 +292,9 @@ public class ZipWriter implements Closeable { * @throws IORuntimeException IO异常 */ private ZipWriter putEntry(final String path, final InputStream in) throws IORuntimeException { + final ZipEntry entry = new ZipEntry(path); try { - out.putNextEntry(new ZipEntry(path)); + out.putNextEntry(entry); if (null != in) { IoUtil.copy(in, out); } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/NioUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/NioUtil.java index 6b647dc38..44c8aa00e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/NioUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/NioUtil.java @@ -204,18 +204,6 @@ public class NioUtil { 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中读取内容 * diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/FileUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/file/FileUtil.java index cea9ecdc4..cf44bb63f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/file/FileUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/file/FileUtil.java @@ -29,7 +29,10 @@ import cn.hutool.core.regex.ReUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.split.SplitUtil; 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.net.URI; @@ -137,6 +140,7 @@ public class FileUtil extends PathUtil { return isDirEmpty(dir.toPath()); } + // region ----- loop and walk /** * 递归遍历目录以及子目录中的所有文件
* 如果提供file为文件,直接返回过滤结果 @@ -265,6 +269,7 @@ public class FileUtil extends PathUtil { IoUtil.closeQuietly(jarFile); } } + // endregion // region ----- file and newFile /** @@ -1707,20 +1712,6 @@ public class FileUtil extends PathUtil { return readLines(path, CharsetUtil.UTF_8, collection); } - /** - * 从文件中读取每一行数据 - * - * @param 集合类型 - * @param path 文件路径 - * @param charset 字符集 - * @param collection 集合 - * @return 文件中的每行内容的集合 - * @throws IORuntimeException IO异常 - */ - public static > 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); } - /** - * 从文件中读取每一行数据 - * - * @param 集合类型 - * @param file 文件路径 - * @param charset 字符集 - * @param collection 集合 - * @return 文件中的每行内容的集合 - * @throws IORuntimeException IO异常 - */ - public static > 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); } - /** - * 从文件中读取每一行数据 - * - * @param path 文件路径 - * @param charset 字符集 - * @return 文件中的每行内容的集合List - * @throws IORuntimeException IO异常 - */ - public static List 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); } - /** - * 从文件中读取每一行数据 - * - * @param file 文件 - * @param charset 字符集 - * @return 文件中的每行内容的集合List - * @throws IORuntimeException IO异常 - */ - public static List 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); } - /** - * 将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写入文件,覆盖模式 * @@ -2202,19 +2142,6 @@ public class FileUtil extends PathUtil { 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写入文件,覆盖模式 * @@ -2241,19 +2168,6 @@ public class FileUtil extends PathUtil { 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写入文件,追加模式 * @@ -2280,19 +2194,6 @@ public class FileUtil extends PathUtil { 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写入文件,追加模式 * @@ -2334,20 +2235,6 @@ public class FileUtil extends PathUtil { return writeLines(list, file, CharsetUtil.UTF_8); } - /** - * 将列表写入文件,覆盖模式 - * - * @param 集合元素类型 - * @param list 列表 - * @param path 绝对路径 - * @param charset 字符集 - * @return 目标文件 - * @throws IORuntimeException IO异常 - */ - public static File writeLines(final Collection 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); } - /** - * 将列表写入文件,覆盖模式 - * - * @param 集合元素类型 - * @param list 列表 - * @param file 文件 - * @param charset 字符集 - * @return 目标文件 - * @throws IORuntimeException IO异常 - * @since 4.2.0 - */ - public static File writeLines(final Collection 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); } - /** - * 将列表写入文件,追加模式 - * - * @param 集合元素类型 - * @param list 列表 - * @param path 绝对路径 - * @param charset 字符集 - * @return 目标文件 - * @throws IORuntimeException IO异常 - */ - public static File appendLines(final Collection list, final String path, final String charset) throws IORuntimeException { - return writeLines(list, path, charset, true); - } - - /** - * 将列表写入文件,追加模式 - * - * @param 集合元素类型 - * @param list 列表 - * @param file 文件 - * @param charset 字符集 - * @return 目标文件 - * @throws IORuntimeException IO异常 - * @since 3.1.2 - */ - public static File appendLines(final Collection 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); } - /** - * 将列表写入文件 - * - * @param 集合元素类型 - * @param list 列表 - * @param path 文件路径 - * @param charset 字符集 - * @param isAppend 是否追加 - * @return 目标文件 - * @throws IORuntimeException IO异常 - */ - public static File writeLines(final Collection 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); } - /** - * 将列表写入文件 - * - * @param 集合元素类型 - * @param list 列表 - * @param file 文件 - * @param charset 字符集 - * @param isAppend 是否追加 - * @return 目标文件 - * @throws IORuntimeException IO异常 - */ - public static File writeLines(final Collection list, final File file, final String charset, final boolean isAppend) throws IORuntimeException { - return FileWriter.of(file, CharsetUtil.charset(charset)).writeLines(list, isAppend); - } - /** * 将列表写入文件 * diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/FileWriter.java b/hutool-core/src/main/java/cn/hutool/core/io/file/FileWriter.java index 5d2a2c3c8..4dab0c4f8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/file/FileWriter.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/file/FileWriter.java @@ -74,16 +74,6 @@ public class FileWriter extends FileWrapper { checkFile(); } - /** - * 构造 - * - * @param file 文件 - * @param charset 编码,使用 {@link CharsetUtil#charset(String)} - */ - public FileWriter(final File file, final String charset) { - this(file, CharsetUtil.charset(charset)); - } - /** * 构造 * diff --git a/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java b/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java index 30ad2c764..b83133fab 100755 --- a/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java @@ -1285,8 +1285,12 @@ public class MapUtil extends MapGetUtil { if (JdkUtil.IS_JDK8) { V value = map.get(key); if (null == value) { - //map.putIfAbsent(key, mappingFunction.apply(key)); - value = map.computeIfAbsent(key, mappingFunction); + map.putIfAbsent(key, mappingFunction.apply(key)); + value = map.get(key); + + // 判空后调用依旧无法解决死循环问题 + // 见:Issue2349Test + //value = map.computeIfAbsent(key, mappingFunction); } return value; } else { diff --git a/hutool-core/src/main/java/cn/hutool/core/map/SafeConcurrentHashMap.java b/hutool-core/src/main/java/cn/hutool/core/map/SafeConcurrentHashMap.java index 891af958a..5333b22d8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/SafeConcurrentHashMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/SafeConcurrentHashMap.java @@ -12,6 +12,8 @@ package cn.hutool.core.map; +import cn.hutool.core.util.JdkUtil; + import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; @@ -43,7 +45,7 @@ public class SafeConcurrentHashMap extends ConcurrentHashMap { * * @param initialCapacity 预估初始大小 */ - public SafeConcurrentHashMap(int initialCapacity) { + public SafeConcurrentHashMap(final int initialCapacity) { super(initialCapacity); } @@ -52,7 +54,7 @@ public class SafeConcurrentHashMap extends ConcurrentHashMap { * * @param m 初始键值对 */ - public SafeConcurrentHashMap(Map m) { + public SafeConcurrentHashMap(final Map m) { super(m); } @@ -62,7 +64,7 @@ public class SafeConcurrentHashMap extends ConcurrentHashMap { * @param initialCapacity 初始容量 * @param loadFactor 增长系数 */ - public SafeConcurrentHashMap(int initialCapacity, float loadFactor) { + public SafeConcurrentHashMap(final int initialCapacity, final float loadFactor) { super(initialCapacity, loadFactor); } @@ -73,14 +75,27 @@ public class SafeConcurrentHashMap extends ConcurrentHashMap { * @param loadFactor 增长系数 * @param concurrencyLevel 并发级别,即Segment的个数 */ - public SafeConcurrentHashMap(int initialCapacity, - float loadFactor, int concurrencyLevel) { + public SafeConcurrentHashMap(final int initialCapacity, + final float loadFactor, final int concurrencyLevel) { super(initialCapacity, loadFactor, concurrencyLevel); } // endregion == 构造 == @Override - public V computeIfAbsent(K key, Function mappingFunction) { - return MapUtil.computeIfAbsent(this, key, mappingFunction); + public V computeIfAbsent(final K key, final Function 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); + } } } diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQueryUtil.java b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQueryUtil.java index 96b632859..3883f4730 100755 --- a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQueryUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQueryUtil.java @@ -191,17 +191,6 @@ public class UrlQueryUtil { return Convert.toMap(String.class, String.class, queryMap); } - /** - * 将URL参数解析为Map(也可以解析Post中的键值对参数) - * - * @param paramsStr 参数字符串(或者带参数的Path) - * @param charset 字符集 - * @return 参数Map - */ - public static Map> decodeQuery(final String paramsStr, final String charset) { - return decodeQueryList(paramsStr, CharsetUtil.charset(charset)); - } - /** * 将URL参数解析为Map(也可以解析Post中的键值对参数) * diff --git a/hutool-core/src/main/java/cn/hutool/core/text/StrUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/StrUtil.java index 1fd2c5248..e78da5f1f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/StrUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/StrUtil.java @@ -164,17 +164,6 @@ public class StrUtil extends CharSequenceUtil implements StrPool { 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)); - } - /** * 解码字节码 * diff --git a/hutool-core/src/test/java/cn/hutool/core/compress/Issue3018Test.java b/hutool-core/src/test/java/cn/hutool/core/compress/Issue3018Test.java new file mode 100644 index 000000000..53f386243 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/compress/Issue3018Test.java @@ -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"); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/net/url/UrlQueryUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/net/url/UrlQueryUtilTest.java index 30417bf86..ad8526663 100755 --- a/hutool-core/src/test/java/cn/hutool/core/net/url/UrlQueryUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/url/UrlQueryUtilTest.java @@ -11,7 +11,7 @@ public class UrlQueryUtilTest { @Test public void decodeQueryTest() { final String paramsStr = "uuuu=0&a=b&c=%3F%23%40!%24%25%5E%26%3Ddsssss555555"; - final Map> map = UrlQueryUtil.decodeQuery(paramsStr, CharsetUtil.NAME_UTF_8); + final Map> map = UrlQueryUtil.decodeQueryList(paramsStr, CharsetUtil.UTF_8); Assertions.assertEquals("0", map.get("uuuu").get(0)); Assertions.assertEquals("b", map.get("a").get(0)); Assertions.assertEquals("?#@!$%^&=dsssss555555", map.get("c").get(0)); @@ -28,7 +28,7 @@ public class UrlQueryUtilTest { @Test public void toQueryTest() { final String paramsStr = "uuuu=0&a=b&c=3Ddsssss555555"; - final Map> map = UrlQueryUtil.decodeQuery(paramsStr, CharsetUtil.NAME_UTF_8); + final Map> map = UrlQueryUtil.decodeQueryList(paramsStr, CharsetUtil.UTF_8); final String encodedParams = UrlQueryUtil.toQuery(map); Assertions.assertEquals(paramsStr, encodedParams); @@ -91,41 +91,41 @@ public class UrlQueryUtilTest { public void decodeParamTest() { // 开头的?被去除 String a = "?a=b&c=d&"; - Map> map = UrlQueryUtil.decodeQuery(a, CharsetUtil.NAME_UTF_8); + Map> map = UrlQueryUtil.decodeQueryList(a, CharsetUtil.UTF_8); Assertions.assertEquals("b", map.get("a").get(0)); Assertions.assertEquals("d", map.get("c").get(0)); // =e被当作空为key,e为value 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("d", map.get("c").get(0)); Assertions.assertEquals("e", map.get("").get(0)); // 多余的&去除 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("d", map.get("c").get(0)); Assertions.assertEquals("e", map.get("").get(0)); // 值为空 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("d", map.get("c").get(0)); Assertions.assertEquals("", map.get("e").get(0)); // &=被作为键和值都为空 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("d", map.get("c").get(0)); Assertions.assertEquals("", map.get("").get(0)); // &e&这类单独的字符串被当作key 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("d", map.get("c").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="; - 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("你好", map.get("c").get(0)); Assertions.assertEquals("", map.get("哈喽").get(0)); diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml index eb74276f9..5f1fd8bfd 100755 --- a/hutool-extra/pom.xml +++ b/hutool-extra/pom.xml @@ -43,7 +43,6 @@ 3.5.1 3.9.0 5.1.1 - 4.0.1 2.7.5 3.3.0 @@ -64,21 +63,6 @@ hutool-setting ${project.parent.version} - - javax.servlet - javax.servlet-api - ${servlet-api.version} - provided - true - - - jakarta.servlet - jakarta.servlet-api - - 5.0.0 - provided - true - diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml index 333fb97bf..39d26abc5 100755 --- a/hutool-http/pom.xml +++ b/hutool-http/pom.xml @@ -50,6 +50,21 @@ provided + + + javax.servlet + javax.servlet-api + 4.0.1 + true + + + jakarta.servlet + jakarta.servlet-api + + 5.0.0 + true + + org.apache.httpcomponents.client5 diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/JakartaServletUtil.java b/hutool-http/src/main/java/cn/hutool/http/server/servlet/JakartaServletUtil.java old mode 100755 new mode 100644 similarity index 96% rename from hutool-extra/src/main/java/cn/hutool/extra/servlet/JakartaServletUtil.java rename to hutool-http/src/main/java/cn/hutool/http/server/servlet/JakartaServletUtil.java index 7c26fdeb3..2d614e9a4 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/JakartaServletUtil.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/servlet/JakartaServletUtil.java @@ -10,7 +10,7 @@ * 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.copier.CopyOptions; @@ -33,6 +33,7 @@ import cn.hutool.core.array.ArrayUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.ObjUtil; +import cn.hutool.http.meta.Method; import jakarta.servlet.ServletOutputStream; import jakarta.servlet.ServletRequest; import jakarta.servlet.http.Cookie; @@ -66,14 +67,6 @@ import java.util.Map; */ 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 /** @@ -373,18 +366,6 @@ public class JakartaServletUtil { 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中的信息 * @@ -425,7 +406,7 @@ public class JakartaServletUtil { * @return 是否为GET请求 */ 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请求 */ public static boolean isPostMethod(final HttpServletRequest request) { - return METHOD_POST.equalsIgnoreCase(request.getMethod()); + return Method.POST.name().equalsIgnoreCase(request.getMethod()); } /** diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java b/hutool-http/src/main/java/cn/hutool/http/server/servlet/ServletUtil.java old mode 100755 new mode 100644 similarity index 97% rename from hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java rename to hutool-http/src/main/java/cn/hutool/http/server/servlet/ServletUtil.java index 0bdfe0211..e7ca499cc --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/servlet/ServletUtil.java @@ -10,7 +10,7 @@ * 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.copier.CopyOptions; @@ -32,6 +32,7 @@ import cn.hutool.core.text.StrUtil; import cn.hutool.core.array.ArrayUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.ObjUtil; +import cn.hutool.http.meta.Method; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; @@ -65,14 +66,6 @@ import java.util.Map; */ 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 /** @@ -424,7 +417,7 @@ public class ServletUtil { * @return 是否为GET请求 */ 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请求 */ public static boolean isPostMethod(final HttpServletRequest request) { - return METHOD_POST.equalsIgnoreCase(request.getMethod()); + return Method.POST.name().equalsIgnoreCase(request.getMethod()); } /** diff --git a/hutool-http/src/main/java/cn/hutool/http/server/servlet/package-info.java b/hutool-http/src/main/java/cn/hutool/http/server/servlet/package-info.java new file mode 100644 index 000000000..d8edece20 --- /dev/null +++ b/hutool-http/src/main/java/cn/hutool/http/server/servlet/package-info.java @@ -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; diff --git a/hutool-extra/src/test/java/cn/hutool/extra/servlet/ServletUtilTest.java b/hutool-http/src/test/java/cn/hutool/http/server/servlet/ServletUtilTest.java old mode 100755 new mode 100644 similarity index 75% rename from hutool-extra/src/test/java/cn/hutool/extra/servlet/ServletUtilTest.java rename to hutool-http/src/test/java/cn/hutool/http/server/servlet/ServletUtilTest.java index c311dbbcf..8aa813bf1 --- a/hutool-extra/src/test/java/cn/hutool/extra/servlet/ServletUtilTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/server/servlet/ServletUtilTest.java @@ -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 org.junit.jupiter.api.Disabled;