将相对URL附加到java.net.URL

如果我有一个java.net.URL对象,指向让我们说

http://example.com/myItemshttp://example.com/myItems/

是否有一些助手在某处附加一些相对URL? 例如,附加./myItemIdmyItemId来获取: http://example.com/myItems/myItemIdhttp://example.com/myItems/myItemId

URL有一个构造函数 ,它接受基本URLString规范。

或者, java.net.URI更贴近标准,并有一个resolve方法来做同样的事情。 使用URL.toURI从您的URL创建URI

这个不需要任何额外的库或代码,并给出了所需的结果:

 URL url1 = new URL("http://petstore.swagger.wordnik.com/api/api-docs"); URL url2 = new URL(url1.getProtocol(), url1.getHost(), url1.getPort(), url1.getFile() + "/pet", null); System.out.println(url1); System.out.println(url2); 

这打印:

 http://petstore.swagger.wordnik.com/api/api-docs http://petstore.swagger.wordnik.com/api/api-docs/pet 

只有在主机之后没有路径(恕我直言,接受的答案是错误的)时,接受的答案才有效

这是我写的一个辅助函数,用于添加到url路径:

 public static URL concatenate(URL baseUrl, String extraPath) throws URISyntaxException, MalformedURLException { URI uri = baseUrl.toURI(); String newPath = uri.getPath() + '/' + extraPath; URI newUri = uri.resolve(newPath); return newUri.toURL(); } 

我已经广泛搜索了这个问题的答案。 我能找到的唯一实现是在Android SDK中: Uri.Builder 。 我已经为了自己的目的提取了它。

 private String appendSegmentToPath(String path, String segment) { if (path == null || path.isEmpty()) { return "/" + segment; } if (path.charAt(path.length() - 1) == '/') { return path + segment; } return path + "/" + segment; } 

这是我找到源头的地方。

结合Apache URIBuilder ,我正在使用它: builder.setPath(appendSegmentToPath(builder.getPath(), segment));

您可以使用URIBuilder和方法URI#normalize来避免URI中的重复/

 URIBuilder uriBuilder = new URIBuilder("http://example.com/test"); URI uri = uriBuilder.setPath(uriBuilder.getPath() + "/path/to/add") .build() .normalize(); // expected : http://example.com/test/path/to/add 

使用Apache URIBuilder的一些示例http://hc.apache.org/httpcomponents-client-4.3.x/httpclient/apidocs/org/apache/http/client/utils/URIBuilder.html :

EX1:

 String url = "http://example.com/test"; URIBuilder builder = new URIBuilder(url); builder.setPath((builder.getPath() + "/example").replaceAll("//+", "/")); System.out.println("Result 1 -> " + builder.toString()); 

结果1 – > http://example.com/test/example

EX2:

 String url = "http://example.com/test"; URIBuilder builder = new URIBuilder(url); builder.setPath((builder.getPath() + "///example").replaceAll("//+", "/")); System.out.println("Result 2 -> " + builder.toString()); 

结果2 – > http://example.com/test/example

更新

我相信这是最短的解决方案:

 URL url1 = new URL("http://domain.com/contextpath"); String relativePath = "/additional/relative/path"; URL concatenatedUrl = new URL(url1.toExternalForm() + relativePath); 

你可以使用URI类:

 import java.net.URI; import org.apache.http.client.utils.URIBuilder; URI uri = URI.create("http://example.com/basepath/"); URI uri2 = uri.resolve("./relative"); // => http://example.com/basepath/relative 

请注意基本路径上的尾部斜杠以及要追加的段的基本相对格式。 您还可以使用Apache HTTP客户端中的URIBuilder类:

  org.apache.httpcomponents httpclient 4.5.3  

 import java.net.URI; import org.apache.http.client.utils.URIBuilder; URI uri = URI.create("http://example.com/basepath"); URI uri2 = appendPath(uri, "relative"); // => http://example.com/basepath/relative public URI appendPath(URI uri, String path) { URIBuilder builder = new URIBuilder(uri); builder.setPath(URI.create(builder.getPath() + "/").resolve("./" + path).getPath()); return builder.build(); } 

连接到URI的相对路径:

 java.net.URI uri = URI.create("https://stackoverflow.com/questions") java.net.URI res = uri.resolve(uri.getPath + "/some/path") 

res将包含https://stackoverflow.com/questions/some/path

我对URI的编码有些困难。 追加不适合我,因为它是一个内容://类型,它不喜欢“/”。 这个解决方案假设没有查询,也没有片段(我们毕竟使用路径):

Kotlin代码:

  val newUri = Uri.parse(myUri.toString() + Uri.encode("/$relPath")) 

我的解决方案基于twhitbeck回答:

 import java.net.URI; import java.net.URISyntaxException; public class URIBuilder extends org.apache.http.client.utils.URIBuilder { public URIBuilder() { } public URIBuilder(String string) throws URISyntaxException { super(string); } public URIBuilder(URI uri) { super(uri); } public org.apache.http.client.utils.URIBuilder addPath(String subPath) { if (subPath == null || subPath.isEmpty() || "/".equals(subPath)) { return this; } return setPath(appendSegmentToPath(getPath(), subPath)); } private String appendSegmentToPath(String path, String segment) { if (path == null || path.isEmpty()) { path = "/"; } if (path.charAt(path.length() - 1) == '/' || segment.startsWith("/")) { return path + segment; } return path + "/" + segment; } } 

测试:

 import org.junit.Test; import static org.junit.Assert.assertEquals; public class URIBuilderTest { @Test public void testAddPath() throws Exception { String url = "http://example.com/test"; String expected = "http://example.com/test/example"; URIBuilder builder = new URIBuilder(url); builder.addPath("/example"); assertEquals(expected, builder.toString()); builder = new URIBuilder(url); builder.addPath("example"); assertEquals(expected, builder.toString()); builder.addPath(""); builder.addPath(null); assertEquals(expected, builder.toString()); url = "http://example.com"; expected = "http://example.com/example"; builder = new URIBuilder(url); builder.addPath("/"); assertEquals(url, builder.toString()); builder.addPath("/example"); assertEquals(expected, builder.toString()); } } 

要点: https : //gist.github.com/enginer/230e2dc2f1d213a825d5

对于android,请确保使用android.net.Uri .appendPath()