HttpServletRequest - 获取查询字符串参数,不包括表单数据。

98
HttpServletRequest中,getParameterMap返回一个包含所有查询字符串参数和POST数据参数的映射。
有没有一种方法只获取查询字符串参数的映射?我想避免使用getQueryString并解析值。

16
POST请求中也可以拥有查询字符串参数,这些参数都会被“getParameterMap”返回。 - JasonStoltz
哦,好的。为什么需要两者,只是好奇? - Jacob
2
因为在生成的页面上,我希望查询字符串出现在URL中/出现在查询字符串中。我们有一个跟踪系统,可以查找查询字符串中的特定参数。 - JasonStoltz
req.getParameterMap().containsKey("username"); - Parag Jadhav
6个回答

121

如果查询字符串类似于,您可以使用request.getQueryString()

username=james&password=pwd

要获取名称,您可以这样做

request.getParameter("username"); 

这是用于 Java Server 页面的使用。 - Jorgesys
4
第二个请求会破坏请求流,我猜测问题是如何获取用户名并保留输入流以供后续处理。 - Pavel Niedoba
@PavelNiedoba,你能详细说明一下“请求流变得被破坏”的评论吗?为什么会这样? - scrollout

26

与cularis所说的不同,参数映射中可能存在两者。

我认为最好的方法是代理parameterMap,并对于每个参数检索检查queryString是否包含"&?<parameterName>="。

请注意,在进行此检查之前,需要对parameterName进行URL编码,如Qerub所指出的那样。

这样可以节省解析过程,同时仍然只提供URL参数。


2
请注意,在进行此检查之前,需要对 parameterName 进行 URL 编码。 - qerub
18
查询字符串中不包含 ?。这是URI和查询字符串之间的分隔符。 - BalusC
嗨,@DoubleMalt,我的需求也一样,但是我无法获得你提供的解决方案。你能提供示例代码吗? - Vishal Zanzrukia
@VishalZanzrukia:你的代码为什么不能工作? - DoubleMalt
1
我喜欢这个想法,但查询字符串中并不总是有"="字符。如果参数值为空,则查询字符串中只有<parameterName>。我个人认为按"&"和"="拆分会是更好的解决方案。 - Bren

25
Servlet API缺少此功能,因为在创建它时很多人认为查询字符串和消息体只是发送参数的两种不同方式,而没有意识到参数的目的根本不同。查询字符串参数?foo=bar是URL的一部分,因为它们涉及标识资源(可能是许多资源的集合),例如“所有年龄为42岁的人”:GET /persons?age=42,POST或PUT中的消息正文参数用于表达对目标资源的修改,例如将值设置为属性“hair”:PUT /persons?age=42hair=grey,因此同时使用查询参数和正文参数是符合RESTful的,将它们分开以便用于不同的目的。Java Servlet API确实缺少此功能。

17

如其他答案所述,使用servlet api无法获取查询字符串参数。

因此,我认为最好的方法是自己解析查询参数。(迭代参数并检查查询字符串是否包含参数更加复杂)

我编写了下面的代码来获取查询字符串参数。使用支持CSV分隔查询参数值的apache StringUtils和ArrayUtils。

示例:username=james&username=smith&password=pwd1,pwd2将返回

password: [pwd1, pwd2](长度为2)

username: [james, smith](长度为2)

public static Map<String, String[]> getQueryParameters(HttpServletRequest request) throws UnsupportedEncodingException {
    Map<String, String[]> queryParameters = new HashMap<>();
    String queryString = request.getQueryString();
    if (StringUtils.isNotEmpty(queryString)) {
        queryString = URLDecoder.decode(queryString, StandardCharsets.UTF_8.toString());
        String[] parameters = queryString.split("&");
        for (String parameter : parameters) {
            String[] keyValuePair = parameter.split("=");
            String[] values = queryParameters.get(keyValuePair[0]);
            //length is one if no value is available.
            values = keyValuePair.length == 1 ? ArrayUtils.add(values, "") :
                    ArrayUtils.addAll(values, keyValuePair[1].split(",")); //handles CSV separated query param values.
            queryParameters.put(keyValuePair[0], values);
        }
    }
    return queryParameters;
}

我认为这比被接受的答案好多了,不知道为什么要避免解析查询字符串,因为创建代理并不是更好的解决方案。 - Pavel Niedoba
1
我只是在想,如果任何查询参数在其值中包含 & 字符,是否会给您正确的结果。 - amdg
1
@amdg - 该字符将进行URL编码,因此该代码是正确的。如果未编码,则该字符串将无法解析。 - marathon
考虑同时使用 URLDecoder.decode(keyValuePair[0])(或 [1]):https://docs.oracle.com/javase/6/docs/api/java/net/URLDecoder.html - Pluto
此解决方案还可以与以下其中之一结合使用以执行相反的操作(如果使用x-www-form-urlencoded):https://dev59.com/-Gsz5IYBdhLWcg3wHUS0 - Pluto
1
这里没有考虑带有CSV分隔值的查询参数。例如:username=james&username=smith&password=pwd1,pwd2将会生成一个包含两个username值的映射(正确的),但只有一个password值的映射(错误的)。 - Niv

8

Java 8

return Collections.list(httpServletRequest.getParameterNames())
                  .stream()
                  .collect(Collectors.toMap(parameterName -> parameterName, httpServletRequest::getParameterValues));

httpServletRequest.getParameterMap() 就足够了。 - Unmitigated

2

我在POST中使用查询字符串参数,因为我想通过POST保留传递到原始表单的任何和所有查询字符串。这主要是为了跟踪目的...我不确定REST-like约定在这种情况下是否有效,因为我相当确定跟踪库会查找查询字符串中的特定参数。 - JasonStoltz
有什么特别的原因推荐使用REST风格的查询字符串参数吗?不确定我理解其中的优势是什么? - JasonStoltz
8
顺便提一句,缺乏这种API可能意味着你应该检查一下你的设计。在这种情况下,这意味着Oracle应该检查他们的设计 :) - Stijn de Witt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接