MapをURLフレンドリーなクエリ文字列に変換できるユーティリティクラス/ライブラリを知っていますか?
例:
私は地図を持っています:
"param1"=12,
"param2"="cat"
私は手に入れたい:
param1=12¶m2=cat
最終出力
relativeUrl+param1=12¶m2=cat
既製の最も堅牢なものは、 Apache Http Compoments (HttpClient 4.0)の RLEncodedUtils クラスです。
メソッドURLEncodedUtils.format()
が必要です。
Mapは使用しないため、次のようにパラメーター名を重複させることができます。
a=1&a=2&b=3
この種のパラメータ名の使用をお勧めするわけではありません。
これは私がすぐに書いたものです。改善できると確信しています。
import Java.util.*;
import Java.io.UnsupportedEncodingException;
import Java.net.URLEncoder;
public class MapQuery {
static String urlEncodeUTF8(String s) {
try {
return URLEncoder.encode(s, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new UnsupportedOperationException(e);
}
}
static String urlEncodeUTF8(Map<?,?> map) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<?,?> entry : map.entrySet()) {
if (sb.length() > 0) {
sb.append("&");
}
sb.append(String.format("%s=%s",
urlEncodeUTF8(entry.getKey().toString()),
urlEncodeUTF8(entry.getValue().toString())
));
}
return sb.toString();
}
public static void main(String[] args) {
Map<String,Object> map = new HashMap<String,Object>();
map.put("p1", 12);
map.put("p2", "cat");
map.put("p3", "a & b");
System.out.println(urlEncodeUTF8(map));
// prints "p3=a+%26+b&p2=cat&p1=12"
}
}
Java 8とpolygenelubricants 'のソリューションを使用して、スムーズなソリューションを見つけました。
parameters.entrySet().stream()
.map(p -> urlEncodeUTF8(p.getKey()) + "=" + urlEncodeUTF8(p.getValue()))
.reduce((p1, p2) -> p1 + "&" + p2)
.orElse("");
Spring Utilには、より良い方法があります。
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
params.add("key", key);
params.add("storeId", storeId);
params.add("orderId", orderId);
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("http://spsenthil.com/order").queryParams(params).build();
ListenableFuture<ResponseEntity<String>> responseFuture = restTemplate.getForEntity(uriComponents.toUriString(), String.class);
実際に完全なURIを構築する場合は、- Apache Http Compoments (HttpClient 4)から RIBuilder を試してください。
これは実際には質問に答えませんが、この質問を見つけたときに私が持っていたものに答えました。
Java 8マッピングと削減を使用して、@ Eclipseの回答を基にしたかった。
protected String formatQueryParams(Map<String, String> params) {
return params.entrySet().stream()
.map(p -> p.getKey() + "=" + p.getValue())
.reduce((p1, p2) -> p1 + "&" + p2)
.map(s -> "?" + s)
.orElse("");
}
余分なmap
操作は、縮小された文字列を取り、?
は、文字列が存在する場合のみ前面にあります。
別の「1つのクラス」/それを行う依存関係のない方法、単一/複数の処理:
import Java.io.UnsupportedEncodingException;
import Java.net.URLEncoder;
import Java.util.ArrayList;
import Java.util.Arrays;
import Java.util.Iterator;
import Java.util.LinkedHashMap;
import Java.util.List;
import Java.util.Map;
import Java.util.Map.Entry;
public class UrlQueryString {
private static final String DEFAULT_ENCODING = "UTF-8";
public static String buildQueryString(final LinkedHashMap<String, Object> map) {
try {
final Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
final StringBuilder sb = new StringBuilder(map.size() * 8);
while (it.hasNext()) {
final Map.Entry<String, Object> entry = it.next();
final String key = entry.getKey();
if (key != null) {
sb.append(URLEncoder.encode(key, DEFAULT_ENCODING));
sb.append('=');
final Object value = entry.getValue();
final String valueAsString = value != null ? URLEncoder.encode(value.toString(), DEFAULT_ENCODING) : "";
sb.append(valueAsString);
if (it.hasNext()) {
sb.append('&');
}
} else {
// Do what you want...for example:
assert false : String.format("Null key in query map: %s", map.entrySet());
}
}
return sb.toString();
} catch (final UnsupportedEncodingException e) {
throw new UnsupportedOperationException(e);
}
}
public static String buildQueryStringMulti(final LinkedHashMap<String, List<Object>> map) {
try {
final StringBuilder sb = new StringBuilder(map.size() * 8);
for (final Iterator<Entry<String, List<Object>>> mapIterator = map.entrySet().iterator(); mapIterator.hasNext();) {
final Entry<String, List<Object>> entry = mapIterator.next();
final String key = entry.getKey();
if (key != null) {
final String keyEncoded = URLEncoder.encode(key, DEFAULT_ENCODING);
final List<Object> values = entry.getValue();
sb.append(keyEncoded);
sb.append('=');
if (values != null) {
for (final Iterator<Object> listIt = values.iterator(); listIt.hasNext();) {
final Object valueObject = listIt.next();
sb.append(valueObject != null ? URLEncoder.encode(valueObject.toString(), DEFAULT_ENCODING) : "");
if (listIt.hasNext()) {
sb.append('&');
sb.append(keyEncoded);
sb.append('=');
}
}
}
if (mapIterator.hasNext()) {
sb.append('&');
}
} else {
// Do what you want...for example:
assert false : String.format("Null key in query map: %s", map.entrySet());
}
}
return sb.toString();
} catch (final UnsupportedEncodingException e) {
throw new UnsupportedOperationException(e);
}
}
public static void main(final String[] args) {
// Examples: could be turned into unit tests ...
{
final LinkedHashMap<String, Object> queryItems = new LinkedHashMap<String, Object>();
queryItems.put("brand", "C&A");
queryItems.put("count", null);
queryItems.put("misc", 42);
final String buildQueryString = buildQueryString(queryItems);
System.out.println(buildQueryString);
}
{
final LinkedHashMap<String, List<Object>> queryItems = new LinkedHashMap<String, List<Object>>();
queryItems.put("usernames", new ArrayList<Object>(Arrays.asList(new String[] { "bob", "john" })));
queryItems.put("nullValue", null);
queryItems.put("misc", new ArrayList<Object>(Arrays.asList(new Integer[] { 1, 2, 3 })));
final String buildQueryString = buildQueryStringMulti(queryItems);
System.out.println(buildQueryString);
}
}
}
必要に応じて、シンプル(ほとんどの場合、書きやすい)または複数を使用できます。アンパサンドを追加することで両方を組み合わせることができることに注意してください...問題が見つかった場合は、コメントでお知らせください。
これは、Java 8とorg.Apache.http.client.URLEncodedUtils
]を使用して実装したソリューションです。マップのエントリをBasicNameValuePair
のリストにマップし、ApacheのURLEncodedUtils
を使用してクエリ文字列に変換します。
List<BasicNameValuePair> nameValuePairs = params.entrySet().stream()
.map(entry -> new BasicNameValuePair(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
URLEncodedUtils.format(nameValuePairs, Charset.forName("UTF-8"));
これにはStream
を使用できますが、クエリパラメータを自分で追加する代わりに、Uri.Builder
を使用します。例えば:
final Map<String, String> map = new HashMap<>();
map.put("param1", "cat");
map.put("param2", "12");
final Uri uri =
map.entrySet().stream().collect(
() -> Uri.parse("relativeUrl").buildUpon(),
(builder, e) -> builder.appendQueryParameter(e.getKey(), e.getValue()),
(b1, b2) -> { throw new UnsupportedOperationException(); }
).build();
//Or, if you consider it more readable...
final Uri.Builder builder = Uri.parse("relativeUrl").buildUpon();
map.entrySet().forEach(e -> builder.appendQueryParameter(e.getKey(), e.getValue())
final Uri uri = builder.build();
//...
assertEquals(Uri.parse("relativeUrl?param1=cat¶m2=12"), uri);
@Eclipseの答えを少し改善するために:Javalandでは、リクエストパラメータマップは通常Map<String, String[]>
、_Map<String, List<String>>
または場合によってはMultiValueMap<String, String>
これは同じものです。いずれの場合でも、パラメーターは通常複数の値を持つことができます。 A Java 8ソリューションは、これらの行に沿ったものになります。
public String getQueryString(HttpServletRequest request, String encoding) {
Map<String, String[]> parameters = request.getParameterMap();
return parameters.entrySet().stream()
.flatMap(entry -> encodeMultiParameter(entry.getKey(), entry.getValue(), encoding))
.reduce((param1, param2) -> param1 + "&" + param2)
.orElse("");
}
private Stream<String> encodeMultiParameter(String key, String[] values, String encoding) {
return Stream.of(values).map(value -> encodeSingleParameter(key, value, encoding));
}
private String encodeSingleParameter(String key, String value, String encoding) {
return urlEncode(key, encoding) + "=" + urlEncode(value, encoding);
}
private String urlEncode(String value, String encoding) {
try {
return URLEncoder.encode(value, encoding);
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Cannot url encode " + value, e);
}
}
Javaこれを行うために組み込まれているものはありません。しかし、ちょっと、Javaはプログラミング言語なので、プログラムしてみましょう!
_map.values().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"))
_
これにより、「param1 = 12&param2 = cat」が得られます。ここで、URLとこのビットを結合する必要があります。 _URL + "?" + theAbove
_でもできると思いますが、URLに疑問符が既に含まれている場合は、代わりに「&」ですべてを結合する必要があります。確認する1つの方法は、URLのどこかに疑問符が既にあるかどうかを確認することです。
また、私はあなたの地図に何が含まれているのかよくわかりません。それが生のものであれば、おそらく_URLEncoder.encode
_または同様のe.getKey()
およびe.getValue()
への呼び出しを保護する必要があります。
さらに別の方法は、より広い視野をとることです。マップのコンテンツをURLに追加しようとしていますか?...マップの内容を(追加)としてJavaプロセスからHTTP(S)リクエストを作成しようとしていますかHTTP params?後者の場合、 OkHttp のようなhttpライブラリを調べることができます。これには、このジョブを実行するニースAPIがあります。 。
EntrySetとStreamsの使用:
map
.entrySet()
.stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining("&"));
個人的に、私はこのような解決策を求めます。それは@rzwitserlootによって提供される解決策に非常に似ていますが、わずかな違いがあります。
このソリューションは小さく、シンプルでクリーンです。依存関係の点ではほとんど必要ありません。それらはすべてJava Utilパッケージの一部です。
Map<String, String> map = new HashMap<>();
map.put("param1", "12");
map.put("param2", "cat");
String output = "someUrl?";
output += map.entrySet()
.stream()
.map(x -> x.getKey() + "=" + x.getValue() + "&")
.collect(Collectors.joining("&"));
System.out.println(output.substring(0, output.length() -1));