本文从本人博客搬运,原文格式更加美观,可以移步原文阅读:SpringBoot后端接口请求参数映射方式详解
在SpringBoot项目中,前端HTTP请求中的参数如何映射到Controller层的接口方法中的参数?这里针对各种方式做一个测试与总结,测试采用的SpringBoot版本号为2.2.10.RELEASE
QueryString
参数传递的方式为,在请求URL中直接拼接请求参数,如URL?param1=value1¶m2=value2
QueryString
参数传递方式对于请求方法GET
、POST
、PUT
、PATCH
、DELETE
都适用
可以在Controller的接口中声明基本类型的参数,然后用@RequestParam
注解修饰,指定前端传递的参数名称
@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);
}
}
测试结果如下
定义一个对象,属性名称和前端传递的参数名称一致即可
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private Integer age;
}
然后将Controller接口方法中的参数声明为自定义对象
@RequestMapping("queryString2")
public void testQueryString2(User user) {
log.info("name:{} age:{}", user.getName(), user.getAge());
}
测试结果如下
前端有2种方式针对同一个参数传递多个值:
URL?param=value1¶m=value2¶m=value3
,
隔开,如URL?param=value1,value2,value3
在Controller接口方法中声明数组类型参数,用@RequestParam
指明前端传递的参数名称即可
@RequestMapping("queryString3")
public void testQueryString3(@RequestParam("name") String[] nameArray) {
if (nameArray != null) {
for (String name : nameArray) {
log.info(name);
}
}
}
测试结果如下
如果请求参数名称和Controller中接口方法的参数名称一致,那么可以省略
@RequestParam
注解。不过一般还是建议加上
在Controller接口方法中声明Collection
类型参数,用@RequestParam
指明前端传递的参数名称即可
@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
,所以有去重的效果
在Controller接口方法中声明List
类型参数,用@RequestParam
指明前端传递的参数名称即可
@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
在Controller接口方法中声明Set
类型参数,用@RequestParam
指明前端传递的参数名称即可
@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
都适用
在Controller中用如下步骤接收参数:
{参数名}
形式标出路径参数@PathVariable
指名对应路径参数的参数名@RequestMapping("path1/{name}/{age}")
public void testPath1(@PathVariable("name") String name, @PathVariable("age") Integer age) {
log.info("name:{} age:{}", name, age);
}
测试结果如下
如果接口方法上
@RequestMapping
中路径参数的参数名称和接口方法的参数名称相同,可以省略@PathVariable
注解。但一般推荐加上
直接给路径参数多个值,用,
隔开即可
在Controller接口方法中声明数组类型参数,用@PathVariable
指明路径参数的名称即可
@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());
}
}
测试结果如下
在Controller接口方法中声明Collection
类型参数,用@PathVariable
指明路径参数的名称即可
@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
在Controller接口方法中声明List
类型参数,用@PathVariable
指明路径参数的名称即可
@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
在Controller接口方法中声明Set
类型参数,用@PathVariable
指明路径参数的名称即可
@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
可以在Controller的接口中声明基本类型的参数,然后用@RequestParam
注解修饰,指定请求体中的参数名称
@RequestMapping("form1")
public void testForm1(@RequestParam("name") String name, @RequestParam("age") Integer age) {
log.info("name:{} age:{}", name, age);
}
测试结果如下
定义一个对象,属性名称和请求体中的参数名称一致即可
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private Integer age;
}
然后将Controller接口方法中的参数声明为自定义对象
@RequestMapping("form2")
public void testForm2(User user) {
log.info("name:{} age:{}", user.getName(), user.getAge());
}
测试结果如下
请求体中的参数如果想要传递多个值,有2种方式:
,
隔开即可在Controller接口方法中声明数组类型参数,用@RequestParam
指明请求体中的参数名称即可
@RequestMapping("form3")
public void testForm3(@RequestParam("name") String[] nameArray) {
for (String name : nameArray) {
log.info(name);
}
}
测试结果如下
在Controller接口方法中声明Collection
类型参数,用@RequestParam
指明请求体中的参数名称即可
@RequestMapping("form4")
public void testForm4(@RequestParam("name") Collection<String> nameCollection) {
log.info("类型:{}", nameCollection.getClass());
for (String name : nameCollection) {
log.info(name);
}
}
测试结果如下
在Controller接口方法中声明List
类型参数,用@RequestParam
指明请求体中的参数名称即可
@RequestMapping("form5")
public void testForm5(@RequestParam("nameList") List<String> nameList) {
log.info("类型:{}", nameList.getClass());
for (String name : nameList) {
log.info(name);
}
}
测试结果如下
在Controller接口方法中声明Set
类型参数,用@RequestParam
指明请求体中的参数名称即可
@RequestMapping("form6")
public void testForm6(@RequestParam("name") Set<String> nameSet) {
log.info("类型:{}", nameSet.getClass());
for (String name : nameSet) {
log.info(name);
}
}
测试结果如下
也可以在自定义对象中将属性声明为数组、集合类型,来接收多个值
用于文件上传。要求在请求头中携带Content-Type
,值为multipart/form-data
。请求体中可以携带普通参数,也可以携带文件
Postman测试发现这种方式适用于
GET
、POST
、PUT
、PATCH
、DELETE
,但浏览器一般只能用POST
表单提交进行文件上传,所以建议用POST
请求
可以在Controller的接口中分别声明普通类型参数和文件类型参数,其中文件类型参数必须是MultipartFile
类型,然后用@RequestParam
注解修饰,指定请求体中对应的参数名称
@RequestMapping("formData1")
public void testFormData1(@RequestParam("fileName") String fileName, @RequestParam("file")MultipartFile file) {
log.info("{}:{}", fileName, file.getSize());
}
测试结果如下
FormData方式中的普通参数(即非文件类型参数)同样也可以利用数组、集合类型接收多个值,可以封装为自定义对象,方法与表单参数方式类似
要求请求头携带Content-Type
,值为application/json
。请求体中的内容为json格式
在Controller的接口方法映射这种请求参数只能通过自定义对象,自定义对象的属性名称要与请求体中json的属性名称一致,然后将自定义对象作为接口方法的参数,并标注@RequestBody
注解,框架会自动将请求体的json转换为自定义对象
@RequestMapping("json1")
public void testJson1(@RequestBody User user) {
log.info(user.toString());
}
测试结果如下
经过PostMan测试发现,用
GET
方法发送这种请求也可以顺利接收到参数,但是一般浏览器不支持GET
请求携带请求体数据,所以还是建议实际开发中只针对POST
、PUT
、PATCH
、DELETE
采用这种方式进行参数映射