转自:SpringBoot后端接口请求参数映射方式详解 | 包包的Tech Pool 侵删
在SpringBoot项目中,前端HTTP请求中的参数如何映射到Controller层的接口方法中的参数?这里针对各种方式做一个测试与总结,测试采用的SpringBoot版本号为2.2.10.RELEASE
QueryString方式
QueryString
参数传递的方式为,在请求URL中直接拼接请求参数,如URL?param1=value1¶m2=value2
QueryString
参数传递方式对于请求方法GET
、POST
、PUT
、PATCH
、DELETE
都适用
1.映射基本类型参数
可以在Controller的接口中声明基本类型的参数,然后用@RequestParam
注解修饰,指定前端传递的参数名称
1 2 3 4 5 6 7 8 9 | @RestController @RequestMapping("param") @Slf4j public class RequestParamTestController { @RequestMapping("queryString1") public void testQueryString1(@RequestParam("name") String name, @RequestParam("age") Integer age) { log.info("name:{} age:{}", name, age); } } |
测试结果如下
2.映射对象类型参数
定义一个对象,属性名称和前端传递的参数名称一致即可
1 2 3 4 5 6 7 | @Data @AllArgsConstructor @NoArgsConstructor public class User { private String name; private Integer age; } |
然后将Controller接口方法中的参数声明为自定义对象
1 2 3 4 | @RequestMapping("queryString2") public void testQueryString2(User user) { log.info("name:{} age:{}", user.getName(), user.getAge()); } |
测试结果如下
3.映射数组、集合类型参数
前端有2种方式针对同一个参数传递多个值:
- 在请求的QueryString中,拼接多个参数名称一样的参数即可,如
URL?param=value1¶m=value2¶m=value3
- 在请求的QueryString中,对同一个参数赋多个值,多个值之间用
,
隔开,如URL?param=value1,value2,value3
3.1 映射数组
在Controller接口方法中声明数组类型参数,用@RequestParam
指明前端传递的参数名称即可
1 2 3 4 5 6 7 8 | @RequestMapping("queryString3") public void testQueryString3(@RequestParam("name") String[] nameArray) { if (nameArray != null) { for (String name : nameArray) { log.info(name); } } } |
测试结果如下
如果请求参数名称和Controller中接口方法的参数名称一致,那么可以省略
@RequestParam
注解。不过一般还是建议加上
3.2 映射Collection
在Controller接口方法中声明Collection
类型参数,用@RequestParam
指明前端传递的参数名称即可
1 2 3 4 5 6 7 8 9 | @RequestMapping("queryString4") public void testQueryString4(@RequestParam("name") Collection<String> nameCollection) { if (nameCollection != null) { log.info("类型:{}", nameCollection.getClass()); for (String name : nameCollection) { log.info(name); } } } |
测试结果如下
可以发现框架默认采用的实现类是LinkedHashSet
。那我们继续测试传递相同value的时候是否也会采用这个实现
可以发现传递多个相同value的时候框架采用的实现类还是LinkedHashSet
,所以有去重的效果
3.3 映射List
在Controller接口方法中声明List
类型参数,用@RequestParam
指明前端传递的参数名称即可
1 2 3 4 5 6 7 8 9 | @RequestMapping("queryString5") public void testQueryString5(@RequestParam("name") List<String> nameList) { if (nameList != null) { log.info("类型:{}", nameList.getClass()); for (String name : nameList) { log.info(name); } } } |
测试结果如下
可以发现框架默认采用的实现类是ArrayList
3.4 映射Set
在Controller接口方法中声明Set
类型参数,用@RequestParam
指明前端传递的参数名称即可
1 2 3 4 5 6 7 8 9 | @RequestMapping("queryString6") public void testQueryString6(@RequestParam("name") Set<String> nameSet) { if (nameSet != null) { log.info("类型:{}", nameSet.getClass()); for (String name : nameSet) { log.info(name); } } } |
测试结果如下
可以发现框架默认采用的实现类是LinkedHashSet
,与声明为Collection
类型时一致
注意:
- 也可以在自定义对象中将属性声明为数组、集合类型,来接收多个值
路径参数方式
路径传参方式是将参数直接包含在URL路径中,比如URL/paramValue1/paramValue2
路径参数方式对于请求方法
GET
、POST
、PUT
、PATCH
、DELETE
都适用
1.映射基本类型参数
在Controller中用如下步骤接收参数:
- 在接口对应的请求路径中用
{参数名}
形式标出路径参数 - 在接口方法的参数上标注
@PathVariable
指名对应路径参数的参数名
1 2 3 4 | @RequestMapping("path1/{name}/{age}") public void testPath1(@PathVariable("name") String name, @PathVariable("age") Integer age) { log.info("name:{} age:{}", name, age); } |
测试结果如下
如果接口方法上
@RequestMapping
中路径参数的参数名称和接口方法的参数名称相同,可以省略@PathVariable
注解。但一般推荐加上
2.映射数组、集合类型参数
直接给路径参数多个值,用,
隔开即可
2.1 映射数组
在Controller接口方法中声明数组类型参数,用@PathVariable
指明路径参数的名称即可
1 2 3 4 5 6 7 8 9 | @RequestMapping("path2/{name}/{age}") public void testPath2(@PathVariable("name") String[] nameArray, @PathVariable("age") Integer[] ageArray) { for (String name : nameArray) { log.info(name); } for (Integer age : ageArray) { log.info(age.toString()); } } |
测试结果如下
2.2 映射Collection
在Controller接口方法中声明Collection
类型参数,用@PathVariable
指明路径参数的名称即可
1 2 3 4 5 6 7 8 9 10 | @RequestMapping("path3/{name}/{age}") public void testPath3(@PathVariable("name") Collection<String> nameCollection, @PathVariable("age") Collection<Integer> ageCollection) { log.info("类型:{}", nameCollection.getClass()); for (String name : nameCollection) { log.info(name); } for (Integer age : ageCollection) { log.info(age.toString()); } } |
测试结果如下
可以发现框架默认采用的类型是LinkedHashSet
2.3 映射List
在Controller接口方法中声明List
类型参数,用@PathVariable
指明路径参数的名称即可
1 2 3 4 5 6 7 8 9 10 | @RequestMapping("path4/{name}/{age}") public void testPath4(@PathVariable("name") List<String> nameList, @PathVariable("age") List<Integer> ageList) { log.info("类型:{}", nameList.getClass()); for (String name : nameList) { log.info(name); } for (Integer age : ageList) { log.info(age.toString()); } } |
测试结果如下
框架采用的实现类是ArrayList
2.4 映射Set
在Controller接口方法中声明Set
类型参数,用@PathVariable
指明路径参数的名称即可
1 2 3 4 5 6 7 8 9 10 | @RequestMapping("path5/{name}/{age}") public void testPath5(@PathVariable("name") Set<String> nameSet, @PathVariable("age") Set<Integer> ageSet) { log.info("类型:{}", nameSet.getClass()); for (String name : nameSet) { log.info(name); } for (Integer age : ageSet) { log.info(age.toString()); } } |
测试结果如下
框架采用的实现类是LinkedHashSet
路径参数方式映射到Controller接口方法中的
数组
、Collection
、List
和Set
类型参数时,即便路径中的参数名称和接口方法中的参数名称一致,也不能省略@PathVariable
注解
表单参数方式
表单参数方式要求在请求头中携带Content-Type
,值为application/x-www-form-urlencoded
,并且请求体中以param:value
形式携带参数,每行代表一个参数,多个参数就有多行
注意:表单参数方式不适用于
GET
请求,适用于POST
、PUT
、PATCH
、DELETE
1.映射基本类型参数
可以在Controller的接口中声明基本类型的参数,然后用@RequestParam
注解修饰,指定请求体中的参数名称
1 2 3 4 | @RequestMapping("form1") public void testForm1(@RequestParam("name") String name, @RequestParam("age") Integer age) { log.info("name:{} age:{}", name, age); } |
测试结果如下
2.映射对象类型参数
定义一个对象,属性名称和请求体中的参数名称一致即可
1 2 3 4 5 6 7 | @Data @AllArgsConstructor @NoArgsConstructor public class User { private String name; private Integer age; } |
然后将Controller接口方法中的参数声明为自定义对象
1 2 3 4 | @RequestMapping("form2") public void testForm2(User user) { log.info("name:{} age:{}", user.getName(), user.getAge()); } |
测试结果如下
3.映射数组、集合类型参数
请求体中的参数如果想要传递多个值,有2种方式:
- 直接给参数多个值,用
,
隔开即可 - 声明多个参数名一样的参数
3.1 映射数组
在Controller接口方法中声明数组类型参数,用@RequestParam
指明请求体中的参数名称即可
1 2 3 4 5 6 | @RequestMapping("form3") public void testForm3(@RequestParam("name") String[] nameArray) { for (String name : nameArray) { log.info(name); } } |
测试结果如下
3.2 映射Collection
在Controller接口方法中声明Collection
类型参数,用@RequestParam
指明请求体中的参数名称即可
1 2 3 4 5 6 7 | @RequestMapping("form4") public void testForm4(@RequestParam("name") Collection<String> nameCollection) { log.info("类型:{}", nameCollection.getClass()); for (String name : nameCollection) { log.info(name); } } |
测试结果如下
3.3 映射List
在Controller接口方法中声明List
类型参数,用@RequestParam
指明请求体中的参数名称即可
1 2 3 4 5 6 7 | @RequestMapping("form5") public void testForm5(@RequestParam("nameList") List<String> nameList) { log.info("类型:{}", nameList.getClass()); for (String name : nameList) { log.info(name); } } |
测试结果如下
3.4 映射Set
在Controller接口方法中声明Set
类型参数,用@RequestParam
指明请求体中的参数名称即可
1 2 3 4 5 6 7 | @RequestMapping("form6") public void testForm6(@RequestParam("name") Set<String> nameSet) { log.info("类型:{}", nameSet.getClass()); for (String name : nameSet) { log.info(name); } } |
测试结果如下
也可以在自定义对象中将属性声明为数组、集合类型,来接收多个值
FormData方式
用于文件上传。要求在请求头中携带Content-Type
,值为multipart/form-data
。请求体中可以携带普通参数,也可以携带文件
Postman测试发现这种方式适用于
GET
、POST
、PUT
、PATCH
、DELETE
,但浏览器一般只能用POST
表单提交进行文件上传,所以建议用POST
请求
可以在Controller的接口中分别声明普通类型参数和文件类型参数,其中文件类型参数必须是MultipartFile
类型,然后用@RequestParam
注解修饰,指定请求体中对应的参数名称
1 2 3 4 | @RequestMapping("formData1") public void testFormData1(@RequestParam("fileName") String fileName, @RequestParam("file")MultipartFile file) { log.info("{}:{}", fileName, file.getSize()); } |
测试结果如下
FormData方式中的普通参数(即非文件类型参数)同样也可以利用数组、集合类型接收多个值,可以封装为自定义对象,方法与表单参数方式类似
请求体json方式
要求请求头携带Content-Type
,值为application/json
。请求体中的内容为json格式
在Controller的接口方法映射这种请求参数只能通过自定义对象,自定义对象的属性名称要与请求体中json的属性名称一致,然后将自定义对象作为接口方法的参数,并标注@RequestBody
注解,框架会自动将请求体的json转换为自定义对象
1 2 3 4 | @RequestMapping("json1") public void testJson1(@RequestBody User user) { log.info(user.toString()); } |
测试结果如下
经过PostMan测试发现,用
GET
方法发送这种请求也可以顺利接收到参数,但是一般浏览器不支持GET
请求携带请求体数据,所以还是建议实际开发中只针对POST
、PUT
、PATCH
、DELETE
采用这种方式进行参数映射