Java EE有ServletRequest.getParameterValues()。

在非ee平台上,URL.getQuery()只是返回一个字符串。

当不在Java EE上时,正确解析URL中的查询字符串的正常方法是什么?


在回答中,尝试创建自己的解析器是很受欢迎的。这是一个非常有趣和令人兴奋的微编码项目,但我不能说这是一个好主意。

下面的代码段通常是有缺陷或损坏的。对读者来说,打破它们是一项有趣的练习。还有攻击使用它们的网站的黑客。

解析查询字符串是一个明确定义的问题,但阅读规范并理解其中的细微差别并非易事。最好是让一些平台库编码器为您做艰苦的工作,并进行修复!


当前回答

public static Map <String, String> parseQueryString (final URL url)
        throws UnsupportedEncodingException
{
    final Map <String, String> qps = new TreeMap <String, String> ();
    final StringTokenizer pairs = new StringTokenizer (url.getQuery (), "&");
    while (pairs.hasMoreTokens ())
    {
        final String pair = pairs.nextToken ();
        final StringTokenizer parts = new StringTokenizer (pair, "=");
        final String name = URLDecoder.decode (parts.nextToken (), "ISO-8859-1");
        final String value = URLDecoder.decode (parts.nextToken (), "ISO-8859-1");
        qps.put (name, value);
    }
    return qps;
}

其他回答

你说“Java”,但“不是Java EE”。您的意思是您正在使用JSP和/或servlet,而不是完整的Java EE堆栈?如果是这种情况,那么您应该仍然可以使用request.getParameter()。

如果你的意思是你正在编写Java,但你没有编写jsp或servlet,或者你只是使用Java作为参考点,但你在一些没有内置参数解析的其他平台上……哇,这听起来像是一个不太可能的问题,但如果是这样的话,原则是:

xparm=0
word=""
loop
  get next char
  if no char
    exit loop
  if char=='='
    param_name[xparm]=word
    word=""
  else if char=='&'
    param_value[xparm]=word
    word=""
    xparm=xparm+1
  else if char=='%'
    read next two chars
    word=word+interpret the chars as hex digits to make a byte
  else
    word=word+char

(我可以编写Java代码,但这将是毫无意义的,因为如果您有Java可用,您可以只使用request.getParameters。)

原来在这里回答

在Android上,android.net包中有Uri类。请注意,Uri是android.net的一部分,而Uri是java.net的一部分。

Uri类有很多提取查询键值对的函数。

下面的函数以HashMap的形式返回键值对。

在Java中:

Map<String, String> getQueryKeyValueMap(Uri uri){
    HashMap<String, String> keyValueMap = new HashMap();
    String key;
    String value;

    Set<String> keyNamesList = uri.getQueryParameterNames();
    Iterator iterator = keyNamesList.iterator();

    while (iterator.hasNext()){
        key = (String) iterator.next();
        value = uri.getQueryParameter(key);
        keyValueMap.put(key, value);
    }
    return keyValueMap;
}

在芬兰湾的科特林:

fun getQueryKeyValueMap(uri: Uri): HashMap<String, String> {
        val keyValueMap = HashMap<String, String>()
        var key: String
        var value: String

        val keyNamesList = uri.queryParameterNames
        val iterator = keyNamesList.iterator()

        while (iterator.hasNext()) {
            key = iterator.next() as String
            value = uri.getQueryParameter(key) as String
            keyValueMap.put(key, value)
        }
        return keyValueMap
    }

对于servlet或JSP页面,您可以使用request.getParameter("paramname")获取查询字符串的键/值对。

String name = request.getParameter("name");

还有其他方法,但我在创建的所有servlet和jsp页面中都是这样做的。

在Android上,我尝试使用@diyism回答,但我遇到了@rpetrich提出的空格字符问题,例如: 我填写了一个表单,其中用户名=“us+us”和密码=“pw pw”,导致URL字符串如下:

http://somewhere?username=us%2Bus&password=pw+pw

但是,@diyism代码返回“us+us”和“pw+pw”,即它不检测空格字符。如果URL被%20重写,空格字符将被识别:

http://somewhere?username=us%2Bus&password=pw%20pw

这导致以下修复:

Uri uri = Uri.parse(url_string.replace("+", "%20"));
uri.getQueryParameter("para1");

自从Android M之后,事情变得更加复杂。android.net.URI.getQueryParameter()的答案有一个错误,在JellyBean之前打破空格。 Apache URLEncodedUtils.parse()可以工作,但在L中已弃用,在M中已被删除。

所以现在最好的答案是UrlQuerySanitizer。它从API级别1开始就存在,现在仍然存在。它还使您考虑一些棘手的问题,如如何处理特殊字符或重复值。

最简单的代码是

UrlQuerySanitizer.ValueSanitizer sanitizer = UrlQuerySanitizer.getAllButNullLegal();
// remember to decide if you want the first or last parameter with the same name
// If you want the first call setPreferFirstRepeatedParameter(true);
sanitizer.parseUrl(url);
String value = sanitizer.getValue("paramName");

如果你对默认的解析行为满意,你可以这样做:

new UrlQuerySanitizer(url).getValue("paramName")

但是您应该确保了解默认的解析行为是什么,因为它可能不是您想要的。