ソースを参照

fix UrlBuilder bug

Looly 4 年 前
コミット
b7ca34d0e8

+ 3 - 1
CHANGELOG.md

@@ -3,7 +3,7 @@
 
 -------------------------------------------------------------------------------------------------------------
 
-# 5.5.8 (2021-01-20)
+# 5.5.8 (2021-01-21)
 
 ### 新特性
 * 【extra  】     增加自动装配SpringUtil类(pr#1366@Github)
@@ -14,6 +14,8 @@
 ### Bug修复
 * 【core   】     修复FileUtil.move以及PathUtil.copy等无法自动创建父目录的问题(issue#I2CKTI@Gitee)
 * 【core   】     修复Console.input读取不全问题(pr#263@Gitee)
+* 【core   】     修复URLUtil.encodeAll未检查空指针问题(issue#I2CNPS@Gitee)
+* 【core   】     修复UrlBuilder.of的query中含有?丢失问题(issue#I2CNPS@Gitee)
 
 -------------------------------------------------------------------------------------------------------------
 

+ 10 - 10
hutool-cache/src/main/java/cn/hutool/cache/Cache.java

@@ -16,16 +16,16 @@ import java.util.Iterator;
 public interface Cache<K, V> extends Iterable<V>, Serializable {
 
 	/**
-	 * 返回缓存容量,<code>0</code>表示无大小限制
+	 * 返回缓存容量,{@code 0}表示无大小限制
 	 *
-	 * @return 返回缓存容量,<code>0</code>表示无大小限制
+	 * @return 返回缓存容量,{@code 0}表示无大小限制
 	 */
 	int capacity();
 
 	/**
-	 * 缓存失效时长, <code>0</code> 表示没有设置,单位毫秒
+	 * 缓存失效时长, {@code 0} 表示没有设置,单位毫秒
 	 *
-	 * @return 缓存失效时长, <code>0</code> 表示没有设置,单位毫秒
+	 * @return 缓存失效时长, {@code 0} 表示没有设置,单位毫秒
 	 */
 	long timeout();
 
@@ -49,9 +49,9 @@ public interface Cache<K, V> extends Iterable<V>, Serializable {
 	void put(K key, V object, long timeout);
 
 	/**
-	 * 从缓存中获得对象,当对象不在缓存中或已经过期返回<code>null</code>
+	 * 从缓存中获得对象,当对象不在缓存中或已经过期返回{@code null}
 	 * <p>
-	 * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回<code>null</code>,否则返回值。
+	 * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回{@code null},否则返回值。
 	 * <p>
 	 * 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。
 	 *
@@ -66,7 +66,7 @@ public interface Cache<K, V> extends Iterable<V>, Serializable {
 	/**
 	 * 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象
 	 * <p>
-	 * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回<code>null</code>,否则返回值。
+	 * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回{@code null},否则返回值。
 	 * <p>
 	 * 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。
 	 *
@@ -81,7 +81,7 @@ public interface Cache<K, V> extends Iterable<V>, Serializable {
 	/**
 	 * 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象
 	 * <p>
-	 * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回<code>null</code>,否则返回值。
+	 * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回{@code null},否则返回值。
 	 * <p>
 	 * 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。
 	 *
@@ -93,9 +93,9 @@ public interface Cache<K, V> extends Iterable<V>, Serializable {
 	V get(K key, boolean isUpdateLastAccess, Func0<V> supplier);
 
 	/**
-	 * 从缓存中获得对象,当对象不在缓存中或已经过期返回<code>null</code>
+	 * 从缓存中获得对象,当对象不在缓存中或已经过期返回{@code null}
 	 * <p>
-	 * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回<code>null</code>,否则返回值。
+	 * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回{@code null},否则返回值。
 	 *
 	 * @param key                键
 	 * @param isUpdateLastAccess 是否更新最后访问时间,即重新计算超时时间。

+ 2 - 2
hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java

@@ -135,7 +135,7 @@ public final class UrlBuilder implements Serializable {
 	 * @return UrlBuilder
 	 */
 	public static UrlBuilder of(String scheme, String host, int port, String path, String query, String fragment, Charset charset) {
-		return of(scheme, host, port, UrlPath.of(path, charset), UrlQuery.of(query, charset), fragment, charset);
+		return of(scheme, host, port, UrlPath.of(path, charset), UrlQuery.of(query, charset, false), fragment, charset);
 	}
 
 	/**
@@ -504,4 +504,4 @@ public final class UrlBuilder implements Serializable {
 		return build();
 	}
 
-}
+}

+ 39 - 11
hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java

@@ -29,7 +29,7 @@ public class UrlQuery {
 	 * 构建UrlQuery
 	 *
 	 * @param queryMap 初始化的查询键值对
-	 * @return {@link UrlQuery}
+	 * @return UrlQuery
 	 */
 	public static UrlQuery of(Map<? extends CharSequence, ?> queryMap) {
 		return new UrlQuery(queryMap);
@@ -40,11 +40,24 @@ public class UrlQuery {
 	 *
 	 * @param queryStr 初始化的查询字符串
 	 * @param charset  decode用的编码,null表示不做decode
-	 * @return {@link UrlQuery}
+	 * @return UrlQuery
 	 */
 	public static UrlQuery of(String queryStr, Charset charset) {
+		return of(queryStr, charset, true);
+	}
+
+	/**
+	 * 构建UrlQuery
+	 *
+	 * @param queryStr       初始化的查询字符串
+	 * @param charset        decode用的编码,null表示不做decode
+	 * @param autoRemovePath 是否自动去除path部分,{@code true}则自动去除第一个?前的内容
+	 * @return UrlQuery
+	 * @since 5.5.8
+	 */
+	public static UrlQuery of(String queryStr, Charset charset, boolean autoRemovePath) {
 		final UrlQuery urlQuery = new UrlQuery();
-		urlQuery.parse(queryStr, charset);
+		urlQuery.parse(queryStr, charset, autoRemovePath);
 		return urlQuery;
 	}
 
@@ -102,16 +115,31 @@ public class UrlQuery {
 	 * @return this
 	 */
 	public UrlQuery parse(String queryStr, Charset charset) {
+		return parse(queryStr, charset, true);
+	}
+
+	/**
+	 * 解析URL中的查询字符串
+	 *
+	 * @param queryStr       查询字符串,类似于key1=v1&amp;key2=&amp;key3=v3
+	 * @param charset        decode编码,null表示不做decode
+	 * @param autoRemovePath 是否自动去除path部分,{@code true}则自动去除第一个?前的内容
+	 * @return this
+	 * @since 5.5.8
+	 */
+	public UrlQuery parse(String queryStr, Charset charset, boolean autoRemovePath) {
 		if (StrUtil.isBlank(queryStr)) {
 			return this;
 		}
 
-		// 去掉Path部分
-		int pathEndPos = queryStr.indexOf('?');
-		if (pathEndPos > -1) {
-			queryStr = StrUtil.subSuf(queryStr, pathEndPos + 1);
-			if (StrUtil.isBlank(queryStr)) {
-				return this;
+		if (autoRemovePath) {
+			// 去掉Path部分
+			int pathEndPos = queryStr.indexOf('?');
+			if (pathEndPos > -1) {
+				queryStr = StrUtil.subSuf(queryStr, pathEndPos + 1);
+				if (StrUtil.isBlank(queryStr)) {
+					return this;
+				}
 			}
 		}
 
@@ -135,9 +163,9 @@ public class UrlQuery {
 				case '&'://键值对之间的分界符
 					addParam(name, queryStr.substring(pos, i), charset);
 					name = null;
-					if (i+4 < len && "amp;".equals(queryStr.substring(i + 1, i + 5))) {
+					if (i + 4 < len && "amp;".equals(queryStr.substring(i + 1, i + 5))) {
 						// issue#850@Github,"&amp;"转义为"&"
-						i+=4;
+						i += 4;
 					}
 					// 开始位置从分节符后开始
 					pos = i + 1;

+ 2 - 2
hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java

@@ -332,7 +332,7 @@ public class URLUtil {
 	 * @throws UtilException UnsupportedEncodingException
 	 */
 	public static String encodeAll(String url, Charset charset) throws UtilException {
-		if (null == charset) {
+		if (null == charset || StrUtil.isEmpty(url)) {
 			return url;
 		}
 
@@ -870,4 +870,4 @@ public class URLUtil {
 
 		return builder.toString();
 	}
-}
+}

+ 18 - 0
hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java

@@ -6,6 +6,10 @@ import cn.hutool.core.util.CharsetUtil;
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+
 public class UrlBuilderTest {
 
 	@Test
@@ -217,4 +221,18 @@ public class UrlBuilderTest {
 		final UrlBuilder urlBuilder = UrlBuilder.ofHttp("https://hutool.cn//file/test.jpg", CharsetUtil.CHARSET_UTF_8);
 		Assert.assertEquals("https://hutool.cn//file/test.jpg", urlBuilder.toString());
 	}
+
+	@Test
+	public void toURITest() throws URISyntaxException {
+		String webUrl = "http://exmple.com/patha/pathb?a=123"; // 报错数据
+		final UrlBuilder urlBuilder = UrlBuilder.of(webUrl, StandardCharsets.UTF_8);
+		Assert.assertEquals(new URI(webUrl), urlBuilder.toURI());
+	}
+
+	@Test
+	public void testEncodeInQuery() {
+		String webUrl = "http://exmple.com/patha/pathb?a=123&b=4?6&c=789"; // b=4?6  参数中有未编码的?
+		final UrlBuilder urlBuilder = UrlBuilder.of(webUrl, StandardCharsets.UTF_8);
+		Assert.assertEquals("a=123&b=4%3F6&c=789", urlBuilder.getQueryStr());
+	}
 }