Spring Boot - 请求参数接收
笔记
一直没时间总结 Spring Controller 接收参数的多种方式,只记得常用的 GET、POST 接收,而一些 List、Map 参数的接收却经常忘记怎么接收,每次都只能百度,所以现在总结不同的接收请求参数方式。
2022-12-12 @Young Kbt
# 支持的请求模式
GET 方式:主要用于简单查询,使用注解:@GetMapping
或者 @RequestMapping(method = RequestMethod.GET)
POST 方式:主要用于复杂查询或数据添加,使用注解:@PostMapping
或者 @RequestMapping(method = RequestMethod.POST)
HEAD、PUT、PATCH、DELETE、OPTIONS、TRACE 等方式不常用。
# 说明
- 项目端口为 8085,在本地运行,所以是
http://localhost:8085
- 内容用到了
@Slf4j
日志输出,安装了 lombok 依赖即可使用 - 推荐使用
@GetMapping
或者@PostPostMapping
看起来明确的请求方式 @RequestParam
只能用于 URL 后面 ? 携带参数的链接,@RequestBody
只能用于 JSON 格式的链接- 标题有 通用,代表 GET 和 POST 请求使用方式都一样,所以 POST 请求内容不再描述
- 其实通过 URL 后面 ? 携带参数的链接,POST 和 GET 都是获取方式通用,只是 POST 需要的是更安装的传输:RequestBody
# GET 请求
# 基本类型参数注入(通用)
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/simpleGet")
public void simpleGet(String name, String age) {
log.info("接收的参数:{}, {}", name, age);
}
}
2
3
4
5
6
7
8
9
10
请求连接:http://localhost:8085/test/simpleGet?name=kele&age=18
。
日志输入:
2022-12-12 21:55:24.535 INFO 18888 --- [nio-8085-exec-1] com.pxw.mit.controller.TestController : 接收的参数:kele, 18
# 指定参数注入(通用)
如果前端传来的链接和参数名不一致时,则需要指定前端传来的参数,用到 @RequestParam
注解。
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/appointGet")
public void appointGet(@RequestParam("name1") String name, @RequestParam("age1") String age) {
log.info("接收的参数:{}, {}", name, age);
}
}
2
3
4
5
6
7
8
9
10
请求连接:http://localhost:8085/test/appointGet?name1=bingtang&age1=17
。
日志输出:
2022-12-12 22:01:03.398 INFO 4024 --- [nio-8085-exec-2] com.pxw.mit.controller.TestController : 接收的参数:bingtang, 17
# 占位符参数注入(通用)
@PathVariable
映射 URL 绑定的 占位符。
通过 @PathVariable
可以将 URL 中占位符参数绑定到控制器处理方法的入参中 URL 中的 {xxx}。
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/pathVariableGet/{name}/{age}")
public void pathVariableGet(@PathVariable String name, @PathVariable String age) {
log.info("接收的参数:{}, {}", name, age);
}
}
2
3
4
5
6
7
8
9
10
请求连接:http://localhost:8085/test/pathVariableGet/xueli/18
。
日志输出:
2022-12-12 22:08:31.110 INFO 11260 --- [nio-8085-exec-2] com.pxw.mit.controller.TestController : 接收的参数:xueli, 18
可以看到和 ? 方式比读起来更加舒服。
如果参数名称和地址占位符不一致,则需要利用 @PathVariable
指定。
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/pathVariableGet/{name1}/{age1}")
public void pathVariableGet(@PathVariable("name1") String name, @PathVariable("age1") String age) {
log.info("接收的参数:{}, {}", name, age);
}
}
2
3
4
5
6
7
8
9
10
11
请求连接:http://localhost:8085/test/pathVariableGet/xueli/18
。
日志输出:
2022-12-12 22:10:53.839 INFO 16900 --- [nio-8085-exec-3] com.pxw.mit.controller.TestController : 接收的参数:xueli, 18
# 实体类参数注入(通用)
简单
可以自定义一个实体类,属性和前端传来的参数名一致,且有 setter 和 getter 方法即可自动注入。
public class User {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
测试
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/beanGet")
public void beanGet(User user) {
log.info("接收的参数:{}, {}", user.getName(), user.getAge());
}
}
2
3
4
5
6
7
8
9
10
请求链接:http://localhost:8085/test/beanGet?name=xueli&age=17
。
日志输出:
2022-12-12 22:20:29.293 INFO 4404 --- [nio-8085-exec-3] com.pxw.mit.controller.TestController : 接收的参数:xueli, 17
多个重复的实体类
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/beanGet")
public void beanGet(User user1, User user2) {
log.info("接收的参数1:{}, {}", user1.getName(), user1.getAge());
log.info("接收的参数2:{}, {}", user2.getName(), user2.getAge());
}
}
2
3
4
5
6
7
8
9
10
11
请求链接:http://localhost:8085/test/beanGet?name=xueli&age=17
。
日志输出:
2022-12-12 22:24:17.323 INFO 1824 --- [nio-8085-exec-2] com.pxw.mit.controller.TestController : 接收的参数1:xueli, 17
2022-12-12 22:24:17.324 INFO 1824 --- [nio-8085-exec-2] com.pxw.mit.controller.TestController : 接收的参数2:xueli, 17
2
可以看出,只要前端传来的参数名和实体类的属性名匹配,则全部注入进去。
多个不相同的实体类
其实从上面也可以看出,只要属性名匹配,则不管多少个实体类,都注入。
准备一个新的类 Other
public class Other {
private String email;
private String phone;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
测试
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/beanGet")
public void beanGet(User user, Other other) {
log.info("接收的参数1:{}, {}", user.getName(), user.getAge());
log.info("接收的参数2:{}, {}", other.getEmail(), other.getPhone());
}
}
2
3
4
5
6
7
8
9
10
11
请求链接:http://localhost:8085/test/beanGet?name=xueli&age=17
。
日志输出:
2022-12-12 22:29:41.427 INFO 17612 --- [nio-8085-exec-7] com.pxw.mit.controller.TestController : 接收的参数1:xueli, 17
2022-12-12 22:29:41.427 INFO 17612 --- [nio-8085-exec-7] com.pxw.mit.controller.TestController : 接收的参数2:2456@qq.com, 13377456541
2
这里就不「部分相同的实体类」了,如果参数存在 实体类和基本类型参数,只要参数名匹配,都全部注入。
总结:GET 请求中,只要实体类的属性名或者基本类型参数名能匹配,则不管多少个实体类,都注入值。
# 实体类 List 集合
虽然是 GET 请求,但是一旦用到 List 集合,就需要满足两个条件:
- 使用
@RequestBody
- 参数必须是 JSON 格式(POST 请求的传参方式),不能是在 URL
?
后面
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/listBeanGet")
public void listBeanGet(@RequestBody List<User> user) {
log.info("接收的参数:{}", user);
}
}
2
3
4
5
6
7
8
9
10
请求链接:http://localhost:8085/test/listBeanGet
。
JSON 参数:
[
{
"name": "kele",
"age": "18"
},
{
"name": "bingtang",
"age": "17"
}
]
2
3
4
5
6
7
8
9
10
如图:
日志输出:
2022-12-12 22:41:32.873 INFO 3452 --- [nio-8085-exec-1] com.pxw.mit.controller.TestController : 接收的参数:[User(name=kele, age=18), User(name=bingtang, age=17)]
如果多个 List 集合的参数怎么办?
如:
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/listBeanGet")
public void listBeanGet(@RequestBody List<User> user, List<Other> othe) {
log.info("接收的参数:{}", user);
}
}
2
3
4
5
6
7
8
9
10
这样是 不行的,出现异常的,目前我暂未发现如何注入两种对象集合类型。
注意:@RequestBody
在一个方法里只能用一次,因为 @RequestBody
修饰的参数一旦注入了数据,那么请求流将关闭,这样后面 @RequestBody
修饰的其他参数无法获取数据,并且抛出异常。
# 基本类型 List 集合(通用)
- 需要使用
@RequestParam
修饰才能接收 List 集合
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/listSimpleGet")
public void listSimpleGet(@RequestParam List<String> name) {
log.info("接收的参数:{}", name);
}
}
2
3
4
5
6
7
8
9
10
11
请求连接:http://localhost:8085/test/listSimpleGet?name=kele&name=xueli
日志输出:
2022-12-12 22:52:24.627 INFO 10784 --- [nio-8085-exec-4] com.pxw.mit.controller.TestController : 接收的参数:[kele, xueli]
name 和前端的传参名一致。
参数名和前端传来的不一致
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/listSimpleGet")
public void listSimpleGet(@RequestParam("name1") List<String> name) {
log.info("接收的参数:{}", name);
}
}
2
3
4
5
6
7
8
9
10
请求连接:http://localhost:8085/test/listSimpleGet?name1=kele&name1=xueli
。
日志输出:
2022-12-12 22:54:33.958 INFO 27768 --- [nio-8085-exec-2] com.pxw.mit.controller.TestController : 接收的参数:[kele, xueli]
多个 List 参数
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/listSimpleGet")
public void listSimpleGet(@RequestParam List<String> name, @RequestParam List<String> age) {
log.info("接收的参数1:{}", name);
log.info("接收的参数2:{}", age);
}
}
2
3
4
5
6
7
8
9
10
11
请求连接:http://localhost:8085/test/listSimpleGet?name=kele&age=18&name=xueli&age=17
。
日志输出:
2022-12-12 22:57:51.469 INFO 9972 --- [nio-8085-exec-4] com.pxw.mit.controller.TestController : 接收的参数1:[kele, xueli]
2022-12-12 22:57:51.470 INFO 9972 --- [nio-8085-exec-4] com.pxw.mit.controller.TestController : 接收的参数2:[18, 17]
2
同理,只要前端传入的参数名和后端接收的一致,则可以注入。
# 基本类型 Map 类型(通用)
Map 参数需要用 @RequestParam
修饰才能接收。
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/mapSimpleGet")
public void mapSimpleGet(@RequestParam Map<String, String> map) {
log.info("接收的参数:{}", map);
}
}
2
3
4
5
6
7
8
9
10
请求链接:http://localhost:8085/test/mapSimpleGet?name=kele&age=18
。
日志输出:
2022-12-12 23:03:52.587 INFO 31556 --- [nio-8085-exec-1] com.pxw.mit.controller.TestController : 接收的参数:{name=kele, age=18}
多个 Map
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/mapSimpleGet")
public void mapSimpleGet(@RequestParam Map<String, String> map1, @RequestParam Map<String, String> map2) {
log.info("接收的参数1:{}", map1);
log.info("接收的参数2:{}", map2);
}
}
2
3
4
5
6
7
8
9
10
11
请求链接:http://localhost:8085/test/mapSimpleGet?name=kele&age=18
。
日志输出:
2022-12-12 23:05:12.785 INFO 2488 --- [nio-8085-exec-3] com.pxw.mit.controller.TestController : 接收的参数1:{name=kele, age=18}
2022-12-12 23:05:12.785 INFO 2488 --- [nio-8085-exec-3] com.pxw.mit.controller.TestController : 接收的参数2:{name=kele, age=18}
2
无论多少个,依然全部注入。
注意:参数的 Map<String, String>
泛型可以随便填,如 Map<String, Integer>
、Map<String, User>
,Spring 不会管你的 Map 泛型,它默认都是 Map<String, String>
注入。
# 基本类型数组(通用)
直接接收即可
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/arraySimpleGet")
public void arraySimpleGet(String[] name) {
log.info("接收的参数:{}, {}", name[0], name[1]);
}
}
2
3
4
5
6
7
8
9
10
请求链接:http://localhost:8085/test/arraySimpleGet?name=kele&name=xueli
。
日志输出:
2022-12-12 23:14:44.518 INFO 22476 --- [nio-8085-exec-3] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
2022-12-12 23:14:44.534 INFO 22476 --- [nio-8085-exec-3] com.pxw.mit.controller.TestController : 接收的参数:kele, xueli
2
前端传来的参数名和后端参数名不一样
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/arraySimpleGet")
public void arraySimpleGet(@RequestParam("name1") String[] name) {
log.info("接收的参数:{}, {}", name[0], name[1]);
}
}
2
3
4
5
6
7
8
9
10
请求链接:http://localhost:8085/test/arraySimpleGet?name=kele&name=xueli
。
日志输出:
2022-12-12 23:15:54.526 INFO 17492 --- [nio-8085-exec-1] com.pxw.mit.controller.TestController : 接收的参数:kele, xueli
多个数组参数
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/arraySimpleGet")
public void arraySimpleGet(String[] name, String[] age) {
log.info("接收的参数1:{}, {}", name[0], name[1]);
log.info("接收的参数2:{}, {}", age[0], age[1]);
}
}
2
3
4
5
6
7
8
9
10
11
请求链接:http://localhost:8085/test/arraySimpleGet?name=kele&age=18&name=xueli&age=17
。
日志输出:
2022-12-12 23:17:37.961 INFO 25276 --- [nio-8085-exec-2] com.pxw.mit.controller.TestController : 接收的参数1:kele, xueli
2022-12-12 23:17:37.961 INFO 25276 --- [nio-8085-exec-2] com.pxw.mit.controller.TestController : 接收的参数2:18, 17
2
# POST 请求 - JSON
为了简洁,POST 请求的代码块直接写方法,类始终是上面的 TestController 类。
注意此时的请求链接是 POST 请求,且 @RequestBody
只接收 JSON 参数。
GET 请求里,除了 实体类 List 集合 外,其他的方式 POST 通用(URL 后面 ? 携带参数)。
说明:一个方法里
@RequestBody
只能用一次,也就是说接收的 JSON 只能有一个参数接收,其他参数只能从其他方式如 URL ? 后面传过来
因为 @RequestBody
执行一次后,就关闭请求流,导致其他 @RequestBody
修饰的参数无法获取 JSON,然后抛出异常。
# 基本类型参数注入
@PostMapping("/simplePost")
public void simplePost(@RequestBody String str) {
log.info("接收的参数:{}", str);
}
2
3
4
请求链接:http://localhost:8085/test/simplePost
。
JSON 参数:
{
"name": "kele",
"age": "18"
}
2
3
4
日志输出:
2022-12-12 23:34:07.042 INFO 26364 --- [nio-8085-exec-2] com.pxw.mit.controller.TestController : 接收的参数:{
"name": "kele",
"age": "18"
}
2
3
4
这是个字符串。
# 实体类参数注入
@PostMapping("/beanPost")
public void beanPost(@RequestBody User user) {
log.info("接收的参数:{}, {}", user.getName(), user.getAge());
}
2
3
4
请求链接:http://localhost:8085/test/beanPost
。
JSON 参数:
{
"name": "kele",
"age": "18"
}
2
3
4
输出日志:
2022-12-12 23:36:35.842 INFO 25052 --- [nio-8085-exec-1] com.pxw.mit.controller.TestController : 接收的参数1:kele, 18
如果接收多个实体类,就将这些实体类封装到一个更大的实体类。如果还有其他实体类,那就继续封装成更更大的实体类 ......(没办法)
如果接收基础类型的参数,如
String name
,则通过 URL ? 后携带 name 过来即可。也就是说,这种方式不限制多次接收。
# 实体类 List 集合
@PostMapping("/listBeanPost")
public void listBeanPost(@RequestBody List<User> user) {
log.info("接收的参数:{}", user);
}
2
3
4
请求链接:http://localhost:8085/test/listBeanPost
。
JSON 参数:
[
{
"name": "kele",
"age": "18"
},
{
"name": "xueli",
"age": "17"
}
]
2
3
4
5
6
7
8
9
10
日志输出:
2022-12-12 23:43:17.329 INFO 22628 --- [nio-8085-exec-2] com.pxw.mit.controller.TestController : 接收的参数:[User(name=kele, age=18), User(name=xueli, age=17)]
# POST 请求 - form
x-www-form-unlencoded 请求和 GET 请求的方式基本类似,这里仅仅说明一些注意细节,具体方式情况上面的 GET 请求。
如果使用 x-www-form-unlencoded 传参,则注意以下几点:
- 实体类、实体类集合作为参数,只能接收 JSON 格式的参数,无法接收 x-www-form-unlencoded
- 如果是其他类型(非实体类)的参数,则需要在每个参数前面加上
@RequestParam
即可,包括 List、Map、数组 - 参数名要和前端传来的保持一致,如果不想保持,则用
@RequestParam("xxx")
指定前端的参数名,xxx 就是前端的参数名
如:
@PostMapping("/listSimplePost")
public void listSimplePost(@RequestParam List<String> name) {
log.info("接收的参数:{}", name);
}
@PostMapping("/mapSimplePost")
public void mapSimplePost(@RequestParam Map<String, String> map) {
log.info("接收的参数:{}", map);
}
@PostMapping("/arraySimplePost")
public void arraySimplePost(String[] name, String[] age) {
log.info("接收的参数1:{}, {}", name[0], name[1]);
log.info("接收的参数2:{}, {}", age[0], age[1]);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
请求链接:
http://localhost:8085/test/listSimplePost
http://localhost:8085/test/mapSimplePost
http://localhost:8085/test/arraySimplePost
请求的参数
日志输出:
2022-12-13 00:04:59.154 INFO 16928 --- [io-8085-exec-10] com.pxw.mit.controller.TestController : 接收的参数:[kele, xueli]
2022-12-13 00:04:17.087 INFO 16928 --- [nio-8085-exec-8] com.pxw.mit.controller.TestController : 接收的参数:{name=kele, age=18}
2022-12-13 00:04:20.289 INFO 16928 --- [nio-8085-exec-9] com.pxw.mit.controller.TestController : 接收的参数1:kele, xueli
2022-12-13 00:04:20.289 INFO 16928 --- [nio-8085-exec-9] com.pxw.mit.controller.TestController : 接收的参数2:18, 17
2
3
4
5
6
除实体类和 Map、List、数组外,其他和 GET 请求的方式一致。如果您不放心,则每个参数前都加 @RequestParam
即可。
# 结束语
后面如果遇到其他的接收方式,则会更新。
如果您有其他优雅的方式,或者您有其他补充或疑惑,可以在评论一起讨论。