diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Console.java b/hutool-core/src/main/java/cn/hutool/core/lang/Console.java index e6b91e564..b57504f05 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/Console.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/Console.java @@ -85,8 +85,7 @@ public class Console { public static void log(final Throwable t, final String template, final Object... values) { out.println(StrUtil.format(template, values)); if (null != t) { - //noinspection CallToPrintStackTrace - t.printStackTrace(); + t.printStackTrace(out); out.flush(); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java index 5d75c857e..b030162e9 100755 --- a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java @@ -340,6 +340,22 @@ public final class UrlBuilder implements Builder { return this; } + /** + * 是否path的末尾加 / + * + * @param withEngTag 是否path的末尾加 / + * @return this + * @since 5.8.5 + */ + public UrlBuilder setWithEndTag(final boolean withEngTag) { + if (null == this.path) { + this.path = UrlPath.of(); + } + + this.path.setWithEndTag(withEngTag); + return this; + } + /** * 增加路径节点,路径节点中的"/"会被转义为"%2F" * @@ -489,7 +505,7 @@ public final class UrlBuilder implements Builder { final StringBuilder fileBuilder = new StringBuilder(); // path - fileBuilder.append(StrUtil.blankToDefault(getPathStr(), StrUtil.SLASH)); + fileBuilder.append(getPathStr()); // query final String query = getQueryStr(); diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlPath.java b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlPath.java index 26b7d8d9e..42014c795 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlPath.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlPath.java @@ -22,6 +22,16 @@ public class UrlPath { private List segments; private boolean withEngTag; + /** + * 构建UrlPath + * + * @return UrlPath + * @since 6.0.0 + */ + public static UrlPath of() { + return new UrlPath(); + } + /** * 构建UrlPath * @@ -30,9 +40,7 @@ public class UrlPath { * @return UrlPath */ public static UrlPath of(final CharSequence pathStr, final Charset charset) { - final UrlPath urlPath = new UrlPath(); - urlPath.parse(pathStr, charset); - return urlPath; + return of().parse(pathStr, charset); } /** @@ -100,12 +108,12 @@ public class UrlPath { public UrlPath parse(CharSequence path, final Charset charset) { if (StrUtil.isNotEmpty(path)) { // 原URL中以/结尾,则这个规则需保留,issue#I1G44J@Gitee - if(StrUtil.endWith(path, CharUtil.SLASH)){ + if (StrUtil.endWith(path, CharUtil.SLASH)) { this.withEngTag = true; } path = fixPath(path); - if(StrUtil.isNotEmpty(path)){ + if (StrUtil.isNotEmpty(path)) { final List split = StrUtil.split(path, '/'); for (final String seg : split) { addInternal(URLDecoder.decodeForPath(seg, charset), false); @@ -135,20 +143,21 @@ public class UrlPath { * path = path-abempty / path-absolute / path-noscheme / path-rootless / path-empty * * - * @param charset encode编码,null表示不做encode + * @param charset encode编码,null表示不做encode * @param encodePercent 是否编码`%` * @return 如果没有任何内容,则返回空字符串"" * @since 5.8.0 */ public String build(final Charset charset, final boolean encodePercent) { if (CollUtil.isEmpty(this.segments)) { - return StrUtil.EMPTY; + // 没有节点的path取决于是否末尾追加/,如果不追加返回空串,否则返回/ + return withEngTag ? StrUtil.SLASH : StrUtil.EMPTY; } final char[] safeChars = encodePercent ? null : new char[]{'%'}; final StringBuilder builder = new StringBuilder(); for (final String segment : segments) { - if(builder.length() == 0){ + if (builder.length() == 0) { // 根据https://www.ietf.org/rfc/rfc3986.html#section-3.3定义 // path的第一部分不允许有":",其余部分允许 // 在此处的Path部分特指host之后的部分,即不包含第一部分 @@ -157,12 +166,15 @@ public class UrlPath { builder.append(CharUtil.SLASH).append(RFC3986.SEGMENT.encode(segment, charset, safeChars)); } } - if (StrUtil.isEmpty(builder)) { - // 空白追加是保证以/开头 - builder.append(CharUtil.SLASH); - }else if (withEngTag && false == StrUtil.endWith(builder, CharUtil.SLASH)) { - // 尾部没有/则追加,否则不追加 - builder.append(CharUtil.SLASH); + + if (withEngTag) { + if (StrUtil.isEmpty(builder)) { + // 空白追加是保证以/开头 + builder.append(CharUtil.SLASH); + } else if (false == StrUtil.endWith(builder, CharUtil.SLASH)) { + // 尾部没有/则追加,否则不追加 + builder.append(CharUtil.SLASH); + } } return builder.toString(); 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 924bc6c07..82b13c21d 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 @@ -20,6 +20,17 @@ public class UrlBuilderTest { Assert.assertEquals("http://www.hutool.cn/", buildUrl); } + @Test + public void buildWithoutSlashTest(){ + // https://github.com/dromara/hutool/issues/2459 + String buildUrl = UrlBuilder.of().setScheme("http").setHost("192.168.1.1").setPort(8080).setWithEndTag(false).build(); + Assert.assertEquals("http://192.168.1.1:8080", buildUrl); + + buildUrl = UrlBuilder.of().setScheme("http").setHost("192.168.1.1").setPort(8080).addQuery("url", "http://192.168.1.1/test/1") + .setWithEndTag(false).build(); + Assert.assertEquals("http://192.168.1.1:8080?url=http://192.168.1.1/test/1", buildUrl); + } + @Test public void buildTest2() { // path中的+不做处理