如何将map转换为url查询字符串?

Ula*_*kar 66 java utilities java-ee

你知道任何实用程序类/库,可以将Map转换为URL友好的查询字符串吗?

示例:
我有一张地图:
- "param1"= 12,
- "param2"="cat"

我想得到:__CODE__.

PS.我知道我可以轻松地自己编写,我很惊讶我无法在任何地方找到它(我到目前为止检查了Apache Commons).

ZZ *_*der 61

我现在看到的最强大的是来自Apache Http Compoments(HttpClient 4.0)的URLEncodedUtils类.

这个方法URLEncodedUtils.format()就是你所需要的.

它不使用map,因此你可以有重复的参数名称,比如

  a=1&a=2&b=3
Run Code Online (Sandbox Code Playgroud)

不是我推荐这种参数名称的使用.

  • @UlaKrukar,这是因为map <string,string>是错误的数据结构.它不保留顺序,也不允许重复键. (9认同)
  • 它接近我的需要.唯一的问题是它需要NameValuePair对象,而我最多只有Map.Entry对象. (3认同)
  • @Jonik,这正是我要做的:)但我仍感到惊讶的是,没有任何东西只需要一张地图,看起来很明显应该.有很多方法可以将查询字符串转换为映射,而没有任何方法可以执行相反的操作. (3认同)
  • LinkedHashMap 可以很好地工作......来自 Groovy 的 URIBuilder 接受 Map 接口来生成 queryString (3认同)

pol*_*nts 40

这是我很快写的东西; 我相信它可以改进.

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"
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 编写自己的并不难,问题是在哪里,如果有的话,有一个现成的版本. (8认同)
  • 参数map**通常**表示为`Map <String,List <String >>`或`Map <String,String []>`.您可以为同一个名称设置多个值.不确定OP是否很聪明地设计它. (5认同)

ecl*_*pse 29

我找到了使用java 8和polygenelubricants解决方案的平滑解决方案.

parameters.entrySet().stream()
    .map(p -> urlEncodeUTF8(p.getKey()) + "=" + urlEncodeUTF8(p.getValue()))
    .reduce((p1, p2) -> p1 + "&" + p2)
    .orElse("");
Run Code Online (Sandbox Code Playgroud)

  • 数组呢?``toto [] = 4&toto [] = 5`` (3认同)

Sen*_* SP 16

在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);
Run Code Online (Sandbox Code Playgroud)


arc*_*don 16

2016年6月更新

感到有必要增加一个答案见过有过时或不充分的答案很常见的问题太多太多的SOF的答案-一个好的图书馆和两个固体一些例如使用parseformat操作.

使用org.apache.httpcomponents.httpclient库.该库包含此org.apache.http.client.utils.URLEncodedUtils类实用程序.

例如,从Maven下载这个依赖项很容易:

 <dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5</version>
 </dependency>
Run Code Online (Sandbox Code Playgroud)

出于我的目的,我只需要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;
Run Code Online (Sandbox Code Playgroud)

//代码段

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
    }
Run Code Online (Sandbox Code Playgroud)

这个库完全符合我的需要,并能够替换一些被黑客入侵的自定义代码.


Thr*_*idh 10

如果你真的想建立一个完整的URI,尝试URIBuilder的Apache HTTP元件库(HttpClient的4).

这实际上并没有回答这个问题,但它回答了我在发现这个问题时的问题.


sbz*_*oom 8

我想使用java 8映射和reduce来构建@ 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("");
Run Code Online (Sandbox Code Playgroud)

}

额外的map操作采用缩减的字符串,并且?仅在字符串存在时才放在前面.

  • 如果参数值包含特殊字符,不编码会产生问题 (2认同)

Chr*_*ssy 7

另一种"一类"/无依赖方式,处理单个/多个:

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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用简单(在大多数情况下更容易编写)或在需要时使用多个.请注意,两者都可以通过添加&符组合...如果您发现任何问题,请在评论中告诉我.


Mar*_*des 6

这是我使用 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"));
Run Code Online (Sandbox Code Playgroud)


rzw*_*oot 6

Java 中没有内置任何东西来执行此操作。但是,嘿,Java 是一种编程语言,所以。让我们来编程吧!

map
.entrySet()
.stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining("&"))
Run Code Online (Sandbox Code Playgroud)

这给了你param1=12&param2=cat。现在我们需要将 URL 和这个位连接在一起。您可能认为可以这样做:URL + "?" + theAbove但如果 URL 已经包含问号,则必须用“&”将其全部连接在一起。一种检查方法是查看 URL 中的某个位置是否已存在问号。

另外,我不太清楚你的地图上有什么。e.getKey()如果它是原始的东西,您可能必须保护对and e.getValue()with或类似的调用URLEncoder.encode

另一种方法是视野更广阔。您是否尝试将地图的内容附加到 URL,或者...您是否尝试从 Java 进程发出 HTTP (S) 请求,并将地图中的内容作为(附加)HTTP 参数?在后一种情况下,您可以查看像OkHttp这样的 HTTP 库,它有一些很好的 API 来完成这项工作,然后您就可以首先放弃对该 URL 的任何修改。