1.概述
在本文中,我们将探讨Spring的@RequestParam
注解。
@RequestParam
可以从请求中提取查询参数(query parameters),表单参数(form data)甚至文件。
本文将讨论如何使用@RequestParam
及其属性。还会讨论@RequestParam
和@PathVariable
之间的区别。
2. 一个简单的例子
假设我们有一个终点(endpoint)/api/book
,它接受一个名为id的参数:
@RequestMapping("/api/book")
@ResponseBody
public String getBook(@RequestParam String id) {
return "id : " + id;
}
上面的代码,我们使用 @RequestParam
提取查询参数id。
我们使用CURL来测试一下:
# curl http://localhost:8080/api/book?id=abc
ID: abc%
接下来,让我们看一下这个注解的属性:name, value, required和defaultValue。
3. 指定请求参数名称
在前面的示例中,变量名称和参数名称相同。
但是有时候它们可能会有所不同。我们可以使用name属性来配置@RequestParam
名称:
@RequestMapping("/api/book2")
@ResponseBody
public String getBooks(@RequestParam("id") String bookId, @RequestParam String name) {
return String.format("id: %s; name: %s", bookId, name);
}
我们使用CURL来测试一下:
# curl http://localhost:8080/api/book2?id=abc&name=pei
id: abc; name: pei%
对于@RequestParam
注解,@RequestParam("id")
和@RequestParam(value = "id")
是一样的。
4. 设定请求参数为可选
默认情况下,@RequestParam
注解的参数是必须的,如果不存在,会收到错误。
# curl http://localhost:8080/api/book3?id=abc
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 400 Required String parameter 'name' is not present</title>
</head>
<body><h2>HTTP ERROR 400 Required String parameter 'name' is not present</h2>
<table>
<tr><th>URI:</th><td>/api/book2</td></tr>
<tr><th>STATUS:</th><td>400</td></tr>
<tr><th>MESSAGE:</th><td>Required String parameter 'name' is not present</td></tr>
<tr><th>SERVLET:</th><td>mvc</td></tr>
</table>
<hr><a href="http://eclipse.org/jetty">Powered by Jetty:// 9.4.24.v20191120</a><hr/>
</body>
</html>
查看日志,我们会发现spring会抛出MissingServletRequestParameterException异常:
21:31:26.763 [qtp934993374-17] DEBUG o.s.w.s.m.m.a.ServletInvocableHandlerMethod - Could not resolve parameter [1] in public java.lang.String com.ripjava.spring.mvc.model.controller.RequestParamController.getBooks(java.lang.String,java.lang.String): Required String parameter 'name' is not present
21:31:26.763 [qtp934993374-17] WARN o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'name' is not present]
21:31:26.763 [qtp934993374-17] DEBUG o.s.web.servlet.DispatcherServlet - Completed 400 BAD_REQUEST
如果,我们把@RequestParam
设置为可选的话
@RequestMapping("/api/book3")
@ResponseBody
public String getBooks3(@RequestParam(value = "id",required = false) String bookId, @RequestParam(required = false) String name) {
return String.format("id: %s; name: %s", bookId, name);
}
我来测试一下:
# curl http://localhost:8080/api/book3?id=abc
id: abc; name: null%
# curl http://localhost:8080/api/book3
id: null; name: null%
如果未指定参数,则方法参数会绑定为null。
4.1 使用Java 8 可选
除了使用required参数,我们可以将参数包装在Optional
类中,这样我们不使用required参数,也可以将参数设置为可选。
@RequestMapping("/api/book4")
@ResponseBody
public String getBooks4(@RequestParam(value = "id") Optional<String> bookId, @RequestParam Optional<String> name) {
return String.format("id: %s; name: %s", bookId.orElse("null"), name.orElse("null"));
}
我们来测试一下:
# curl http://localhost:8080/api/book4?id=abc
id: abc; name: null%
# curl http://localhost:8080/api/book4
id: null; name: null%
5. 设定请求参数的默认值
我们还可以使用defaultValue属性将默认值设置为@RequestParam
:
@RequestMapping("/api/book5")
@ResponseBody
public String getBooks5(@RequestParam(value = "id", defaultValue = "null") String bookId, @RequestParam(defaultValue = "null") String name) {
return String.format("id: %s; name: %s", bookId, name);
}
这就像required = false
一样,如果用户不提供参数将使用默认值:
# curl http://localhost:8080/api/book5?id=abc
id: abc; name: default%
# curl http://localhost:8080/api/book5
id: default; name: default%
需要注意的是:当我们设置 defaultValue 属性 时,required被设置为了false。
6. 映射所有的参数
还也可以通过使用Map 来映射多个参数,而不需要定义它们的名称和数量:
@RequestMapping("/api/book6")
@ResponseBody
public String getBooks6(@RequestParam Map<String,String> allParams) {
return allParams.entrySet().stream()
.map(entry -> String.format("name: %s, value:%s ", entry.getKey(), entry.getValue()))
.collect(Collectors.joining(System.lineSeparator()));
}
我们来测试一下:
# curl http://localhost:8080/api/book6?id=abc&name=pei&domin=ripjava
name: name, value:pei
name: domin, value:ripjava
name: id, value:abc %
7.映射参数的多个值到List
一个@RequestParam
可以具有多个值:
@RequestMapping("/api/book7")
@ResponseBody
public String getBooks7(@RequestParam List<String> ids) {
return String.join(",", ids);
}
我们来测试一下:
- 将映射以逗号分隔的参数:
# curl http://localhost:8080/api/book7?ids=one,two,three
one,two,three%
- 单独的参数的列表
# curl http://localhost:8080/api/book7?ids=one&ids=two&ids=three
one,two,three%
8.结论
在本文中,我们学习了如何使用@RequestParam
。
与往常一样,可以在GitHub上找到示例实现。