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

时间:2009-03-11 23:29:52

标签: java php http build

我有一个包含我的数据的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 ();
}

5 个答案:

答案 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。
  • 硬编码编码看起来很可疑。 UTF-8不是给定的,它必须匹配HTTP请求标头中定义的编码。所以代码应该确保它们确实 - 至少将它定义为某个常量,并在此处和请求编码设置的任何地方引用它。

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