Looly 5 years ago
parent
commit
80ed1c0141

+ 2 - 0
CHANGELOG.md

@@ -24,6 +24,8 @@
 * 【core   】     修复Dict中putAll大小写问题(issue#I1MU5B@Gitee)
 * 【core   】     修复POI中sax读取数字判断错误问题(issue#931@Github)
 * 【core   】     修复DateUtil.endOfQuarter错误问题(issue#I1NGZ7@Gitee)
+* 【core   】     修复URL中有空格转为+问题(issue#I1NGW4@Gitee)
+* 【core   】     修复CollUtil.intersectionDistinct空集合结果错误问题
 
 -------------------------------------------------------------------------------------------------------------
 ## 5.3.8 (2020-06-16)

+ 9 - 6
hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java

@@ -283,23 +283,26 @@ public class CollUtil {
 	@SafeVarargs
 	public static <T> Set<T> intersectionDistinct(Collection<T> coll1, Collection<T> coll2, Collection<T>... otherColls) {
 		final Set<T> result;
-		if (isEmpty(coll1)) {
-			result = new LinkedHashSet<>();
+		if (isEmpty(coll1) || isEmpty(coll2)) {
+			// 有一个空集合就直接返回空
+			return new LinkedHashSet<>();
 		} else {
 			result = new LinkedHashSet<>(coll1);
 		}
 
-		if (isNotEmpty(coll2)) {
-			result.retainAll(coll2);
-		}
-
 		if (ArrayUtil.isNotEmpty(otherColls)) {
 			for (Collection<T> otherColl : otherColls) {
 				if(isNotEmpty(otherColl)){
 					result.retainAll(otherColl);
+				} else {
+					// 有一个空集合就直接返回空
+					return new LinkedHashSet<>();
 				}
 			}
 		}
+
+		result.retainAll(coll2);
+
 		return result;
 	}
 

+ 62 - 26
hutool-core/src/main/java/cn/hutool/core/net/URLEncoder.java

@@ -12,24 +12,23 @@ import java.util.BitSet;
 
 /**
  * URL编码,数据内容的类型是 application/x-www-form-urlencoded。
- * 
+ *
  * <pre>
  * 1.字符"a"-"z","A"-"Z","0"-"9",".","-","*",和"_" 都不会被编码;
  * 2.将空格转换为%20 ;
  * 3.将非文本内容转换成"%xy"的形式,xy是两位16进制的数值;
  * </pre>
- * 
- * @author looly,
  *
+ * @author looly
  */
-public class URLEncoder implements Serializable{
+public class URLEncoder implements Serializable {
 	private static final long serialVersionUID = 1L;
 
 	// --------------------------------------------------------------------------------------------- Static method start
 	/**
 	 * 默认{@link URLEncoder}<br>
 	 * 默认的编码器针对URI路径编码,定义如下:
-	 * 
+	 *
 	 * <pre>
 	 * pchar = unreserved(不处理) / pct-encoded / sub-delims(子分隔符) / ":" / "@"
 	 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
@@ -37,32 +36,42 @@ public class URLEncoder implements Serializable{
 	 * </pre>
 	 */
 	public static final URLEncoder DEFAULT = createDefault();
-	
+
 	/**
 	 * 用于查询语句的{@link URLEncoder}<br>
 	 * 编码器针对URI路径编码,定义如下:
-	 * 
+	 *
 	 * <pre>
-	 * 0x20 ' ' =》 '+' 
-	 * 0x2A, 0x2D, 0x2E, 0x30 to 0x39, 0x41 to 0x5A, 0x5F, 0x61 to 0x7A as-is 
+	 * 0x20 ' ' =》 '+'
+	 * 0x2A, 0x2D, 0x2E, 0x30 to 0x39, 0x41 to 0x5A, 0x5F, 0x61 to 0x7A as-is
 	 * '*', '-', '.', '0' to '9', 'A' to 'Z', '_', 'a' to 'z' Also '=' and '&amp;' 不编码
 	 * 其它编码为 %nn 形式
 	 * </pre>
-	 * 
+	 * <p>
 	 * 详细见:https://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
 	 */
 	public static final URLEncoder QUERY = createQuery();
 
 	/**
+	 * 全编码的{@link URLEncoder}<br>
+	 * <pre>
+	 * 	 0x2A, 0x2D, 0x2E, 0x30 to 0x39, 0x41 to 0x5A, 0x5F, 0x61 to 0x7A as-is
+	 * 	 '*', '-', '.', '0' to '9', 'A' to 'Z', '_', 'a' to 'z' 不编码
+	 * 	 其它编码为 %nn 形式
+	 * 	 </pre>
+	 */
+	public static final URLEncoder ALL = createAll();
+
+	/**
 	 * 创建默认{@link URLEncoder}<br>
 	 * 默认的编码器针对URI路径编码,定义如下:
-	 * 
+	 *
 	 * <pre>
 	 * pchar = unreserved(不处理) / pct-encoded / sub-delims(子分隔符) / ":" / "@"
 	 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
 	 * sub-delims = "!" / "$" / "&amp;" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
 	 * </pre>
-	 * 
+	 *
 	 * @return {@link URLEncoder}
 	 */
 	public static URLEncoder createDefault() {
@@ -95,16 +104,16 @@ public class URLEncoder implements Serializable{
 	/**
 	 * 创建用于查询语句的{@link URLEncoder}<br>
 	 * 编码器针对URI路径编码,定义如下:
-	 * 
+	 *
 	 * <pre>
-	 * 0x20 ' ' =》 '+' 
-	 * 0x2A, 0x2D, 0x2E, 0x30 to 0x39, 0x41 to 0x5A, 0x5F, 0x61 to 0x7A as-is 
+	 * 0x20 ' ' =》 '+'
+	 * 0x2A, 0x2D, 0x2E, 0x30 to 0x39, 0x41 to 0x5A, 0x5F, 0x61 to 0x7A as-is
 	 * '*', '-', '.', '0' to '9', 'A' to 'Z', '_', 'a' to 'z' Also '=' and '&amp;' 不编码
 	 * 其它编码为 %nn 形式
 	 * </pre>
-	 * 
+	 * <p>
 	 * 详细见:https://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
-	 * 
+	 *
 	 * @return {@link URLEncoder}
 	 */
 	public static URLEncoder createQuery() {
@@ -122,16 +131,44 @@ public class URLEncoder implements Serializable{
 
 		return encoder;
 	}
+
+	/**
+	 * 创建{@link URLEncoder}<br>
+	 * 编码器针对URI路径编码,定义如下:
+	 *
+	 * <pre>
+	 * 0x2A, 0x2D, 0x2E, 0x30 to 0x39, 0x41 to 0x5A, 0x5F, 0x61 to 0x7A as-is
+	 * '*', '-', '.', '0' to '9', 'A' to 'Z', '_', 'a' to 'z' 不编码
+	 * 其它编码为 %nn 形式
+	 * </pre>
+	 * <p>
+	 * 详细见:https://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
+	 *
+	 * @return {@link URLEncoder}
+	 */
+	public static URLEncoder createAll() {
+		final URLEncoder encoder = new URLEncoder();
+		encoder.addSafeCharacter('*');
+		encoder.addSafeCharacter('-');
+		encoder.addSafeCharacter('.');
+		encoder.addSafeCharacter('_');
+
+		return encoder;
+	}
 	// --------------------------------------------------------------------------------------------- Static method end
 
-	/** 存放安全编码 */
+	/**
+	 * 存放安全编码
+	 */
 	private final BitSet safeCharacters;
-	/** 是否编码空格为+ */
+	/**
+	 * 是否编码空格为+
+	 */
 	private boolean encodeSpaceAsPlus = false;
 
 	/**
 	 * 构造<br>
-	 * 
+	 * <p>
 	 * [a-zA-Z0-9]默认不被编码
 	 */
 	public URLEncoder() {
@@ -150,7 +187,7 @@ public class URLEncoder implements Serializable{
 
 	/**
 	 * 构造
-	 * 
+	 *
 	 * @param safeCharacters 安全字符,安全字符不被编码
 	 */
 	private URLEncoder(BitSet safeCharacters) {
@@ -160,7 +197,7 @@ public class URLEncoder implements Serializable{
 	/**
 	 * 增加安全字符<br>
 	 * 安全字符不被编码
-	 * 
+	 *
 	 * @param c 字符
 	 */
 	public void addSafeCharacter(char c) {
@@ -170,7 +207,7 @@ public class URLEncoder implements Serializable{
 	/**
 	 * 移除安全字符<br>
 	 * 安全字符不被编码
-	 * 
+	 *
 	 * @param c 字符
 	 */
 	public void removeSafeCharacter(char c) {
@@ -179,7 +216,7 @@ public class URLEncoder implements Serializable{
 
 	/**
 	 * 是否将空格编码为+
-	 * 
+	 *
 	 * @param encodeSpaceAsPlus 是否将空格编码为+
 	 */
 	public void setEncodeSpaceAsPlus(boolean encodeSpaceAsPlus) {
@@ -189,9 +226,8 @@ public class URLEncoder implements Serializable{
 	/**
 	 * 将URL中的字符串编码为%形式
 	 *
-	 * @param path 需要编码的字符串
+	 * @param path    需要编码的字符串
 	 * @param charset 编码
-	 *
 	 * @return 编码后的字符串
 	 */
 	public String encode(String path, Charset charset) {

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

@@ -14,7 +14,6 @@ import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
 import java.net.HttpURLConnection;
 import java.net.JarURLConnection;
 import java.net.MalformedURLException;
@@ -331,11 +330,8 @@ public class URLUtil {
 		if (null == charset) {
 			return url;
 		}
-		try {
-			return java.net.URLEncoder.encode(url, charset.toString());
-		} catch (UnsupportedEncodingException e) {
-			throw new UtilException(e);
-		}
+
+		return URLEncoder.ALL.encode(url, charset);
 	}
 
 	/**

+ 14 - 15
hutool-core/src/test/java/cn/hutool/core/collection/CollUtilTest.java

@@ -27,14 +27,13 @@ import java.util.SortedSet;
 
 /**
  * 集合工具类单元测试
- * 
- * @author looly
  *
+ * @author looly
  */
 public class CollUtilTest {
 
 	@Test
-	public void isNotEmptyTest(){
+	public void isNotEmptyTest() {
 		Assert.assertFalse(CollUtil.isNotEmpty((Collection<?>) null));
 	}
 
@@ -79,7 +78,7 @@ public class CollUtilTest {
 		Collection<String> intersection = CollUtil.intersection(list1, list2);
 		Assert.assertEquals(2, CollUtil.count(intersection, t -> t.equals("b")));
 	}
-	
+
 	@Test
 	public void intersectionDistinctTest() {
 		ArrayList<String> list1 = CollUtil.newArrayList("a", "b", "b", "c", "d", "x");
@@ -87,10 +86,10 @@ public class CollUtilTest {
 		ArrayList<String> list3 = CollUtil.newArrayList();
 
 		Collection<String> intersectionDistinct = CollUtil.intersectionDistinct(list1, list2);
-        	Assert.assertEquals(CollUtil.newLinkedHashSet("a", "b", "c", "d"), intersectionDistinct);
+		Assert.assertEquals(CollUtil.newLinkedHashSet("a", "b", "c", "d"), intersectionDistinct);
 
-        	Collection<String> intersectionDistinct2 = CollUtil.intersectionDistinct(list1, list2, list3);
-        	Assert.assertTrue(intersectionDistinct2.isEmpty());
+		Collection<String> intersectionDistinct2 = CollUtil.intersectionDistinct(list1, list2, list3);
+		Assert.assertTrue(intersectionDistinct2.isEmpty());
 	}
 
 	@Test
@@ -144,7 +143,7 @@ public class CollUtilTest {
 	}
 
 	@Test
-	public void subtractTest(){
+	public void subtractTest() {
 		List<String> list1 = CollUtil.newArrayList("a", "b", "b", "c", "d", "x");
 		List<String> list2 = CollUtil.newArrayList("a", "b", "b", "b", "c", "d", "x2");
 		final Collection<String> subtract = CollUtil.subtract(list1, list2);
@@ -228,7 +227,7 @@ public class CollUtilTest {
 		Assert.assertSame(list, filtered);
 		Assert.assertEquals(CollUtil.newArrayList("b", "c"), filtered);
 	}
-	
+
 	@Test
 	public void removeNullTest() {
 		ArrayList<String> list = CollUtil.newArrayList("a", "b", "c", null, "", "  ");
@@ -239,7 +238,7 @@ public class CollUtilTest {
 		Assert.assertSame(list, filtered);
 		Assert.assertEquals(CollUtil.newArrayList("a", "b", "c", "", "  "), filtered);
 	}
-	
+
 	@Test
 	public void removeEmptyTest() {
 		ArrayList<String> list = CollUtil.newArrayList("a", "b", "c", null, "", "  ");
@@ -250,13 +249,13 @@ public class CollUtilTest {
 		Assert.assertSame(list, filtered);
 		Assert.assertEquals(CollUtil.newArrayList("a", "b", "c", "  "), filtered);
 	}
-	
+
 	@Test
 	public void removeBlankTest() {
 		ArrayList<String> list = CollUtil.newArrayList("a", "b", "c", null, "", "  ");
-		
+
 		ArrayList<String> filtered = CollUtil.removeBlank(list);
-		
+
 		// 原地过滤
 		Assert.assertSame(list, filtered);
 		Assert.assertEquals(CollUtil.newArrayList("a", "b", "c"), filtered);
@@ -632,9 +631,9 @@ public class CollUtilTest {
 	}
 
 	@Test
-	public void toMapTest(){
+	public void toMapTest() {
 		Collection<String> keys = CollUtil.newArrayList("a", "b", "c", "d");
-		final Map<String, String> map = CollUtil.toMap(keys, new HashMap<>(), (value)->"key" + value);
+		final Map<String, String> map = CollUtil.toMap(keys, new HashMap<>(), (value) -> "key" + value);
 		Assert.assertEquals("a", map.get("keya"));
 		Assert.assertEquals("b", map.get("keyb"));
 		Assert.assertEquals("c", map.get("keyc"));

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

@@ -198,4 +198,10 @@ public class UrlBuilderTest {
 		final UrlBuilder builder = UrlBuilder.ofHttp(getWorkDayUrl, CharsetUtil.CHARSET_UTF_8);
 		Assert.assertEquals(getWorkDayUrl, builder.toString());
 	}
+
+	@Test
+	public void blankEncodeTest(){
+		final UrlBuilder urlBuilder = UrlBuilder.ofHttp("http://a.com/aaa bbb.html", CharsetUtil.CHARSET_UTF_8);
+		Assert.assertEquals("http://a.com/aaa%20bbb.html", urlBuilder.toString());
+	}
 }