我有一个包含我的数据的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 ();
}
答案 0 :(得分:6)
查看QueryStringBuilder课程及其test class:
private String httpBuildQuery(Map<String, String> data)
throws UnsupportedEncodingException {
QueryStringBuilder builder = new QueryStringBuilder();
for (Entry<String, String> pair : data.entrySet()) {
builder.addQueryParameter(pair.getKey(), pair.getValue());
}
return builder.encode("UTF-8");
}
答案 1 :(得分:2)
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
* <p/>
* <p/>
* 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<String, Object> params, String encoding) {
if (isEmpty(encoding)) {
encoding = "UTF-8";
}
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, Object> entry : params.entrySet()) {
if (sb.length() > 0) {
sb.append('&');
}
String name = entry.getKey();
Object value = entry.getValue();
if (value instanceof Map) {
List<String> baseParam = new ArrayList<String>();
baseParam.add(name);
String str = buildUrlFromMap(baseParam, (Map) value, encoding);
sb.append(str);
} else if (value instanceof Collection) {
List<String> baseParam = new ArrayList<String>();
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<String> baseParam, Map<Object, Object> map, String encoding) {
StringBuilder sb = new StringBuilder();
String token;
//Build string of first level - related with params of provided Map
for (Map.Entry<Object, Object> entry : map.entrySet()) {
if (sb.length() > 0) {
sb.append('&');
}
String name = String.valueOf(entry.getKey());
Object value = entry.getValue();
if (value instanceof Map) {
List<String> baseParam2 = new ArrayList<String>(baseParam);
baseParam2.add(name);
String str = buildUrlFromMap(baseParam2, (Map) value, encoding);
sb.append(str);
} else if (value instanceof List) {
List<String> baseParam2 = new ArrayList<String>(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<String> 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<String> baseParam2 = new ArrayList<String>(baseParam);
baseParam2.add(String.valueOf(i));
String str = buildUrlFromMap(baseParam2, (Map) value, encoding);
sb.append(str);
} else if (value instanceof List) {
List<String> baseParam2 = new ArrayList<String>(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<String> 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<String, Object> params = new LinkedHashMap<String, Object>();
params.put("a", "1");
params.put("b", "2");
params.put("c", "3");
System.out.println(httpBuildQuery(params, "UTF-8"));
}
private static void testWithMap() {
Map<String, Object> params = new LinkedHashMap<String, Object>();
params.put("a", "1");
params.put("b", "2");
Map<String, Object> cParams = new LinkedHashMap<String, Object>();
cParams.put("c1", "c1val");
cParams.put("c2", "c2val");
params.put("c", cParams);
System.out.println(httpBuildQuery(params, "UTF-8"));
}
private static void testWithNestedMap() {
Map<String, Object> params = new LinkedHashMap<String, Object>();
params.put("a", "1");
params.put("b", "2");
Map<String, Object> cParamsLevel1 = new LinkedHashMap<String, Object>();
cParamsLevel1.put("cL1-1", "cLevel1-1val");
cParamsLevel1.put("cL1-2", "cLevel1-2val");
Map<String, Object> cParamsLevel2 = new LinkedHashMap<String, Object>();
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<String, Object> params = new LinkedHashMap<String, Object>();
params.put("a", "1");
params.put("b", "2");
List<Object> cParams = new ArrayList<Object>();
cParams.add("c1val");
cParams.add("c2val");
params.put("c", cParams);
System.out.println(httpBuildQuery(params, "UTF-8"));
}
private static void testWithNestedList() {
Map<String, Object> params = new LinkedHashMap<String, Object>();
params.put("a", "1");
params.put("b", "2");
List<Object> cParamsLevel1 = new ArrayList<Object>();
cParamsLevel1.add("cL1-val1");
cParamsLevel1.add("cL12-val2");
List<Object> cParamsLevel2 = new ArrayList<Object>();
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<String, Object> params = new LinkedHashMap<String, Object>();
//flat
params.put("a", "1");
params.put("b", "2");
//Map level 1
Map<String, Object> cParamsLevel1 = new LinkedHashMap<String, Object>();
cParamsLevel1.put("cL1-1", "cLevel1-1val");
cParamsLevel1.put("cL1-2", "cLevel1-2val");
//Map level 2
Map<String, Object> cParamsLevel2 = new LinkedHashMap<String, Object>();
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<Object> dParamsLevel1 = new ArrayList<Object>();
dParamsLevel1.add("dL1-val1");
dParamsLevel1.add("dL12-val2");
//List level 2
List<Object> dParamsLevel2 = new ArrayList<Object>();
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?a=1&b=2&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
<?php
var_dump($_REQUEST);
?>
答案 2 :(得分:1)
您可能希望在强制使用UTF-8之前检查客户端支持的编码的“Accept”请求标头(即使它可能是最佳选择)。
答案 3 :(得分:1)
这应该是最简单(也是最可靠)的解决方案:
protected static String httpBuildQuery(List<? extends NameValuePair> parameters, String encoding) {
return URLEncodedUtils.format(parameters, encoding).replace("*", "%2A");
}
使用示例:
List<NameValuePair> params = new ArrayList<NameValuePair>;
params.add(new BasicNameValuePair("key", "value"));
String queryString = httpBuildQuery(myParamList, "UTF-8");
Java不编码星号(+
),而PHP编码%2A
应该是唯一的区别。
答案 4 :(得分:0)
看起来不错,有这些警告:
Map<String, String>
,而不是将键和值转换为String。编辑:似乎我对编码错了; HTTP GET参数不受编码头的约束,并且传统上根本没有明确定义的编码。 RFC 3988似乎确实强制要求UTF-8,但这对我来说听起来相当脆弱,所以除非你对服务器有严格的控制并确保它确实也使用了UTF-8,否则我会使用POST请求对于任何不在7位ASCII范围内的数据。