Как преобразовать карту в строку запроса url?
знаете ли вы о каком-либо классе/библиотеке утилит, которые могут конвертировать карту в строку запроса, удобную для URL?
пример:
У меня есть карта:
- "param1" =12,
- "param2" = "cat"
Я хочу сделать: param1=12¶m2=cat.
PS. Я знаю, что могу легко написать его Сам, я просто удивлен, что не могу найти его нигде (я проверил Apache Commons до сих пор).
10 ответов:
самый надежный, который я видел на полке, - это URLEncodedUtils класс Apache Http Compoments (HttpClient 4.0).
метод
URLEncodedUtils.format()это то, что вам нужно.он не использует карту, поэтому вы можете дублировать имена параметров, например,
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("");
весной 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);
Обновление Июня 2016
чувствовал себя вынужденным добавить ответ, увидев слишком много ответов SOF с датированными или неадекватными ответами на очень распространенную проблему-хорошая библиотека и некоторые твердые примеры использования для обоих
parseиformatоперации.использовать org.апаш.httpcomponents.с помощью HttpClient библиотека. Библиотека содержит это org.апаш.http.клиент.utils.URLEncodedUtils служебный класс.
например, легко скачать эту зависимость от Maven:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5</version> </dependency>для моих целей мне нужно было только
parse(чтение из строки запроса в виде пар имя-значение) иformat(чтение из пар имя-значение в строку запроса) строки запроса. Однако существуют эквиваленты для того, чтобы сделать то же самое с URI (см. закомментированную строку ниже).// необходимого импорта
import org.apache.http.NameValuePair; import org.apache.http.client.utils.URLEncodedUtils; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets;// фрагмент кода
public static void parseAndFormatExample() throws UnsupportedEncodingException { final String queryString = "nonce=12345&redirectCallbackUrl=http://www.bbc.co.uk"; System.out.println(queryString); // => nonce=12345&redirectCallbackUrl=http://www.bbc.co.uk final List<NameValuePair> params = URLEncodedUtils.parse(queryString, StandardCharsets.UTF_8); // List<NameValuePair> params = URLEncodedUtils.parse(new URI(url), "UTF-8"); for (final NameValuePair param : params) { System.out.println(param.getName() + " : " + param.getValue()); // => nonce : 12345 // => redirectCallbackUrl : http://www.bbc.co.uk } final String newQueryStringEncoded = URLEncodedUtils.format(params, StandardCharsets.UTF_8); // decode when printing to screen final String newQueryStringDecoded = URLDecoder.decode(newQueryStringEncoded, StandardCharsets.UTF_8.toString()); System.out.println(newQueryStringDecoded); // => nonce=12345&redirectCallbackUrl=http://www.bbc.co.uk }эта библиотека сделала именно то, что мне нужно, и смогла замените какой-нибудь взломанный пользовательский код.
Если вы действительно хотите построить полный URI, попробовать URIBuilder С Apache Http Compoments (HttpClient 4).
на самом деле это не ответ на вопрос, но он ответил на тот, который у меня был, когда я нашел этот вопрос.
Я хотел построить ответ @eclipse, используя отображение и сокращение java 8.
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операция принимает уменьшенную строку и ставит?перед только если строка существует.
это решение я реализовал, используя Java 8 и
org.apache.http.client.URLEncodedUtils. Он отображает записи карты в списокBasicNameValuePairа затем использует ApacheURLEncodedUtilsчтобы превратить это в строку запроса.List<BasicNameValuePair> nameValuePairs = params.entrySet().stream() .map(entry -> new BasicNameValuePair(entry.getKey(), entry.getValue())) .collect(Collectors.toList()); URLEncodedUtils.format(nameValuePairs, Charset.forName("UTF-8"));
еще один "один класс" / без зависимости способ сделать это, обрабатывая один / несколько:
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: { 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); } } }вы можете использовать либо простой (проще написать в большинстве случаев) или несколько при необходимости. Обратите внимание, что оба могут быть объединены путем добавления амперсанда... Если вы обнаружите какие-либо проблемы, дайте мне знать в комментариях.
чтобы немного улучшить ответ @eclipse: в Javaland карта параметров запроса обычно представляется как
Map<String, String[]>, aMap<String, List<String>>илиMultiValueMap<String, String>Это одно и то же. В любом случае: параметр обычно может иметь несколько значений. Поэтому решение 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); } }
Comments