假设我有一个指向 http://example.com/myItems
或者 http://example.com/myItems/
的java.net.URL对象,是否有某种助手方法可以将一些相对URL添加到它的末尾?例如添加 ./myItemId
或 myItemId
以获取: http://example.com/myItems/myItemId
。
假设我有一个指向 http://example.com/myItems
或者 http://example.com/myItems/
的java.net.URL对象,是否有某种助手方法可以将一些相对URL添加到它的末尾?例如添加 ./myItemId
或 myItemId
以获取: http://example.com/myItems/myItemId
。
android.net.Uri
。以下代码允许从现有的URL字符串创建Uri.Builder
,然后进行追加操作:Uri.parse(baseUrl) // Create Uri from String
.buildUpon() // Creates a "Builder"
.appendEncodedPath("path/to/add")
.appendQueryParameter("at_ref", "123") // To add ?at_ref=123
.fragment("anker") // To add #anker
.build()
appendEncodedPath
不需要前导的 /
,并且仅在 "baseUrl" 结尾没有斜杠时才包含一个检查,否则会在路径之前添加一个斜杠。遵循以下模式的绝对分层 URI 引用
<scheme>://<authority><absolute path>?<query>#<fragment>
具有以下模式的相对 URI
<relative or absolute path>?<query>#<fragment>
//<authority><absolute path>?<query>#<fragment>
具有以下模式的不透明 URI
<scheme>:<opaque part>#<fragment>
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());
}
}
我在处理URI编码时遇到了一些困难。由于它的类型是content://,所以添加操作对我来说并不起作用,而且它不喜欢“/”符号。此解决方案假定没有查询或片段(毕竟我们是在处理路径):
Kotlin代码:
val newUri = Uri.parse(myUri.toString() + Uri.encode("/$relPath"))
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
例2:
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
这只需要一行代码,normalize()
在这里是你的好朋友,并且在连接之间始终添加一个额外的 /
当 baseUrl 以 /
结尾时,normalize() 将删除多余的。如果它不以 /
结尾,则通过故意添加一个来解决。
String unknownBaseUrl = "https://example.com/apples/";
String result = URI.create(unknownBaseUrl + "/" + "1209").normalize().toString();
System.out.println(result);
output: https://example.com/apples/1209
带有许多额外 /
的示例将根据 RFC 2396 进行规范化,以得到一个合理的路径。
String unknownBaseUrl = "https://example.com/apples/";
String result = URI.create(unknownBaseUrl + "/" + "/1209").normalize().toString();
System.out.println(result);
output: https://example.com/apples/1209
Apache HttpClient 5.1新增了appendPath
方法,支持在URIBuilder
中添加路径:
import org.apache.hc.core5.net.URIBuilder;
..
URI uri = new URIBuilder("https://stackoverflow.com/questions")
.appendPath("7498030")
.appendPath("append-relative-url")
.build();
// https://dev59.com/uGs05IYBdhLWcg3wB9af
Maven 依赖:
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.1</version>
</dependency>
使用Spring框架:
import org.springframework.web.util.DefaultUriBuilderFactory;
...
var url = "http://localhost"
var uriBuilderFactory = new DefaultUriBuilderFactory(url)
var target_uri = uriBuilderFactory.builder().pathSegment("path1").pathSegment("path2").build().toString()
//
// result: http://localhost/path1/path2
public static void main(String[] args) {
System.out.println(concatURISegments(
"http://abc/",
"/dfg/",
"/lmn",
"opq"
));
}
public static String concatURISegments(String... segmentArray) {
if (segmentArray.length == 0) {
return "";
} else if (segmentArray.length == 1) {
return segmentArray[0];
}
List<String> segmentList = new ArrayList<>();
for (String s : segmentArray) {
if (s != null && s.length() > 0) {
segmentList.add(s);
}
}
if (segmentList.size() == 0) {
return "";
} else if (segmentList.size() == 1) {
return segmentList.get(0);
}
StringBuilder sb = new StringBuilder();
sb.append(segmentList.get(0));
String prevS;
String currS;
boolean prevB;
boolean currB;
for (int i = 1; i < segmentList.size(); i++) {
prevS = segmentList.get(i - 1);
currS = segmentList.get(i);
prevB = prevS.endsWith("/");
currB = currS.startsWith("/");
if (!prevB && !currB) {
sb.append("/").append(currS);
} else if (prevB && currB) {
sb.append(currS.substring(1));
} else {
sb.append(currS);
}
}
return sb.toString();
}
对于 Android,请确保使用 android.net.Uri
中的 .appendPath()
方法。
apache.httpclient
的UriBuilder
和java.nio.file.Paths
。String rootUrl = "http://host:80/root/url";
String relativePath = "relative/path";
URIBuilder builder = new URIBuilder(rootUrl);
String combinedPath = Paths.get(builder.getPath(), relativePath).toString();
builder.setPath(combinedPath);
URL targetUrl = builder.build().toURL();
结果为:http://host:80/root/url/relative/path
这适用于任意数量的前导和尾随/
,并且在缺少/
时也可以使用。