有没有Java的http_build_query函数的Java等价物?

我有一个包含我的数据的Map,并希望用它构建一个查询字符串,就像我在PHP上使用http_build_query一样。 我不确定这段代码是否是最好的实现,或者我忘记了什么?

public String toQueryString(Map data) throws UnsupportedEncodingException { StringBuffer queryString = new StringBuffer(); for (Entry pair : data.entrySet()) { queryString.append ( URLEncoder.encode ( (String) pair.getKey (), "UTF-8" ) + "=" ); queryString.append ( URLEncoder.encode ( (String) pair.getValue (), "UTF-8" ) + "&" ); } if (queryString.length () > 0) { queryString.deleteCharAt ( queryString.length () - 1 ); } return queryString.toString (); } 

查看QueryStringBuilder类及其测试类 :

 private String httpBuildQuery(Map data) throws UnsupportedEncodingException { QueryStringBuilder builder = new QueryStringBuilder(); for (Entry pair : data.entrySet()) { builder.addQueryParameter(pair.getKey(), pair.getValue()); } return builder.encode("UTF-8"); } 

PHP http_build_query函数的真正强大之处在于它能够获取关联数组并将其转换为URL字符串。 下面的代码做了类似的事情,它允许url params被构造为包含嵌套Map和Collections的多级Map。除了更多工作之外,还可以添加对Array的支持。

测试方法如下所示。

 import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.*; /** * Class: URLBuilder * User: Gilad Tiram * Date: 6/12/13 * Time: 4:02 PM * 

*

* Utility that helps to build URL String */ public class URLBuilder { /** * Build URL string from Map of params. Nested Map and Collection is also supported * * @param params Map of params for constructing the URL Query String * @param encoding encoding type. If not set the "UTF-8" is selected by default * @return String of type key=value&...key=value * @throws java.io.UnsupportedEncodingException * if encoding isnot supported */ public static String httpBuildQuery(Map params, String encoding) { if (isEmpty(encoding)) { encoding = "UTF-8"; } StringBuilder sb = new StringBuilder(); for (Map.Entry entry : params.entrySet()) { if (sb.length() > 0) { sb.append('&'); } String name = entry.getKey(); Object value = entry.getValue(); if (value instanceof Map) { List baseParam = new ArrayList(); baseParam.add(name); String str = buildUrlFromMap(baseParam, (Map) value, encoding); sb.append(str); } else if (value instanceof Collection) { List baseParam = new ArrayList(); baseParam.add(name); String str = buildUrlFromCollection(baseParam, (Collection) value, encoding); sb.append(str); } else { sb.append(encodeParam(name)); sb.append("="); sb.append(encodeParam(value)); } } return sb.toString(); } private static String buildUrlFromMap(List baseParam, Map map, String encoding) { StringBuilder sb = new StringBuilder(); String token; //Build string of first level - related with params of provided Map for (Map.Entry entry : map.entrySet()) { if (sb.length() > 0) { sb.append('&'); } String name = String.valueOf(entry.getKey()); Object value = entry.getValue(); if (value instanceof Map) { List baseParam2 = new ArrayList(baseParam); baseParam2.add(name); String str = buildUrlFromMap(baseParam2, (Map) value, encoding); sb.append(str); } else if (value instanceof List) { List baseParam2 = new ArrayList(baseParam); baseParam2.add(name); String str = buildUrlFromCollection(baseParam2, (List) value, encoding); sb.append(str); } else { token = getBaseParamString(baseParam) + "[" + name + "]=" + encodeParam(value); sb.append(token); } } return sb.toString(); } private static String buildUrlFromCollection(List baseParam, Collection coll, String encoding) { StringBuilder sb = new StringBuilder(); String token; if (!(coll instanceof List)) { coll = new ArrayList(coll); } List arrColl = (List) coll; //Build string of first level - related with params of provided Map for (int i = 0; i < arrColl.size(); i++) { if (sb.length() > 0) { sb.append('&'); } Object value = (Object) arrColl.get(i); if (value instanceof Map) { List baseParam2 = new ArrayList(baseParam); baseParam2.add(String.valueOf(i)); String str = buildUrlFromMap(baseParam2, (Map) value, encoding); sb.append(str); } else if (value instanceof List) { List baseParam2 = new ArrayList(baseParam); baseParam2.add(String.valueOf(i)); String str = buildUrlFromCollection(baseParam2, (List) value, encoding); sb.append(str); } else { token = getBaseParamString(baseParam) + "[" + i + "]=" + encodeParam(value); sb.append(token); } } return sb.toString(); } private static String getBaseParamString(List baseParam) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < baseParam.size(); i++) { String s = baseParam.get(i); if (i == 0) { sb.append(s); } else { sb.append("[" + s + "]"); } } return sb.toString(); } /** * Check if String is either empty or null * * @param str string to check * @return true if string is empty. Else return false */ public static boolean isEmpty(String str) { return str == null || str.length() == 0; } private static String encodeParam(Object param) { try { return URLEncoder.encode(String.valueOf(param), "UTF-8"); } catch (UnsupportedEncodingException e) { return URLEncoder.encode(String.valueOf(param)); } } /* ========================================================================= */ /* Test functions */ /* ========================================================================= */ public static void main(String[] args) { //basicTest(); //testWithMap(); //testWithList(); //testWithNestedMap(); //testWithNestedList(); testCompound(); } private static void basicTest() { Map params = new LinkedHashMap(); params.put("a", "1"); params.put("b", "2"); params.put("c", "3"); System.out.println(httpBuildQuery(params, "UTF-8")); } private static void testWithMap() { Map params = new LinkedHashMap(); params.put("a", "1"); params.put("b", "2"); Map cParams = new LinkedHashMap(); cParams.put("c1", "c1val"); cParams.put("c2", "c2val"); params.put("c", cParams); System.out.println(httpBuildQuery(params, "UTF-8")); } private static void testWithNestedMap() { Map params = new LinkedHashMap(); params.put("a", "1"); params.put("b", "2"); Map cParamsLevel1 = new LinkedHashMap(); cParamsLevel1.put("cL1-1", "cLevel1-1val"); cParamsLevel1.put("cL1-2", "cLevel1-2val"); Map cParamsLevel2 = new LinkedHashMap(); cParamsLevel2.put("cL2-1", "cLevel2-1val"); cParamsLevel2.put("cL2-2", "cLevel2-2val"); cParamsLevel1.put("cL1-3", cParamsLevel2); params.put("c", cParamsLevel1); System.out.println(httpBuildQuery(params, "UTF-8")); } private static void testWithList() { Map params = new LinkedHashMap(); params.put("a", "1"); params.put("b", "2"); List cParams = new ArrayList(); cParams.add("c1val"); cParams.add("c2val"); params.put("c", cParams); System.out.println(httpBuildQuery(params, "UTF-8")); } private static void testWithNestedList() { Map params = new LinkedHashMap(); params.put("a", "1"); params.put("b", "2"); List cParamsLevel1 = new ArrayList(); cParamsLevel1.add("cL1-val1"); cParamsLevel1.add("cL12-val2"); List cParamsLevel2 = new ArrayList(); cParamsLevel2.add("cL2-val1"); cParamsLevel2.add("cL2-val2"); cParamsLevel1.add(cParamsLevel2); params.put("c", cParamsLevel1); System.out.println(httpBuildQuery(params, "UTF-8")); } private static void testCompound() { Map params = new LinkedHashMap(); //flat params.put("a", "1"); params.put("b", "2"); //Map level 1 Map cParamsLevel1 = new LinkedHashMap(); cParamsLevel1.put("cL1-1", "cLevel1-1val"); cParamsLevel1.put("cL1-2", "cLevel1-2val"); //Map level 2 Map cParamsLevel2 = new LinkedHashMap(); cParamsLevel2.put("cL2-1", "cLevel2-1val"); cParamsLevel2.put("cL2-2", "cLevel2-2val"); cParamsLevel1.put("cL1-3", cParamsLevel2); params.put("c", cParamsLevel1); //List level 1 List dParamsLevel1 = new ArrayList(); dParamsLevel1.add("dL1-val1"); dParamsLevel1.add("dL12-val2"); //List level 2 List dParamsLevel2 = new ArrayList(); dParamsLevel2.add("dL2-val1"); dParamsLevel2.add("dL2-val2"); dParamsLevel1.add(dParamsLevel2); params.put("d", dParamsLevel1); System.out.println(httpBuildQuery(params, "UTF-8")); } }

为了便于测试你的结果,将测试结果附加的字符串附加到指向此PHP的真实URL的查询字符串。 例

 HTTP://localhost/test.php一个= 1&B = 2&amp; C [cL1-1] = cLevel1-1val&C [cL1-2] = cLevel1-2val&C [cL1-3] [cL2-1] = cLevel2-1val&C [cL1- 3] [cL2-2] = cLevel2-2val&d [0] = DL1-VAL1&d [1] = DL12-val2的&d [2] [0] = DL2-VAL1&d [2] [1] = DL2-val2的
  

在强制使用UTF-8之前,您可能想要检查客户端支持的编码的“Accept”请求标头(即使它可能是最佳选择)。

这应该是最简单(也是最可靠)的解决方案:

 protected static String httpBuildQuery(List parameters, String encoding) { return URLEncodedUtils.format(parameters, encoding).replace("*", "%2A"); } 

用法示例:

 List params = new ArrayList; params.add(new BasicNameValuePair("key", "value")); String queryString = httpBuildQuery(myParamList, "UTF-8"); 

Java没有编码星号( + )而PHP编码它%2A应该是唯一的区别。

看起来不错,有这些警告:

  • 使参数成为Map而不是将键和值转换为String。
  • 硬编码编码看起来很可疑。 UTF-8不是给定的,它必须匹配HTTP请求标头中定义的编码。 所以代码应该确保它们确实 – 至少将它定义为某个地方的常量,并在这里和设置请求编码的地方引用它。

编辑:似乎我对编码错了; HTTP GET参数不受编docker的约束,并且传统上根本没有明确定义的编码。 RFC 3988似乎确实强制要求UTF-8,但这对我来说听起来相当脆弱,所以除非你对服务器有严格的控制并且确保它确实也使用了UTF-8,否则我会对任何数据使用POST请求那不是7bit ASCII范围。