From 6b13cb5263efdf65adee18744f8f07e9604fae71 Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 4 Apr 2020 00:50:44 +0800 Subject: [PATCH] prepare 5.3.0 --- CHANGELOG.md | 3 + README.md | 10 +- bin/version.txt | 2 +- docs/js/version.js | 2 +- hutool-all/pom.xml | 2 +- hutool-aop/pom.xml | 2 +- hutool-bloomFilter/pom.xml | 2 +- hutool-bom/pom.xml | 2 +- hutool-cache/pom.xml | 2 +- hutool-captcha/pom.xml | 2 +- hutool-core/pom.xml | 2 +- .../java/cn/hutool/core/codec/Base64.java | 14 +- .../main/java/cn/hutool/core/map/BiMap.java | 71 ++++++++++ .../main/java/cn/hutool/core/map/MapUtil.java | 20 +++ .../java/cn/hutool/core/map/TableMap.java | 24 ++-- .../core/map/multi/CollectionValueMap.java | 12 +- .../hutool/core/map/multi/ListValueMap.java | 4 +- .../cn/hutool/core/map/multi/SetValueMap.java | 4 +- .../net}/multipart/MultipartFormData.java | 25 +--- .../MultipartRequestInputStream.java | 39 ++++-- .../core/net}/multipart/UploadFile.java | 49 ++++--- .../core/net}/multipart/UploadFileHeader.java | 2 +- .../core/net}/multipart/UploadSetting.java | 18 +-- .../core/net/multipart/package-info.java | 7 + .../java/cn/hutool/core/util/CharsetUtil.java | 13 +- hutool-cron/pom.xml | 2 +- hutool-crypto/pom.xml | 2 +- hutool-db/pom.xml | 2 +- hutool-dfa/pom.xml | 2 +- hutool-extra/pom.xml | 2 +- .../cn/hutool/extra/servlet/ServletUtil.java | 6 +- .../extra/servlet/multipart/package-info.java | 7 - hutool-http/pom.xml | 2 +- .../main/java/cn/hutool/http/ContentType.java | 26 +++- .../main/java/cn/hutool/http/HttpUtil.java | 50 +++++-- .../cn/hutool/http/server/HttpServerBase.java | 5 + .../hutool/http/server/HttpServerRequest.java | 120 +++++++++++++---- .../http/server/HttpServerResponse.java | 126 ++++++++++++++++-- .../cn/hutool/http/server/SimpleServer.java | 7 +- .../hutool/http/server/action/RootAction.java | 62 +++++++++ .../http/server/handler/ActionHandler.java | 5 +- .../http/server/handler/HandlerUtil.java | 91 ------------- .../http/server/handler/RootHandler.java | 45 ------- .../hutool/http/server/SimpleServerTest.java | 14 +- .../cn/hutool/http/test/HttpUtilTest.java | 25 ++-- hutool-json/pom.xml | 2 +- hutool-log/pom.xml | 2 +- hutool-poi/pom.xml | 2 +- hutool-script/pom.xml | 2 +- hutool-setting/pom.xml | 2 +- hutool-socket/pom.xml | 2 +- hutool-system/pom.xml | 2 +- pom.xml | 2 +- 53 files changed, 619 insertions(+), 331 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/map/BiMap.java rename {hutool-extra/src/main/java/cn/hutool/extra/servlet => hutool-core/src/main/java/cn/hutool/core/net}/multipart/MultipartFormData.java (86%) rename {hutool-extra/src/main/java/cn/hutool/extra/servlet => hutool-core/src/main/java/cn/hutool/core/net}/multipart/MultipartRequestInputStream.java (84%) rename {hutool-extra/src/main/java/cn/hutool/extra/servlet => hutool-core/src/main/java/cn/hutool/core/net}/multipart/UploadFile.java (89%) rename {hutool-extra/src/main/java/cn/hutool/extra/servlet => hutool-core/src/main/java/cn/hutool/core/net}/multipart/UploadFileHeader.java (94%) rename {hutool-extra/src/main/java/cn/hutool/extra/servlet => hutool-core/src/main/java/cn/hutool/core/net}/multipart/UploadSetting.java (94%) create mode 100644 hutool-core/src/main/java/cn/hutool/core/net/multipart/package-info.java delete mode 100644 hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/package-info.java create mode 100644 hutool-http/src/main/java/cn/hutool/http/server/action/RootAction.java delete mode 100644 hutool-http/src/main/java/cn/hutool/http/server/handler/HandlerUtil.java delete mode 100644 hutool-http/src/main/java/cn/hutool/http/server/handler/RootHandler.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 80db6fe1e..52348afe1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,9 +18,12 @@ * 【core 】 CollUtil增加toMap方法 * 【core 】 CollUtil和IterUtil废弃一些方法 * 【core 】 添加ValidateObjectInputStream避免对象反序列化漏洞风险 +* 【core 】 添加BiMap +* 【all 】 cn.hutool.extra.servlet.multipart包迁移到cn.hutool.core.net下 ### Bug修复 * 【extra 】 修复SpringUtil使用devtools重启报错问题 +* 【http 】 修复HttpUtil.encodeParams针对无参数URL问题(issue#817@Github) ------------------------------------------------------------------------------------------------------------- diff --git a/README.md b/README.md index bf9a22421..1349f9835 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ -- 主页:https://hutool.cn/ | https://www.hutool.club/ --

- -- QQ群③:555368316 -- + -- QQ群③:555368316 -- -- QQ群④:718802356 --

@@ -116,21 +116,21 @@ Hutool的存在就是为了减少代码搜索成本,避免网络上参差不 cn.hutool hutool-all - 5.2.6 + 5.3.0 ``` ### Gradle ``` -compile 'cn.hutool:hutool-all:5.2.6' +compile 'cn.hutool:hutool-all:5.3.0' ``` ### 非Maven项目 点击以下任一链接,下载`hutool-all-X.X.X.jar`即可: -- [Maven中央库1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.2.6/) -- [Maven中央库2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.2.6/) +- [Maven中央库1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.3.0/) +- [Maven中央库2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.3.0/) > 注意 > Hutool 5.x支持JDK8+,对Android平台没有测试,不能保证所有工具类获工具方法可用。 diff --git a/bin/version.txt b/bin/version.txt index a944d7e61..03f488b07 100755 --- a/bin/version.txt +++ b/bin/version.txt @@ -1 +1 @@ -5.2.6 +5.3.0 diff --git a/docs/js/version.js b/docs/js/version.js index b5a3cc686..2f0178e29 100644 --- a/docs/js/version.js +++ b/docs/js/version.js @@ -1 +1 @@ -var version = '5.2.6' \ No newline at end of file +var version = '5.3.0' \ No newline at end of file diff --git a/hutool-all/pom.xml b/hutool-all/pom.xml index 0d5f10848..78044e36e 100644 --- a/hutool-all/pom.xml +++ b/hutool-all/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-all diff --git a/hutool-aop/pom.xml b/hutool-aop/pom.xml index 3c011fb9a..bb9458001 100644 --- a/hutool-aop/pom.xml +++ b/hutool-aop/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-aop diff --git a/hutool-bloomFilter/pom.xml b/hutool-bloomFilter/pom.xml index e7bf57f83..e885cda8f 100644 --- a/hutool-bloomFilter/pom.xml +++ b/hutool-bloomFilter/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-bloomFilter diff --git a/hutool-bom/pom.xml b/hutool-bom/pom.xml index 403ddad61..67a2c345b 100644 --- a/hutool-bom/pom.xml +++ b/hutool-bom/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-bom diff --git a/hutool-cache/pom.xml b/hutool-cache/pom.xml index 008e8704e..82467a4a7 100644 --- a/hutool-cache/pom.xml +++ b/hutool-cache/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-cache diff --git a/hutool-captcha/pom.xml b/hutool-captcha/pom.xml index 0f9c30525..98c2d9dad 100644 --- a/hutool-captcha/pom.xml +++ b/hutool-captcha/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-captcha diff --git a/hutool-core/pom.xml b/hutool-core/pom.xml index 94bd039cc..68a16cf32 100644 --- a/hutool-core/pom.xml +++ b/hutool-core/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-core diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Base64.java b/hutool-core/src/main/java/cn/hutool/core/codec/Base64.java index d796f882b..979b568c8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/Base64.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/Base64.java @@ -1,14 +1,14 @@ package cn.hutool.core.codec; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.CharsetUtil; + import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.CharsetUtil; - /** * Base64工具类,提供Base64的编码和解码方案
* base64编码是用64(2的6次方)个ASCII字符来表示256(2的8次方)个ASCII字符,
@@ -72,7 +72,7 @@ public class Base64 { * @return 被加密后的字符串 */ public static String encode(CharSequence source, String charset) { - return Base64Encoder.encode(source, CharsetUtil.charset(charset)); + return encode(source, CharsetUtil.charset(charset)); } /** @@ -84,7 +84,7 @@ public class Base64 { * @since 3.0.6 */ public static String encodeUrlSafe(CharSequence source, String charset) { - return Base64Encoder.encodeUrlSafe(source, CharsetUtil.charset(charset)); + return encodeUrlSafe(source, CharsetUtil.charset(charset)); } /** @@ -272,7 +272,7 @@ public class Base64 { * @return 被加密后的字符串 */ public static String decodeStr(CharSequence source, String charset) { - return Base64Decoder.decodeStr(source, CharsetUtil.charset(charset)); + return decodeStr(source, CharsetUtil.charset(charset)); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/map/BiMap.java b/hutool-core/src/main/java/cn/hutool/core/map/BiMap.java new file mode 100644 index 000000000..9680675a6 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/map/BiMap.java @@ -0,0 +1,71 @@ +package cn.hutool.core.map; + +import java.util.Map; + +/** + * 双向Map
+ * 互换键值对不检查值是否有重复,如果有则后加入的元素替换先加入的元素
+ * 值的顺序在HashMap中不确定,所以谁覆盖谁也不确定,在有序的Map中按照先后顺序覆盖,保留最后的值
+ * 它与TableMap的区别是,BiMap维护两个Map实现高效的正向和反向查找 + * + * @param 键类型 + * @param 值类型 + * @since 5.2.6 + */ +public class BiMap extends MapWrapper { + + private Map inverse; + + /** + * 构造 + * + * @param raw 被包装的Map + */ + public BiMap(Map raw) { + super(raw); + } + + @Override + public V put(K key, V value) { + if (null != this.inverse) { + this.inverse.put(value, key); + } + return super.put(key, value); + } + + @Override + public void putAll(Map m) { + super.putAll(m); + if (null != this.inverse) { + m.forEach((key, value) -> this.inverse.put(value, key)); + } + } + + @Override + public void clear() { + super.clear(); + this.inverse = null; + } + + /** + * 获取反向Map + * + * @return 反向Map + */ + public Map getInverse() { + if (null == this.inverse) { + inverse = MapUtil.inverse(getRaw()); + } + return this.inverse; + } + + /** + * 根据值获得键 + * + * @param value 值 + * @return 键 + */ + public K getKey(V value) { + return getInverse().get(value); + } +} 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 39199103b..256b3d346 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java @@ -681,11 +681,14 @@ public class MapUtil { /** * Map的键和值互换 + * 互换键值对不检查值是否有重复,如果有则后加入的元素替换先加入的元素
+ * 值的顺序在HashMap中不确定,所以谁覆盖谁也不确定,在有序的Map中按照先后顺序覆盖,保留最后的值 * * @param 键和值类型 * @param map Map对象,键值类型必须一致 * @return 互换后的Map * @since 3.2.2 + * @see #inverse(Map) */ public static Map reverse(Map map) { return filter(map, (Editor>) t -> new Entry() { @@ -707,6 +710,23 @@ public class MapUtil { }); } + /** + * Map的键和值互换
+ * 互换键值对不检查值是否有重复,如果有则后加入的元素替换先加入的元素
+ * 值的顺序在HashMap中不确定,所以谁覆盖谁也不确定,在有序的Map中按照先后顺序覆盖,保留最后的值 + * + * @param 键和值类型 + * @param 键和值类型 + * @param map Map对象,键值类型必须一致 + * @return 互换后的Map + * @since 5.2.6 + */ + public static Map inverse(Map map) { + final Map result = createMap(map.getClass()); + map.forEach((key, value) -> result.put(value, key)); + return result; + } + /** * 排序已有Map,Key有序的Map,使用默认Key排序方式(字母顺序) * diff --git a/hutool-core/src/main/java/cn/hutool/core/map/TableMap.java b/hutool-core/src/main/java/cn/hutool/core/map/TableMap.java index b80ec2ed0..9190bec43 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/TableMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/TableMap.java @@ -16,12 +16,13 @@ import java.util.Objects; import java.util.Set; /** - * 可重复键的Map - * - * @author looly + * 可重复键和值的Map
+ * 通过键值单独建立List方式,使键值对一一对应,实现正向和反向两种查找
+ * 无论是正向还是反向,都是遍历列表查找过程,相比标准的HashMap要慢,数据越多越慢 * * @param 键类型 * @param 值类型 + * @author looly */ public class TableMap implements Map, Serializable { private static final long serialVersionUID = 1L; @@ -31,7 +32,7 @@ public class TableMap implements Map, Serializable { /** * 构造 - * + * * @param size 初始容量 */ public TableMap(int size) { @@ -41,8 +42,8 @@ public class TableMap implements Map, Serializable { /** * 构造 - * - * @param keys 键列表 + * + * @param keys 键列表 * @param values 值列表 */ public TableMap(K[] keys, V[] values) { @@ -89,10 +90,10 @@ public class TableMap implements Map, Serializable { * @return 值列表 * @since 5.2.5 */ - public List getValues(K key){ + public List getValues(K key) { return CollUtil.getAny( this.values, - ListUtil.indexOfAll(this.keys, (ele)-> ObjectUtil.equal(ele, key)) + ListUtil.indexOfAll(this.keys, (ele) -> ObjectUtil.equal(ele, key)) ); } @@ -103,10 +104,10 @@ public class TableMap implements Map, Serializable { * @return 值列表 * @since 5.2.5 */ - public List getKeys(V value){ + public List getKeys(V value) { return CollUtil.getAny( this.keys, - ListUtil.indexOfAll(this.values, (ele)-> ObjectUtil.equal(ele, value)) + ListUtil.indexOfAll(this.values, (ele) -> ObjectUtil.equal(ele, value)) ); } @@ -189,12 +190,13 @@ public class TableMap implements Map, Serializable { public V setValue(V value) { throw new UnsupportedOperationException("setValue not supported."); } + @Override public final boolean equals(Object o) { if (o == this) return true; if (o instanceof Map.Entry) { - Map.Entry e = (Map.Entry)o; + Map.Entry e = (Map.Entry) o; return Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue()); } diff --git a/hutool-core/src/main/java/cn/hutool/core/map/multi/CollectionValueMap.java b/hutool-core/src/main/java/cn/hutool/core/map/multi/CollectionValueMap.java index dab043fd2..64d1a47fe 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/multi/CollectionValueMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/multi/CollectionValueMap.java @@ -1,12 +1,12 @@ package cn.hutool.core.map.multi; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapWrapper; + import java.util.Collection; import java.util.HashMap; import java.util.Map; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.map.MapWrapper; - /** * 值作为集合的Map实现,通过调用putValue可以在相同key时加入多个值,多个值用集合表示 * @@ -67,7 +67,7 @@ public abstract class CollectionValueMap extends MapWrapper>(initialCapacity, loadFactor)); + super(new HashMap<>(initialCapacity, loadFactor)); } // ------------------------------------------------------------------------- Constructor end @@ -81,7 +81,7 @@ public abstract class CollectionValueMap extends MapWrapper collection = this.get(key); if (null == collection) { - collection = createCollction(); + collection = createCollection(); this.put(key, collection); } collection.add(value); @@ -105,5 +105,5 @@ public abstract class CollectionValueMap extends MapWrapper createCollction(); + protected abstract Collection createCollection(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/map/multi/ListValueMap.java b/hutool-core/src/main/java/cn/hutool/core/map/multi/ListValueMap.java index 72b705bbd..b7e908353 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/multi/ListValueMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/multi/ListValueMap.java @@ -62,7 +62,7 @@ public class ListValueMap extends CollectionValueMap { * @param loadFactor 加载因子 */ public ListValueMap(int initialCapacity, float loadFactor) { - super(new HashMap>(initialCapacity, loadFactor)); + super(new HashMap<>(initialCapacity, loadFactor)); } // ------------------------------------------------------------------------- Constructor end @@ -72,7 +72,7 @@ public class ListValueMap extends CollectionValueMap { } @Override - protected Collection createCollction() { + protected Collection createCollection() { return new ArrayList<>(DEFAULT_COLLCTION_INITIAL_CAPACITY); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/map/multi/SetValueMap.java b/hutool-core/src/main/java/cn/hutool/core/map/multi/SetValueMap.java index 52efdc4dc..a1e814bb4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/multi/SetValueMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/multi/SetValueMap.java @@ -62,7 +62,7 @@ public class SetValueMap extends CollectionValueMap { * @param loadFactor 加载因子 */ public SetValueMap(int initialCapacity, float loadFactor) { - super(new HashMap>(initialCapacity, loadFactor)); + super(new HashMap<>(initialCapacity, loadFactor)); } // ------------------------------------------------------------------------- Constructor end @@ -72,7 +72,7 @@ public class SetValueMap extends CollectionValueMap { } @Override - protected Collection createCollction() { + protected Collection createCollection() { return new LinkedHashSet<>(DEFAULT_COLLCTION_INITIAL_CAPACITY); } } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/MultipartFormData.java b/hutool-core/src/main/java/cn/hutool/core/net/multipart/MultipartFormData.java similarity index 86% rename from hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/MultipartFormData.java rename to hutool-core/src/main/java/cn/hutool/core/net/multipart/MultipartFormData.java index a7e32fe57..45f003980 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/MultipartFormData.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/multipart/MultipartFormData.java @@ -1,17 +1,16 @@ -package cn.hutool.extra.servlet.multipart; +package cn.hutool.core.net.multipart; + +import cn.hutool.core.util.ArrayUtil; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.Charset; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; -import javax.servlet.ServletRequest; - -import cn.hutool.core.util.ArrayUtil; - /** * HttpRequest解析器
* 来自Jodd @@ -21,9 +20,9 @@ import cn.hutool.core.util.ArrayUtil; public class MultipartFormData { /** 请求参数 */ - private Map requestParameters = new HashMap(); + private Map requestParameters = new HashMap<>(); /** 请求文件 */ - private Map requestFiles = new HashMap(); + private Map requestFiles = new HashMap<>(); /** 是否解析完毕 */ private boolean loaded; @@ -48,16 +47,6 @@ public class MultipartFormData { } // --------------------------------------------------------------------- Constructor end - /** - * 解析上传文件和表单数据 - * - * @param request Http请求 - * @throws IOException IO异常 - */ - public void parseRequest(ServletRequest request) throws IOException { - parseRequestStream(request.getInputStream(), request.getCharacterEncoding()); - } - /** * 提取上传的文件和表单数据 * @@ -65,7 +54,7 @@ public class MultipartFormData { * @param charset 编码 * @throws IOException IO异常 */ - public void parseRequestStream(InputStream inputStream, String charset) throws IOException { + public void parseRequestStream(InputStream inputStream, Charset charset) throws IOException { setLoaded(); MultipartRequestInputStream input = new MultipartRequestInputStream(inputStream); diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/MultipartRequestInputStream.java b/hutool-core/src/main/java/cn/hutool/core/net/multipart/MultipartRequestInputStream.java similarity index 84% rename from hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/MultipartRequestInputStream.java rename to hutool-core/src/main/java/cn/hutool/core/net/multipart/MultipartRequestInputStream.java index 65b35b648..8dc5df6b0 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/MultipartRequestInputStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/multipart/MultipartRequestInputStream.java @@ -1,15 +1,16 @@ -package cn.hutool.extra.servlet.multipart; +package cn.hutool.core.net.multipart; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.charset.Charset; /** * Http请求解析流,提供了专门针对带文件的form表单的解析
* 来自Jodd - * + * * @author jodd.org */ public class MultipartRequestInputStream extends BufferedInputStream { @@ -20,7 +21,7 @@ public class MultipartRequestInputStream extends BufferedInputStream { /** * 读取byte字节流,在末尾抛出异常 - * + * * @return byte * @throws IOException 读取异常 */ @@ -34,7 +35,7 @@ public class MultipartRequestInputStream extends BufferedInputStream { /** * 跳过指定位数的 bytes. - * + * * @param i 跳过的byte数 * @throws IOException IO异常 */ @@ -47,12 +48,14 @@ public class MultipartRequestInputStream extends BufferedInputStream { // ---------------------------------------------------------------- boundary - /** part部分边界 */ + /** + * part部分边界 + */ protected byte[] boundary; /** * 输入流中读取边界 - * + * * @return 边界 * @throws IOException 读取异常 */ @@ -60,6 +63,7 @@ public class MultipartRequestInputStream extends BufferedInputStream { ByteArrayOutputStream boundaryOutput = new ByteArrayOutputStream(1024); byte b; // skip optional whitespaces + //noinspection StatementWithEmptyBody while ((b = readByte()) <= ' ') { } boundaryOutput.write(b); @@ -89,12 +93,12 @@ public class MultipartRequestInputStream extends BufferedInputStream { /** * 从流中读取文件头部信息, 如果达到末尾则返回null - * + * * @param encoding 字符集 * @return 头部信息, 如果达到末尾则返回null * @throws IOException 读取异常 */ - public UploadFileHeader readDataHeader(String encoding) throws IOException { + public UploadFileHeader readDataHeader(Charset encoding) throws IOException { String dataHeader = readDataHeaderString(encoding); if (dataHeader != null) { lastHeader = new UploadFileHeader(dataHeader); @@ -104,7 +108,14 @@ public class MultipartRequestInputStream extends BufferedInputStream { return lastHeader; } - protected String readDataHeaderString(String encoding) throws IOException { + /** + * 读取数据头信息字符串 + * + * @param charset 编码 + * @return 数据头信息字符串 + * @throws IOException IO异常 + */ + protected String readDataHeaderString(Charset charset) throws IOException { ByteArrayOutputStream data = new ByteArrayOutputStream(); byte b; while (true) { @@ -128,13 +139,13 @@ public class MultipartRequestInputStream extends BufferedInputStream { data.write(b); } skipBytes(3); - return encoding == null ? data.toString() : data.toString(encoding); + return charset == null ? data.toString() : data.toString(charset.name()); } // ---------------------------------------------------------------- copy /** * 全部字节流复制到out - * + * * @param out 输出流 * @return 复制的字节数 * @throws IOException 读取异常 @@ -154,8 +165,8 @@ public class MultipartRequestInputStream extends BufferedInputStream { /** * 复制字节流到out, 大于maxBytes或者文件末尾停止 - * - * @param out 输出流 + * + * @param out 输出流 * @param limit 最大字节数 * @return 复制的字节数 * @throws IOException 读取异常 @@ -178,7 +189,7 @@ public class MultipartRequestInputStream extends BufferedInputStream { /** * 跳过边界表示 - * + * * @return 跳过的字节数 * @throws IOException 读取异常 */ diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadFile.java b/hutool-core/src/main/java/cn/hutool/core/net/multipart/UploadFile.java similarity index 89% rename from hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadFile.java rename to hutool-core/src/main/java/cn/hutool/core/net/multipart/UploadFile.java index 43f4f3884..5e0386603 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadFile.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/multipart/UploadFile.java @@ -1,4 +1,8 @@ -package cn.hutool.extra.servlet.multipart; +package cn.hutool.core.net.multipart; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -10,27 +14,18 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.log.Log; -import cn.hutool.log.LogFactory; - /** * 上传的文件对象 - * + * * @author xiaoleilu - * */ public class UploadFile { - private static Log log = LogFactory.get(); - private static final String TMP_FILE_PREFIX = "hutool-"; private static final String TMP_FILE_SUFFIX = ".upload.tmp"; private UploadFileHeader header; private UploadSetting setting; - + private int size = -1; // 文件流(小文件位于内存中) @@ -40,8 +35,8 @@ public class UploadFile { /** * 构造 - * - * @param header 头部信息 + * + * @param header 头部信息 * @param setting 上传设置 */ public UploadFile(UploadFileHeader header, UploadSetting setting) { @@ -56,6 +51,7 @@ public class UploadFile { */ public void delete() { if (tempFile != null) { + //noinspection ResultOfMethodCallIgnored tempFile.delete(); } if (data != null) { @@ -66,17 +62,18 @@ public class UploadFile { /** * 将上传的文件写入指定的目标文件路径,自动创建文件
* 写入后原临时文件会被删除 + * * @param destPath 目标文件路径 * @return 目标文件 * @throws IOException IO异常 */ public File write(String destPath) throws IOException { - if(data != null || tempFile != null) { + if (data != null || tempFile != null) { return write(FileUtil.touch(destPath)); } return null; } - + /** * 将上传的文件写入目标文件
* 写入后原临时文件会被删除 @@ -87,7 +84,7 @@ public class UploadFile { */ public File write(File destination) throws IOException { assertValid(); - + if (destination.isDirectory() == true) { destination = new File(destination, this.header.getFileName()); } @@ -101,14 +98,14 @@ public class UploadFile { } return destination; } - + /** * @return 获得文件字节流 * @throws IOException IO异常 */ public byte[] getFileContent() throws IOException { assertValid(); - + if (data != null) { return data; } @@ -124,7 +121,7 @@ public class UploadFile { */ public InputStream getFileInputStream() throws IOException { assertValid(); - + if (data != null) { return new BufferedInputStream(new ByteArrayInputStream(data)); } @@ -174,9 +171,10 @@ public class UploadFile { } // ---------------------------------------------------------------- process + /** * 处理上传表单流,提取出文件 - * + * * @param input 上传表单的流 * @return 是否成功 * @throws IOException IO异常 @@ -184,7 +182,6 @@ public class UploadFile { protected boolean processStream(MultipartRequestInputStream input) throws IOException { if (!isAllowedExtension()) { // 非允许的扩展名 - log.debug("Forbidden uploaded file [{}]", this.getFileName()); size = input.skipToBoundary(); return false; } @@ -220,9 +217,9 @@ public class UploadFile { size += input.copy(out, maxFileSize - size + 1); // one more byte to detect larger files if (size > maxFileSize) { // 超出上传大小限制 + //noinspection ResultOfMethodCallIgnored tempFile.delete(); tempFile = null; - log.debug("Upload file [{}] too big, file size > [{}]", this.getFileName(), maxFileSize); input.skipToBoundary(); return false; } @@ -236,6 +233,7 @@ public class UploadFile { } // ---------------------------------------------------------------------------- Private method start + /** * @return 是否为允许的扩展名 */ @@ -257,13 +255,14 @@ public class UploadFile { // 未匹配到扩展名,如果为允许列表,返回false, 否则true return !isAllow; } - + /** * 断言是否文件流可用 + * * @throws IOException IO异常 */ private void assertValid() throws IOException { - if(! isUploaded()) { + if (!isUploaded()) { throw new IOException(StrUtil.format("File [{}] upload fail", getFileName())); } } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadFileHeader.java b/hutool-core/src/main/java/cn/hutool/core/net/multipart/UploadFileHeader.java similarity index 94% rename from hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadFileHeader.java rename to hutool-core/src/main/java/cn/hutool/core/net/multipart/UploadFileHeader.java index b8b1a86ef..5c1770d9b 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadFileHeader.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/multipart/UploadFileHeader.java @@ -1,4 +1,4 @@ -package cn.hutool.extra.servlet.multipart; +package cn.hutool.core.net.multipart; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadSetting.java b/hutool-core/src/main/java/cn/hutool/core/net/multipart/UploadSetting.java similarity index 94% rename from hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadSetting.java rename to hutool-core/src/main/java/cn/hutool/core/net/multipart/UploadSetting.java index c75116c65..08e4dae05 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadSetting.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/multipart/UploadSetting.java @@ -1,4 +1,4 @@ -package cn.hutool.extra.servlet.multipart; +package cn.hutool.core.net.multipart; import cn.hutool.core.util.URLUtil; import cn.hutool.log.Log; @@ -8,7 +8,7 @@ import java.net.URL; /** * 上传文件设定文件 - * + * * @author xiaoleilu * */ @@ -42,7 +42,7 @@ public class UploadSetting { /** * 设定最大文件大小,-1表示无限制 - * + * * @param maxFileSize 最大文件大小 */ public void setMaxFileSize(int maxFileSize) { @@ -59,7 +59,7 @@ public class UploadSetting { /** * 设定文件保存到内存的边界
* 如果文件大小小于这个边界,将保存于内存中,否则保存至临时目录中 - * + * * @param memoryThreshold 文件保存到内存的边界 */ public void setMemoryThreshold(int memoryThreshold) { @@ -75,7 +75,7 @@ public class UploadSetting { /** * 设定上传文件的临时目录,null表示使用系统临时目录 - * + * * @param tmpUploadPath 临时目录,绝对路径 */ public void setTmpUploadPath(String tmpUploadPath) { @@ -92,7 +92,7 @@ public class UploadSetting { /** * 设定文件扩展名限定里列表
* 禁止列表还是允许列表取决于isAllowFileExts - * + * * @param fileExts 文件扩展名列表 */ public void setFileExts(String[] fileExts) { @@ -101,7 +101,7 @@ public class UploadSetting { /** * 是否允许文件扩展名
- * + * * @return 若true表示只允许列表里的扩展名,否则是禁止列表里的扩展名 */ public boolean isAllowFileExts() { @@ -110,7 +110,7 @@ public class UploadSetting { /** * 设定是否允许扩展名 - * + * * @param isAllowFileExts 若true表示只允许列表里的扩展名,否则是禁止列表里的扩展名 */ public void setAllowFileExts(boolean isAllowFileExts) { @@ -128,7 +128,7 @@ public class UploadSetting { /** * 加载全局设定 - * + * * @param settingPath 设定文件路径,相对Classpath */ synchronized public void load(String settingPath) { diff --git a/hutool-core/src/main/java/cn/hutool/core/net/multipart/package-info.java b/hutool-core/src/main/java/cn/hutool/core/net/multipart/package-info.java new file mode 100644 index 000000000..1056d3767 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/net/multipart/package-info.java @@ -0,0 +1,7 @@ +/** + * 文件上传封装 + * + * @author looly + * + */ +package cn.hutool.core.net.multipart; \ No newline at end of file diff --git a/hutool-core/src/main/java/cn/hutool/core/util/CharsetUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/CharsetUtil.java index c19de5d01..c6478af57 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/CharsetUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/CharsetUtil.java @@ -62,6 +62,17 @@ public class CharsetUtil { return StrUtil.isBlank(charsetName) ? Charset.defaultCharset() : Charset.forName(charsetName); } + /** + * 解析字符串编码为Charset对象,解析失败返回系统默认编码 + * + * @param charsetName 字符集,为空则返回默认字符集 + * @return Charset + * @since 5.2.6 + */ + public static Charset parse(String charsetName) { + return parse(charsetName, Charset.defaultCharset()); + } + /** * 解析字符串编码为Charset对象,解析失败返回默认编码 * @@ -70,7 +81,7 @@ public class CharsetUtil { * @return Charset * @since 5.2.6 */ - public static Charset parse(String charsetName, Charset defaultCharset) throws UnsupportedCharsetException { + public static Charset parse(String charsetName, Charset defaultCharset) { if (StrUtil.isBlank(charsetName)) { return defaultCharset; } diff --git a/hutool-cron/pom.xml b/hutool-cron/pom.xml index d7e2134a8..549c8c6da 100644 --- a/hutool-cron/pom.xml +++ b/hutool-cron/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-cron diff --git a/hutool-crypto/pom.xml b/hutool-crypto/pom.xml index ccdd83b22..35777df68 100644 --- a/hutool-crypto/pom.xml +++ b/hutool-crypto/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-crypto diff --git a/hutool-db/pom.xml b/hutool-db/pom.xml index 9860ff4a6..c378809a7 100644 --- a/hutool-db/pom.xml +++ b/hutool-db/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-db diff --git a/hutool-dfa/pom.xml b/hutool-dfa/pom.xml index 82e7f9473..eaa01abd2 100644 --- a/hutool-dfa/pom.xml +++ b/hutool-dfa/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-dfa diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml index 8f42d3959..0ab3cece5 100644 --- a/hutool-extra/pom.xml +++ b/hutool-extra/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-extra diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java index f91530be4..7004f45f3 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java @@ -11,14 +11,14 @@ import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.map.CaseInsensitiveMap; import cn.hutool.core.net.NetUtil; +import cn.hutool.core.net.multipart.MultipartFormData; +import cn.hutool.core.net.multipart.UploadSetting; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; -import cn.hutool.extra.servlet.multipart.MultipartFormData; -import cn.hutool.extra.servlet.multipart.UploadSetting; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; @@ -265,7 +265,7 @@ public class ServletUtil { public static MultipartFormData getMultipart(ServletRequest request, UploadSetting uploadSetting) throws IORuntimeException { final MultipartFormData formData = new MultipartFormData(uploadSetting); try { - formData.parseRequest(request); + formData.parseRequestStream(request.getInputStream(), request.getCharacterEncoding()); } catch (IOException e) { throw new IORuntimeException(e); } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/package-info.java b/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/package-info.java deleted file mode 100644 index 0328d88f6..000000000 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 基于Servlet的文件上传封装 - * - * @author looly - * - */ -package cn.hutool.extra.servlet.multipart; \ No newline at end of file diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml index 0086696a9..c0925f434 100644 --- a/hutool-http/pom.xml +++ b/hutool-http/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-http diff --git a/hutool-http/src/main/java/cn/hutool/http/ContentType.java b/hutool-http/src/main/java/cn/hutool/http/ContentType.java index 759cd7d92..b7398cd39 100644 --- a/hutool-http/src/main/java/cn/hutool/http/ContentType.java +++ b/hutool-http/src/main/java/cn/hutool/http/ContentType.java @@ -28,10 +28,18 @@ public enum ContentType { * Rest请求XML编码 */ XML("application/xml"), + /** + * text/plain编码 + */ + TEXT_PLAIN("text/plain"), /** * Rest请求text/xml编码 */ - TEXT_XML("text/xml"); + TEXT_XML("text/xml"), + /** + * text/html编码 + */ + TEXT_HTML("text/html"); private String value; @@ -39,9 +47,19 @@ public enum ContentType { this.value = value; } + /** + * 获取value值 + * + * @return value值 + * @since 5.2.6 + */ + public String getValue() { + return value; + } + @Override public String toString() { - return value; + return getValue(); } /** @@ -62,7 +80,7 @@ public enum ContentType { * @since 4.1.5 */ public static boolean isDefault(String contentType) { - return null == contentType || isFormUrlEncoed(contentType); + return null == contentType || isFormUrlEncode(contentType); } /** @@ -71,7 +89,7 @@ public enum ContentType { * @param contentType 内容类型 * @return 是否为application/x-www-form-urlencoded */ - public static boolean isFormUrlEncoed(String contentType) { + public static boolean isFormUrlEncode(String contentType) { return StrUtil.startWithIgnoreCase(contentType, FORM_URLENCODED.toString()); } diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java index 264e9c233..07bb0b8af 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java @@ -2,6 +2,7 @@ package cn.hutool.http; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.collection.IterUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.io.FastByteArrayOutputStream; import cn.hutool.core.io.FileUtil; @@ -416,7 +417,7 @@ public class HttpUtil { if (value instanceof Iterable) { value = CollUtil.join((Iterable) value, ","); } else if (value instanceof Iterator) { - value = CollUtil.join((Iterator) value, ","); + value = IterUtil.join((Iterator) value, ","); } valueStr = Convert.toStr(value); if (StrUtil.isNotEmpty(key)) { @@ -435,30 +436,33 @@ public class HttpUtil { * *

注意,此方法只能标准化整个URL,并不适合于单独编码参数值

* - * @param paramsStr url参数,可以包含url本身 + * @param urlWithParams url和参数,可以包含url本身,也可以单独参数 * @param charset 编码 * @return 编码后的url和参数 * @since 4.0.1 */ - public static String encodeParams(String paramsStr, Charset charset) { - if (StrUtil.isBlank(paramsStr)) { + public static String encodeParams(String urlWithParams, Charset charset) { + if (StrUtil.isBlank(urlWithParams)) { return StrUtil.EMPTY; } String urlPart = null; // url部分,不包括问号 String paramPart; // 参数部分 - int pathEndPos = paramsStr.indexOf('?'); + final int pathEndPos = urlWithParams.indexOf('?'); if (pathEndPos > -1) { // url + 参数 - urlPart = StrUtil.subPre(paramsStr, pathEndPos); - paramPart = StrUtil.subSuf(paramsStr, pathEndPos + 1); + urlPart = StrUtil.subPre(urlWithParams, pathEndPos); + paramPart = StrUtil.subSuf(urlWithParams, pathEndPos + 1); if (StrUtil.isBlank(paramPart)) { // 无参数,返回url return urlPart; } - } else { - // 无URL - paramPart = paramsStr; + } else if(false == StrUtil.contains(urlWithParams, '=')){ + // 无参数的URL + return urlWithParams; + }else { + // 无URL的参数 + paramPart = urlWithParams; } paramPart = normalizeParams(paramPart, charset); @@ -534,6 +538,18 @@ public class HttpUtil { * @since 4.0.2 */ public static HashMap decodeParamMap(String paramsStr, String charset) { + return decodeParamMap(paramsStr, CharsetUtil.charset(charset)); + } + + /** + * 将URL参数解析为Map(也可以解析Post中的键值对参数) + * + * @param paramsStr 参数字符串(或者带参数的Path) + * @param charset 字符集 + * @return 参数Map + * @since 5.2.6 + */ + public static HashMap decodeParamMap(String paramsStr, Charset charset) { final Map> paramsMap = decodeParams(paramsStr, charset); final HashMap result = MapUtil.newHashMap(paramsMap.size()); List valueList; @@ -552,6 +568,18 @@ public class HttpUtil { * @return 参数Map */ public static Map> decodeParams(String paramsStr, String charset) { + return decodeParams(paramsStr, CharsetUtil.charset(charset)); + } + + /** + * 将URL参数解析为Map(也可以解析Post中的键值对参数) + * + * @param paramsStr 参数字符串(或者带参数的Path) + * @param charset 字符集 + * @return 参数Map + * @since 5.2.6 + */ + public static Map> decodeParams(String paramsStr, Charset charset) { if (StrUtil.isBlank(paramsStr)) { return Collections.emptyMap(); } @@ -811,7 +839,7 @@ public class HttpUtil { * @param value value * @param charset 编码 */ - private static void addParam(Map> params, String name, String value, String charset) { + private static void addParam(Map> params, String name, String value, Charset charset) { name = URLUtil.decode(name, charset); value = URLUtil.decode(value, charset); final List values = params.computeIfAbsent(name, k -> new ArrayList<>(1)); diff --git a/hutool-http/src/main/java/cn/hutool/http/server/HttpServerBase.java b/hutool-http/src/main/java/cn/hutool/http/server/HttpServerBase.java index 5cf8ecb81..ff146ff89 100644 --- a/hutool-http/src/main/java/cn/hutool/http/server/HttpServerBase.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/HttpServerBase.java @@ -1,7 +1,10 @@ package cn.hutool.http.server; +import cn.hutool.core.util.CharsetUtil; import com.sun.net.httpserver.HttpExchange; +import java.nio.charset.Charset; + /** * HttpServer公用对象,提供HttpExchange包装和公用方法 * @@ -10,6 +13,8 @@ import com.sun.net.httpserver.HttpExchange; */ public class HttpServerBase { + final static Charset DEFAULT_CHARSET = CharsetUtil.CHARSET_UTF_8; + final HttpExchange httpExchange; /** diff --git a/hutool-http/src/main/java/cn/hutool/http/server/HttpServerRequest.java b/hutool-http/src/main/java/cn/hutool/http/server/HttpServerRequest.java index 1239b18cb..f7b14d5fd 100644 --- a/hutool-http/src/main/java/cn/hutool/http/server/HttpServerRequest.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/HttpServerRequest.java @@ -1,9 +1,13 @@ package cn.hutool.http.server; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.map.CaseInsensitiveMap; +import cn.hutool.core.map.multi.ListValueMap; import cn.hutool.core.net.NetUtil; +import cn.hutool.core.net.multipart.MultipartFormData; +import cn.hutool.core.net.multipart.UploadSetting; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; @@ -15,6 +19,7 @@ import cn.hutool.http.useragent.UserAgentUtil; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; +import java.io.IOException; import java.io.InputStream; import java.net.HttpCookie; import java.net.URI; @@ -32,6 +37,9 @@ import java.util.Map; public class HttpServerRequest extends HttpServerBase { private Map cookieCache; + private ListValueMap paramsCache; + private Charset charsetCache; + private byte[] bodyCache; /** * 构造 @@ -159,9 +167,13 @@ public class HttpServerRequest extends HttpServerBase { * @return 编码,默认UTF-8 */ public Charset getCharset() { - final String contentType = getContentType(); - final String charsetStr = HttpUtil.getCharset(contentType); - return CharsetUtil.parse(charsetStr, CharsetUtil.CHARSET_UTF_8); + if(null == this.charsetCache){ + final String contentType = getContentType(); + final String charsetStr = HttpUtil.getCharset(contentType); + this.charsetCache = CharsetUtil.parse(charsetStr, DEFAULT_CHARSET); + } + + return this.charsetCache; } /** @@ -226,12 +238,20 @@ public class HttpServerRequest extends HttpServerBase { } /** - * 获取请求体的流,流中可以读取请求内容,包括请求表单数据或文件上传数据 + * 是否为Multipart类型表单,此类型表单用于文件上传 * - * @return 流 + * @return 是否为Multipart类型表单,此类型表单用于文件上传 */ - public InputStream getBodyStream() { - return this.httpExchange.getRequestBody(); + public boolean isMultipart() { + if (false == isPostMethod()) { + return false; + } + + final String contentType = getContentType(); + if (StrUtil.isBlank(contentType)) { + return false; + } + return contentType.toLowerCase().startsWith("multipart/"); } /** @@ -251,31 +271,49 @@ public class HttpServerRequest extends HttpServerBase { * @return 请求 */ public String getBody(Charset charset) { - InputStream in = null; - try { - in = getBodyStream(); - return IoUtil.read(in, charset); - } finally { - IoUtil.close(in); - } + return StrUtil.str(getBodyBytes(), charset); } /** - * 是否为Multipart类型表单,此类型表单用于文件上传 + * 获取body的bytes数组 * - * @return 是否为Multipart类型表单,此类型表单用于文件上传 + * @return body的bytes数组 */ - public boolean isMultipart() { - if (false == isPostMethod()) { - return false; + public byte[] getBodyBytes(){ + if(null == this.bodyCache){ + this.bodyCache = IoUtil.readBytes(getBodyStream(), true); + } + return this.bodyCache; + } + + /** + * 获取请求体的流,流中可以读取请求内容,包括请求表单数据或文件上传数据 + * + * @return 流 + */ + public InputStream getBodyStream() { + return this.httpExchange.getRequestBody(); + } + + public ListValueMap getParams() { + if (null == this.paramsCache) { + this.paramsCache = new ListValueMap<>(); + final Charset charset = getCharset(); + + //解析URL中的参数 + final String query = getQuery(); + if(StrUtil.isNotBlank(query)){ + this.paramsCache.putAll(HttpUtil.decodeParams(query, charset)); + } + + // 解析body中的参数 + final String body = getBody(); + if(StrUtil.isNotBlank(body)){ + this.paramsCache.putAll(HttpUtil.decodeParams(body, charset)); + } } - final String contentType = getContentType(); - if (StrUtil.isBlank(contentType)) { - return false; - } - - return contentType.toLowerCase().startsWith("multipart/"); + return this.paramsCache; } /** @@ -332,4 +370,36 @@ public class HttpServerRequest extends HttpServerBase { ip = this.httpExchange.getRemoteAddress().getHostName(); return NetUtil.getMultistageReverseProxyIp(ip); } + + /** + * 获得MultiPart表单内容,多用于获得上传的文件 在同一次请求中,此方法只能被执行一次! + * + * @return MultipartFormData + * @throws IORuntimeException IO异常 + * @since 5.3.0 + */ + public MultipartFormData getMultipart() throws IORuntimeException { + return getMultipart(new UploadSetting()); + } + + /** + * 获得multipart/form-data 表单内容
+ * 包括文件和普通表单数据
+ * 在同一次请求中,此方法只能被执行一次! + * + * @param uploadSetting 上传文件的设定,包括最大文件大小、保存在内存的边界大小、临时目录、扩展名限定等 + * @return MultiPart表单 + * @throws IORuntimeException IO异常 + * @since 5.3.0 + */ + public MultipartFormData getMultipart(UploadSetting uploadSetting) throws IORuntimeException { + final MultipartFormData formData = new MultipartFormData(uploadSetting); + try { + formData.parseRequestStream(getBodyStream(), getCharset()); + } catch (IOException e) { + throw new IORuntimeException(e); + } + + return formData; + } } diff --git a/hutool-http/src/main/java/cn/hutool/http/server/HttpServerResponse.java b/hutool-http/src/main/java/cn/hutool/http/server/HttpServerResponse.java index 879c30475..85966760a 100644 --- a/hutool-http/src/main/java/cn/hutool/http/server/HttpServerResponse.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/HttpServerResponse.java @@ -3,12 +3,14 @@ package cn.hutool.http.server; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; +import cn.hutool.http.ContentType; import cn.hutool.http.Header; +import cn.hutool.http.HttpStatus; import cn.hutool.http.HttpUtil; + import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; @@ -18,6 +20,8 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; import java.nio.charset.Charset; import java.util.List; import java.util.Map; @@ -28,6 +32,10 @@ import java.util.Map; public class HttpServerResponse extends HttpServerBase { private Charset charset; + /** + * 是否已经发送了Http状态码,如果没有,提前写出状态码 + */ + private boolean isSendCode; /** * 构造 @@ -48,6 +56,38 @@ public class HttpServerResponse extends HttpServerBase { return send(httpStatusCode, 0); } + /** + * 发送成功状态码 + * + * @return this + */ + public HttpServerResponse sendOk() { + return send(HttpStatus.HTTP_OK); + } + + /** + * 发送404错误页 + * + * @param content 错误页页面内容,默认text/html类型 + * @return this + */ + public HttpServerResponse send404(String content) { + return sendError(HttpStatus.HTTP_NOT_FOUND, content); + } + + /** + * 发送错误页 + * + * @param errorCode HTTP错误状态码,见HttpStatus + * @param content 错误页页面内容,默认text/html类型 + * @return this + */ + public HttpServerResponse sendError(int errorCode, String content) { + send(errorCode); + setContentType(ContentType.TEXT_HTML.toString()); + return write(content); + } + /** * 发送HTTP状态码 * @@ -56,11 +96,17 @@ public class HttpServerResponse extends HttpServerBase { * @return this */ public HttpServerResponse send(int httpStatusCode, long bodyLength) { + if (this.isSendCode) { + throw new IORuntimeException("Http status code has been send!"); + } + try { this.httpExchange.sendResponseHeaders(httpStatusCode, bodyLength); } catch (IOException e) { throw new IORuntimeException(e); } + + this.isSendCode = true; return this; } @@ -70,6 +116,9 @@ public class HttpServerResponse extends HttpServerBase { * @return 响应头 */ public Headers getHeaders() { + if (false == this.isSendCode) { + sendOk(); + } return this.httpExchange.getResponseHeaders(); } @@ -141,7 +190,7 @@ public class HttpServerResponse extends HttpServerBase { public HttpServerResponse setContentType(String contentType) { if (null != contentType && null != this.charset) { if (false == contentType.contains(";charset=")) { - contentType += ";charset=" + this.charset; + contentType = ContentType.build(contentType, this.charset); } } @@ -169,12 +218,27 @@ public class HttpServerResponse extends HttpServerBase { return this; } + /** + * 设置属性 + * + * @param name 属性名 + * @param value 属性值 + * @return this + */ + public HttpServerResponse setAttr(String name, Object value) { + this.httpExchange.setAttribute(name, value); + return this; + } + /** * 获取响应数据流 * * @return 响应数据流 */ public OutputStream getOut() { + if (false == this.isSendCode) { + sendOk(); + } return this.httpExchange.getResponseBody(); } @@ -183,8 +247,43 @@ public class HttpServerResponse extends HttpServerBase { * * @return 响应数据流 */ - public OutputStream getWriter() { - return this.httpExchange.getResponseBody(); + public PrintWriter getWriter() { + final Charset charset = ObjectUtil.defaultIfNull(this.charset, DEFAULT_CHARSET); + return new PrintWriter(new OutputStreamWriter(getOut(), charset)); + } + + /** + * 写出数据到客户端 + * + * @param data 数据 + * @return this + */ + public HttpServerResponse write(String data, String contentType) { + setContentType(contentType); + return write(data); + } + + /** + * 写出数据到客户端 + * + * @param data 数据 + * @return this + */ + public HttpServerResponse write(String data) { + final Charset charset = ObjectUtil.defaultIfNull(this.charset, DEFAULT_CHARSET); + return write(StrUtil.bytes(data, charset)); + } + + /** + * 写出数据到客户端 + * + * @param data 数据 + * @param contentType 返回的类型 + * @return this + */ + public HttpServerResponse write(byte[] data, String contentType) { + setContentType(contentType); + return write(data); } /** @@ -194,8 +293,19 @@ public class HttpServerResponse extends HttpServerBase { * @return this */ public HttpServerResponse write(byte[] data) { - write(new ByteArrayInputStream(data)); - return this; + return write(new ByteArrayInputStream(data)); + } + + /** + * 返回数据给客户端 + * + * @param in 需要返回客户端的内容 + * @param contentType 返回的类型 + * @since 5.2.6 + */ + public HttpServerResponse write(InputStream in, String contentType) { + setContentType(contentType); + return write(in); } /** @@ -236,7 +346,7 @@ public class HttpServerResponse extends HttpServerBase { } /** - * 返回数据给客户端 + * 返回文件数据给客户端(文件下载) * * @param in 需要返回客户端的内容 * @param contentType 返回的类型 @@ -244,7 +354,7 @@ public class HttpServerResponse extends HttpServerBase { * @since 5.2.6 */ public void write(InputStream in, String contentType, String fileName) { - final Charset charset = ObjectUtil.defaultIfNull(this.charset, CharsetUtil.CHARSET_UTF_8); + final Charset charset = ObjectUtil.defaultIfNull(this.charset, DEFAULT_CHARSET); setHeader("Content-Disposition", StrUtil.format("attachment;filename={}", URLUtil.encode(fileName, charset))); setContentType(contentType); write(in); diff --git a/hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java b/hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java index 21d62fd1f..aa1377963 100644 --- a/hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java @@ -1,9 +1,10 @@ package cn.hutool.http.server; import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.lang.Console; import cn.hutool.http.server.action.Action; +import cn.hutool.http.server.action.RootAction; import cn.hutool.http.server.handler.ActionHandler; -import cn.hutool.http.server.handler.RootHandler; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; @@ -72,7 +73,7 @@ public class SimpleServer { * @return this */ public SimpleServer setRoot(String root) { - return addHandler("/", new RootHandler(root)); + return addAction("/", new RootAction(root)); } /** @@ -119,6 +120,8 @@ public class SimpleServer { * 启动Http服务器,启动后会阻塞当前线程 */ public void start() { + final InetSocketAddress address = getAddress(); + Console.log("Hutool Simple Http Server listen on 【{}:{}】", address.getHostName(), address.getPort()); this.server.start(); } } diff --git a/hutool-http/src/main/java/cn/hutool/http/server/action/RootAction.java b/hutool-http/src/main/java/cn/hutool/http/server/action/RootAction.java new file mode 100644 index 000000000..1444cdbb6 --- /dev/null +++ b/hutool-http/src/main/java/cn/hutool/http/server/action/RootAction.java @@ -0,0 +1,62 @@ +package cn.hutool.http.server.action; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.http.server.HttpServerRequest; +import cn.hutool.http.server.HttpServerResponse; + +import java.io.File; +import java.util.List; + +/** + * 默认的处理器,通过解析用户传入的path,找到网页根目录下对应文件后返回 + * + * @author looly + * @since 5.2.6 + */ +public class RootAction implements Action { + + public static final String DEFAULT_INDEX_FILE_NAME = "index.html"; + + private final String rootDir; + private List indexFileNames; + + /** + * 构造 + * + * @param rootDir 网页根目录 + */ + public RootAction(String rootDir) { + this(rootDir, DEFAULT_INDEX_FILE_NAME); + } + + /** + * 构造 + * + * @param rootDir 网页根目录 + * @param indexFileNames 主页文件名列表 + */ + public RootAction(String rootDir, String... indexFileNames) { + this.rootDir = rootDir; + this.indexFileNames = CollUtil.toList(indexFileNames); + } + + @Override + public void doAction(HttpServerRequest request, HttpServerResponse response) { + final String path = request.getPath(); + File file = FileUtil.file(rootDir, path); + if (file.exists()) { + if (file.isDirectory()) { + for (String indexFileName : indexFileNames) { + //默认读取主页 + file = FileUtil.file(file, indexFileName); + if (file.exists() && file.isFile()) { + response.write(file); + } + } + } + } + + response.send404("404 Not Found !"); + } +} diff --git a/hutool-http/src/main/java/cn/hutool/http/server/handler/ActionHandler.java b/hutool-http/src/main/java/cn/hutool/http/server/handler/ActionHandler.java index 94a51d004..e469ad3d0 100644 --- a/hutool-http/src/main/java/cn/hutool/http/server/handler/ActionHandler.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/handler/ActionHandler.java @@ -27,6 +27,9 @@ public class ActionHandler implements HttpHandler { @Override public void handle(HttpExchange httpExchange) { - action.doAction(new HttpServerRequest(httpExchange), new HttpServerResponse(httpExchange)); + action.doAction( + new HttpServerRequest(httpExchange), + new HttpServerResponse(httpExchange) + ); } } diff --git a/hutool-http/src/main/java/cn/hutool/http/server/handler/HandlerUtil.java b/hutool-http/src/main/java/cn/hutool/http/server/handler/HandlerUtil.java deleted file mode 100644 index a3fe4d0b8..000000000 --- a/hutool-http/src/main/java/cn/hutool/http/server/handler/HandlerUtil.java +++ /dev/null @@ -1,91 +0,0 @@ -package cn.hutool.http.server.handler; - -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.http.Header; -import cn.hutool.http.HttpStatus; -import cn.hutool.http.HttpUtil; -import com.sun.net.httpserver.HttpExchange; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; - -/** - * 请求处理器相关工具类 - * - * @since 5.2.6 - */ -public class HandlerUtil { - - /** - * 返回404页面 - * - * @param httpExchange HttpExchange - * @param content 要发送的404页面内容 - * @throws IOException IO异常 - */ - public static void send404(HttpExchange httpExchange, String content) throws IOException { - if (null == httpExchange) { - return; - } - - if (null == content) { - content = "404 Not Found !"; - } - - httpExchange.sendResponseHeaders(HttpStatus.HTTP_NOT_FOUND, 0); - try (OutputStream out = httpExchange.getResponseBody()) { - IoUtil.writeUtf8(out, false, content); - } - } - - /** - * 返回文件 - * - * @param httpExchange HttpExchange - * @param file 要发送的文件 - * @throws IOException IO异常 - */ - public static void sendFile(HttpExchange httpExchange, File file) throws IOException { - if (ArrayUtil.hasNull(httpExchange, file)) { - return; - } - addHeader(httpExchange, - Header.CONTENT_TYPE.toString(), - HttpUtil.getMimeType(file.getName(), "text/html")); - httpExchange.sendResponseHeaders(HttpStatus.HTTP_OK, 0); - try (OutputStream out = httpExchange.getResponseBody()) { - FileUtil.writeToStream(file, out); - } - } - - /** - * 增加响应头信息 - * - * @param httpExchange HttpExchange - * @param header 头名 - * @param value 头值 - */ - public static void addHeader(HttpExchange httpExchange, String header, String value) { - if (ArrayUtil.hasEmpty(httpExchange, header)) { - return; - } - httpExchange.getResponseHeaders().add(header, value); - } - - /** - * 获取响应头信息 - * - * @param httpExchange HttpExchange - * @param header 头名 - * @return 值,不存在返回null - */ - public static String getHeader(HttpExchange httpExchange, String header) { - if (ArrayUtil.hasEmpty(httpExchange, header)) { - return null; - } - return httpExchange.getRequestHeaders().getFirst(header); - } -} diff --git a/hutool-http/src/main/java/cn/hutool/http/server/handler/RootHandler.java b/hutool-http/src/main/java/cn/hutool/http/server/handler/RootHandler.java deleted file mode 100644 index 8e10274ee..000000000 --- a/hutool-http/src/main/java/cn/hutool/http/server/handler/RootHandler.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.hutool.http.server.handler; - -import cn.hutool.core.io.FileUtil; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -import java.io.File; -import java.io.IOException; -import java.net.URI; - -/** - * 默认的处理器,通过解析用户传入的path,找到网页根目录下对应文件后返回 - * - * @author looly - * @since 5.2.6 - */ -public class RootHandler implements HttpHandler { - - private final String rootDir; - - /** - * 构造 - * - * @param rootDir 网页根目录 - */ - public RootHandler(String rootDir) { - this.rootDir = rootDir; - } - - @Override - public void handle(HttpExchange httpExchange) throws IOException { - final URI uri = httpExchange.getRequestURI(); - File file = FileUtil.file(rootDir, uri.getPath()); - if (file.exists()) { - if (file.isDirectory()) { - //默认读取主页 - file = FileUtil.file(file, "index.html"); - } - HandlerUtil.sendFile(httpExchange, file); - } - - // 文件未找到 - HandlerUtil.send404(httpExchange, null); - } -} diff --git a/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java b/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java index 70a70a510..afb3657ae 100644 --- a/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java @@ -1,13 +1,23 @@ package cn.hutool.http.server; +import cn.hutool.http.ContentType; import cn.hutool.http.HttpUtil; -import cn.hutool.http.server.handler.RootHandler; public class SimpleServerTest { public static void main(String[] args) { HttpUtil.createServer(8888) - .addHandler("/", new RootHandler("D:\\test")) + // 设置默认根目录, + .setRoot("d:/test") + // 返回JSON数据测试 + .addAction("/restTest", (request, response) -> + response.write("{\"id\": 1, \"msg\": \"OK\"}", ContentType.JSON.toString()) + ) + // 获取表单数据测试 + // http://localhost:8888/formTest?a=1&a=2&b=3 + .addAction("/formTest", (request, response) -> + response.write(request.getParams().toString(), ContentType.TEXT_PLAIN.toString()) + ) .start(); } } diff --git a/hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java b/hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java index 58ea75870..59afded99 100644 --- a/hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java @@ -1,13 +1,5 @@ package cn.hutool.http.test; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Console; import cn.hutool.core.util.CharsetUtil; @@ -15,6 +7,13 @@ import cn.hutool.core.util.ReUtil; import cn.hutool.http.Header; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpUtil; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; public class HttpUtilTest { @@ -164,6 +163,16 @@ public class HttpUtilTest { paramsStr = "a=bbb&c=你好&哈喽&"; encode = HttpUtil.encodeParams(paramsStr, CharsetUtil.CHARSET_UTF_8); Assert.assertEquals("a=bbb&c=%E4%BD%A0%E5%A5%BD&%E5%93%88%E5%96%BD=", encode); + + // URL原样输出 + paramsStr = "https://www.hutool.cn/"; + encode = HttpUtil.encodeParams(paramsStr, CharsetUtil.CHARSET_UTF_8); + Assert.assertEquals(paramsStr, encode); + + // URL原样输出 + paramsStr = "https://www.hutool.cn/?"; + encode = HttpUtil.encodeParams(paramsStr, CharsetUtil.CHARSET_UTF_8); + Assert.assertEquals("https://www.hutool.cn/", encode); } @Test diff --git a/hutool-json/pom.xml b/hutool-json/pom.xml index af66a23a4..6b4058a92 100644 --- a/hutool-json/pom.xml +++ b/hutool-json/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-json diff --git a/hutool-log/pom.xml b/hutool-log/pom.xml index 98f927ac6..29dad09b7 100644 --- a/hutool-log/pom.xml +++ b/hutool-log/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-log diff --git a/hutool-poi/pom.xml b/hutool-poi/pom.xml index 379315af5..42eee9aa1 100644 --- a/hutool-poi/pom.xml +++ b/hutool-poi/pom.xml @@ -8,7 +8,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-poi diff --git a/hutool-script/pom.xml b/hutool-script/pom.xml index 05cf7bf27..dc77c1722 100644 --- a/hutool-script/pom.xml +++ b/hutool-script/pom.xml @@ -8,7 +8,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-script diff --git a/hutool-setting/pom.xml b/hutool-setting/pom.xml index eb777bc49..e1b72b92a 100644 --- a/hutool-setting/pom.xml +++ b/hutool-setting/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-setting diff --git a/hutool-socket/pom.xml b/hutool-socket/pom.xml index 011ef7557..f87b3cab0 100644 --- a/hutool-socket/pom.xml +++ b/hutool-socket/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-socket diff --git a/hutool-system/pom.xml b/hutool-system/pom.xml index a89067307..0a7c45ab4 100644 --- a/hutool-system/pom.xml +++ b/hutool-system/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool-system diff --git a/pom.xml b/pom.xml index e443672b0..0c7c027be 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ cn.hutool hutool-parent - 5.2.6-SNAPSHOT + 5.3.0-SNAPSHOT hutool 提供丰富的Java工具方法 https://github.com/looly/hutool