如何向现有 URL 追加查询参数?

我想将键-值对作为查询参数附加到现有 URL。虽然我可以通过检查 URL 是否有查询部分或片段部分,并通过跳过一堆 if 子句来执行追加,但我想知道是否有干净的方法,如果通过 Apache Commons 库或类似的东西来执行这一操作。

http://example.com就是 http://example.com?name=John

http://example.com#fragment就是 http://example.com?name=John#fragment

http://example.com?email=john.doe@email.com就是 http://example.com?email=john.doe@email.com&name=John

http://example.com?email=john.doe@email.com#fragment就是 http://example.com?email=john.doe@email.com&name=John#fragment

我以前已经多次运行过这个场景,我希望在执行此操作时不会以任何方式破坏 URL。

184072 次浏览

This can be done by using the java.net.URI class to construct a new instance using the parts from an existing one, this should ensure it conforms to URI syntax.

The query part will either be null or an existing string, so you can decide to append another parameter with & or start a new query.

public class StackOverflow26177749 {


public static URI appendUri(String uri, String appendQuery) throws URISyntaxException {
URI oldUri = new URI(uri);


String newQuery = oldUri.getQuery();
if (newQuery == null) {
newQuery = appendQuery;
} else {
newQuery += "&" + appendQuery;
}


return new URI(oldUri.getScheme(), oldUri.getAuthority(),
oldUri.getPath(), newQuery, oldUri.getFragment());
}


public static void main(String[] args) throws Exception {
System.out.println(appendUri("http://example.com", "name=John"));
System.out.println(appendUri("http://example.com#fragment", "name=John"));
System.out.println(appendUri("http://example.com?email=john.doe@email.com", "name=John"));
System.out.println(appendUri("http://example.com?email=john.doe@email.com#fragment", "name=John"));
}
}

Shorter alternative

public static URI appendUri(String uri, String appendQuery) throws URISyntaxException {
URI oldUri = new URI(uri);
return new URI(oldUri.getScheme(), oldUri.getAuthority(), oldUri.getPath(),
oldUri.getQuery() == null ? appendQuery : oldUri.getQuery() + "&" + appendQuery, oldUri.getFragment());
}

Output

http://example.com?name=John
http://example.com?name=John#fragment
http://example.com?email=john.doe@email.com&name=John
http://example.com?email=john.doe@email.com&name=John#fragment

Use the URI class.

Create a new URI with your existing String to "break it up" to parts, and instantiate another one to assemble the modified url:

URI u = new URI("http://example.com?email=john@email.com&name=John#fragment");


// Modify the query: append your new parameter
StringBuilder sb = new StringBuilder(u.getQuery() == null ? "" : u.getQuery());
if (sb.length() > 0)
sb.append('&');
sb.append(URLEncoder.encode("paramName", "UTF-8"));
sb.append('=');
sb.append(URLEncoder.encode("paramValue", "UTF-8"));


// Build the new url with the modified query:
URI u2 = new URI(u.getScheme(), u.getAuthority(), u.getPath(),
sb.toString(), u.getFragment());

There are plenty of libraries that can help you with URI building (don't reinvent the wheel). Here are three to get you started:


Java EE 7

import javax.ws.rs.core.UriBuilder;
...
return UriBuilder.fromUri(url).queryParam(key, value).build();

org.apache.httpcomponents:httpclient:4.5.2

import org.apache.http.client.utils.URIBuilder;
...
return new URIBuilder(url).addParameter(key, value).build();

org.springframework:spring-web:4.2.5.RELEASE

import org.springframework.web.util.UriComponentsBuilder;
...
return UriComponentsBuilder.fromUriString(url).queryParam(key, value).build().toUri();

See also: GIST > URI Builder Tests

I suggest an improvement of the Adam's answer accepting HashMap as parameter

/**
* Append parameters to given url
* @param url
* @param parameters
* @return new String url with given parameters
* @throws URISyntaxException
*/
public static String appendToUrl(String url, HashMap<String, String> parameters) throws URISyntaxException
{
URI uri = new URI(url);
String query = uri.getQuery();


StringBuilder builder = new StringBuilder();


if (query != null)
builder.append(query);


for (Map.Entry<String, String> entry: parameters.entrySet())
{
String keyValueParam = entry.getKey() + "=" + entry.getValue();
if (!builder.toString().isEmpty())
builder.append("&");


builder.append(keyValueParam);
}


URI newUri = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), builder.toString(), uri.getFragment());
return newUri.toString();
}

Kotlin & clean, so you don't have to refactor before code review:

private fun addQueryParameters(url: String?): String? {
val uri = URI(url)


val queryParams = StringBuilder(uri.query.orEmpty())
if (queryParams.isNotEmpty())
queryParams.append('&')


queryParams.append(URLEncoder.encode("$QUERY_PARAM=$param", Xml.Encoding.UTF_8.name))
return URI(uri.scheme, uri.authority, uri.path, queryParams.toString(), uri.fragment).toString()
}

An update to Adam's answer considering tryp's answer too. Don't have to instantiate a String in the loop.

public static URI appendUri(String uri, Map<String, String> parameters) throws URISyntaxException {
URI oldUri = new URI(uri);
StringBuilder queries = new StringBuilder();


for(Map.Entry<String, String> query: parameters.entrySet()) {
queries.append( "&" + query.getKey()+"="+query.getValue());
}


String newQuery = oldUri.getQuery();
if (newQuery == null) {
newQuery = queries.substring(1);
} else {
newQuery += queries.toString();
}


URI newUri = new URI(oldUri.getScheme(), oldUri.getAuthority(),
oldUri.getPath(), newQuery, oldUri.getFragment());


return newUri;
}

For android, Use: https://developer.android.com/reference/android/net/Uri#buildUpon()

URI oldUri = new URI(uri);
Uri.Builder builder = oldUri.buildUpon();
builder.appendQueryParameter("newParameter", "dummyvalue");
Uri newUri =  builder.build();