diff --git a/CHANGELOG.md b/CHANGELOG.md index 393208b5b..5a5654dac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,11 @@ ## 5.3.3 (2020-04-25) ### 新特性 +* 【core 】 ImgUtil.createImage支持背景透明(issue#851@Github) +* 【json 】 更改JSON转字符串时" implements Map, Iterable>, Ser }; } + @Override + public String toString() { + return "TableMap{" + + "keys=" + keys + + ", values=" + values + + '}'; + } + private static class Entry implements Map.Entry { private final K key; diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java index 710cb9485..c84fa3f0a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java @@ -61,10 +61,10 @@ public class UrlQuery { * @param queryMap 初始化的查询键值对 */ public UrlQuery(Map queryMap) { - if(MapUtil.isNotEmpty(queryMap)) { + if (MapUtil.isNotEmpty(queryMap)) { query = new TableMap<>(queryMap.size()); addAll(queryMap); - } else{ + } else { query = new TableMap<>(MapUtil.DEFAULT_INITIAL_CAPACITY); } } @@ -88,7 +88,7 @@ public class UrlQuery { * @return this */ public UrlQuery addAll(Map queryMap) { - if(MapUtil.isNotEmpty(queryMap)) { + if (MapUtil.isNotEmpty(queryMap)) { queryMap.forEach(this::add); } return this; @@ -122,34 +122,31 @@ public class UrlQuery { char c; // 当前字符 for (i = 0; i < len; i++) { c = queryStr.charAt(i); - if (c == '=') { // 键值对的分界点 - if (null == name) { - // name可以是"" - name = queryStr.substring(pos, i); - } - pos = i + 1; - } else if (c == '&') { // 参数对的分界点 - if (null == name && pos != i) { - // 对于像&a&这类无参数值的字符串,我们将name为a的值设为"" - addParam(queryStr.substring(pos, i), StrUtil.EMPTY, charset); - } else if (name != null) { + switch (c) { + case '='://键和值的分界符 + if (null == name) { + // name可以是"" + name = queryStr.substring(pos, i); + // 开始位置从分节符后开始 + pos = i + 1; + } + // 当=不作为分界符时,按照普通字符对待 + break; + case '&'://键值对之间的分界符 addParam(name, queryStr.substring(pos, i), charset); name = null; - } - pos = i + 1; + if ("amp;".equals(queryStr.substring(i + 1, i + 5))) { + // issue#850@Github,"&"转义为"&" + i+=4; + } + // 开始位置从分节符后开始 + pos = i + 1; + break; } } // 处理结尾 - if (pos != i) { - if (name == null) { - addParam(queryStr.substring(pos, i), StrUtil.EMPTY, charset); - } else { - addParam(name, queryStr.substring(pos, i), charset); - } - } else if (name != null) { - addParam(name, StrUtil.EMPTY, charset); - } + addParam(name, queryStr.substring(pos, i), charset); return this; } @@ -158,17 +155,18 @@ public class UrlQuery { * * @return 查询的Map,只读 */ - public Map getQueryMap(){ + public Map getQueryMap() { return MapUtil.unmodifiable(this.query); } /** * 获取查询值 + * * @param key 键 * @return 值 */ - public CharSequence get(CharSequence key){ - if(MapUtil.isEmpty(this.query)){ + public CharSequence get(CharSequence key) { + if (MapUtil.isEmpty(this.query)) { return null; } return this.query.get(key); @@ -231,15 +229,25 @@ public class UrlQuery { } /** - * 将键值对加入到值为List类型的Map中 + * 将键值对加入到值为List类型的Map中,,情况如下: + *
+	 *     1、key和value都不为null,类似于 "a=1"或者"=1",直接put
+	 *     2、key不为null,value为null,类似于 "a=",值传""
+	 *     3、key为null,value不为null,类似于 "1"
+	 *     4、key和value都为null,忽略之,比如&&
+	 * 
* - * @param name key - * @param value value + * @param key key,为null则value作为key + * @param value value,为null且key不为null时传入"" * @param charset 编码 */ - private void addParam(String name, String value, Charset charset) { - name = URLUtil.decode(name, charset); - value = URLUtil.decode(value, charset); - this.query.put(name, value); + private void addParam(String key, String value, Charset charset) { + if (null != key) { + final String actualKey = URLUtil.decode(key, charset); + this.query.put(actualKey, StrUtil.nullToEmpty(URLUtil.decode(value, charset))); + } else if (null != value) { + // name为空,value作为name,value赋值"" + this.query.put(URLUtil.decode(value, charset), StrUtil.EMPTY); + } } } diff --git a/hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java b/hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java index 777169541..4ff8f6b8c 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java @@ -170,4 +170,22 @@ public class UrlBuilderTest { Assert.assertEquals("frag1", builder.getFragment()); } + + @Test + public void weixinUrlTest(){ + String urlStr = "https://mp.weixin.qq.com/s?" + + "__biz=MzI5NjkyNTIxMg==" + + "&mid=100000465" + + "&idx=1" + + "&sn=1044c0d19723f74f04f4c1da34eefa35" + + "&chksm=6cbda3a25bca2ab4516410db6ce6e125badaac2f8c5548ea6e18eab6dc3c5422cb8cbe1095f7"; + final UrlBuilder builder = UrlBuilder.ofHttp(urlStr, CharsetUtil.CHARSET_UTF_8); + // 原URL中的&替换为&,value中的=被编码为%3D + Assert.assertEquals("https://mp.weixin.qq.com/s?" + + "__biz=MzI5NjkyNTIxMg%3D%3D" + + "&mid=100000465&idx=1" + + "&sn=1044c0d19723f74f04f4c1da34eefa35" + + "&chksm=6cbda3a25bca2ab4516410db6ce6e125badaac2f8c5548ea6e18eab6dc3c5422cb8cbe1095f7", + builder.toString()); + } } diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java index 7eded0776..189b53112 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java @@ -14,6 +14,7 @@ import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; import cn.hutool.core.net.url.UrlBuilder; import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; @@ -159,12 +160,21 @@ public class HttpRequest extends HttpBase { private SSLSocketFactory ssf; /** - * 构造 + * 构造,URL编码默认使用UTF-8 * * @param url URL */ public HttpRequest(String url) { - setUrl(url); + this(UrlBuilder.ofHttp(url, CharsetUtil.CHARSET_UTF_8)); + } + + /** + * 构造 + * + * @param url {@link UrlBuilder} + */ + public HttpRequest(UrlBuilder url) { + this.url = url; // 给定一个默认头信息 this.header(GlobalHeaders.INSTANCE.headers); } 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 2c325eec1..de61f7f70 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 @@ -11,6 +11,10 @@ public class SimpleServerTest { HttpUtil.createServer(8888) // 设置默认根目录, .setRoot("d:/test") + // get数据测试,返回请求的PATH + .addAction("/get", (request, response) -> + response.write(request.getURI().toString(), ContentType.TEXT_PLAIN.toString()) + ) // 返回JSON数据测试 .addAction("/restTest", (request, response) -> response.write("{\"id\": 1, \"msg\": \"OK\"}", ContentType.JSON.toString()) 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 fda2003d1..7a66972c3 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 @@ -295,4 +295,13 @@ public class HttpUtilTest { String mimeType = HttpUtil.getMimeType("aaa.aaa"); Assert.assertNull(mimeType); } + + @Test + @Ignore + public void getWeixinTest(){ + // 测试特殊URL,即URL中有&情况是否请求正常 + String url = "https://mp.weixin.qq.com/s?__biz=MzI5NjkyNTIxMg==&mid=100000465&idx=1&sn=1044c0d19723f74f04f4c1da34eefa35&chksm=6cbda3a25bca2ab4516410db6ce6e125badaac2f8c5548ea6e18eab6dc3c5422cb8cbe1095f7"; + final String s = HttpUtil.get(url); + Console.log(s); + } }