Есть ли в Java эквивалент функции http_build_query в PHP? - PullRequest
8 голосов
/ 12 марта 2009

У меня есть Map с моими данными, и я хочу создать строку запроса с ней, как если бы я использовал http_build_query на PHP. Я не уверен, является ли этот код лучшей реализацией или я что-то забыл?

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 ]

6 голосов
/ 22 марта 2009

посмотрите на класс QueryStringBuilder и его тестовый класс :

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");
}
2 голосов
/ 12 июня 2013

Истинная сила функции PHP http_build_query заключается в ее способности получать ассоциативный массив и переводить его в строку URL. Следующий код выполняет аналогичные действия, и он позволяет создавать URL-параметры в виде многоуровневой карты, которая включает в себя вложенные карту и коллекции. По мере проделывания этой работы можно также добавить поддержку массива.

Методы испытаний приведены ниже.

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"));

}

}

Для простоты проверки ваших результатов добавьте строку, полученную в результате проверки, как строку запроса реального URL, указывающую на этот PHP. Пример

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);
?>
1 голос
/ 19 февраля 2014

Это должно быть самое простое (и самое надежное) решение:

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 должно быть единственным отличием.

1 голос
/ 22 марта 2009

Возможно, вы захотите проверить заголовок запроса «Принять» для кодировок, поддерживаемых клиентом, перед форсированием UTF-8 (хотя это, вероятно, лучший выбор).

0 голосов
/ 12 марта 2009

Выглядит хорошо, с этими предостережениями:

  • делает параметр Map<String, String> вместо того, чтобы приводить ключ и значение к String.
  • жестко закодированная кодировка выглядит подозрительно. UTF-8 не является заданным, он должен соответствовать кодировке, определенной в заголовке HTTP-запроса. Таким образом, код должен гарантировать, что они это делают - по крайней мере, определить его как константу где-нибудь и ссылаться на это как здесь, так и везде, где установлена ​​кодировка запроса.

Редактировать: Кажется, я ошибся в кодировке; Параметры HTTP GET не подчиняются заголовку кодировки и обычно вообще не имеют четко определенной кодировки. RFC 3988 , похоже, действительно требует UTF-8, но это звучит довольно хрупко для меня, поэтому, если вы не обладаете жестким контролем над сервером и не можете гарантировать, что он действительно использует UTF-8, я бы используйте запросы POST для любых данных, которые не находятся в 7-битном диапазоне ASCII.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...