在web开发中我们都要进行前端传参后端取参的过程,今天就简单记录下针对GET, POST, PUT, DELETE 请求的参数该如何映射。
1. GET 请求的参数映射
1.1 参数名映射
GET请求是最简单的,只需要将参数以键值对的形式拼接到url后面就可以了,比如下面:
http://localhost:8080/helloParam?name=zhangsan&age=33n
&birthDay=2023-08-01 20:01:11n
&plays=basketabll&plays=football&plays=swimming
后端可以去获取参数:
@GetMapping(value = "/helloParam")
public String hello(String name,
Integer age,
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime birthDay,
String[] plays,
@RequestParam("plays") List plays2) {
log.info("请求参数: name = {}, age = {}, birthDay = {}, plays = {}, plays2 = {}", name, age, birthDay, plays, plays2);
return "success";
}
//日志输出:请求参数: name = zhangsan, age = 33, birthDay = 2023-08-01T20:01:11, plays = [basketabll, football, swimming], plays2 = [basketabll, football, swimming]
日期字符串如何想直接映射成
LocalDateTime
类型,需要使用@DateTimeFormat
注解进行标注。plays
是一个数组,后端可以用数组或者集合接收,注意用集合接收时,需要搭配@RequestParam
注解,否则将无法映射成功。
注意:前端的参数名必须和后端方法的变量名保持一致,如果不一致,将无法映射。如果就不一致,可以使用 @RequestParam
来完成映射。
1.2 使用 @RequestParam
注解完成映射
比如:将上面请求参数中的 name
参数改为 cname
发送请求:
http://localhost:8080/helloParam?cname=zhangsan3333&age=33n
&birthDay=2023-08-01 20:01:11n
&plays=basketabll&plays=football&plays=swimming
后端映射:
@GetMapping(value = "/helloParam")
public String hello(@RequestParam("cname") String n,
Integer age,
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime birthDay,
String[] plays,
@RequestParam("plays") List plays2) {
log.info("请求参数: name = {}, age = {}, birthDay = {}, plays = {}, plays2 = {}", n, age, birthDay, plays, plays2);
return "success";
}
//日志输出:请求参数: name = zhangsan333, age = 33, birthDay = 2023-08-01T20:01:11, plays = [basketabll, football, swimming], plays2 = [basketabll, football, swimming]
使用
@RequestParam
注解时,要求参数必须存在,否则请求将会报错。可以使用它的required
属性来避免这个问题。
1.3 后端用对象接收参数
还是上面的请求,比如我需要传递分页参数,而后端的分页参数保存在Page
对象中
http://localhost:8080/helloParam?name=zhangsan3333&age=33n
&birthDay=2023-08-01 20:01:11n
&plays=basketabll&plays=football&plays=swimmingn
&page=1&size=10
后端可以这样接收:
@GetMapping(value = "/helloParam")
public String hello(Page page,
String name,
Integer age,
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime birthDay) {
log.info("请求参数: name = {}, age = {}, birthDay = {}, 分页参数:page = {}", n, age, birthDay, page);
return "success";
}
//日志输出:请求参数: name = zhangsan3333, age = 33, birthDay = 2023-08-01T20:01:11, 分页参数:page = Page(page=1, size=10)
Page对象:
@Data
public class Page {
private Integer page;
private Integer size;
}
将请求参数也封装到对象中:
@GetMapping(value = "/helloParam")
public String hello(Page page, Student student) {
log.info("请求对象参数: student = {}, 分页参数 = {}", student, page);
return "success";
}
//日志输出:请求对象参数: student = Student(name=zhangsan3333, age=33, birthDay=2023-08-01T20:01:11, plays=[basketabll, football, swimming]), 分页参数 = Page(page=1, size=10)
@Data
public class Student {
private String name;
private Integer age;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime birthDay;
private List plays;
}
1.4 Restful 风格的参数映射
http://localhost:8080/helloParam/liubei/45/1949-10-01 23:23:44
后端可以这样接收:
@GetMapping(value = "/helloParam/{cname}/{age}/{birthDay}")
public String helloObj2(@PathVariable("cname") String name,
Integer age,
Student student) {
log.info("Restful请求参数: name = {}, age = {}, 对象student = {}", name, age, student);
return "success";
}
//日志输出:Restful请求参数: name = liubei, age = null, 对象student = Student(name=null, age=45, birthDay=1949-10-01T23:23:44, plays=null)
@GetMapping("/hello/{name}/{age}/{birthDay}")
这里的{参数名}要和方法中的参数名保持一致。而且当用单个参数去接收时,必须搭配@PathVariable
注解才可以映射成功,否则将无法映射,比如age就无法映射。当用对象去接收时,无需指定@PathVariable
注解,但是对象的属性名要和Restful的请求{参数名}保持一致才可以映射成功,Student
类中是name
,而Rfestul中的请求参数是cname
, 所以无法映射。
2. POST 请求的参数映射
说起POST
请求,我们先看下几个比较常见的Content-Type
。
Content-Type | Content-Type 描述 |
---|---|
multipart/form-data | multipart/form-data就是我们常见的表单,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件(可以多个文件) |
x-www-form-urlencoded | x-www-from-urlencoded,会将表单内的数据转换为键值对,比如,name=zhangsan&age=23,相比multipart/form-data ,它只能上传键值对,不能上传文件 |
raw | 可以上传任意格式的文本,比如我们常见的 JOSN(application/json ), 还有其他的 text, xml, html... |
binary | 就是application/octet-stream,只可以上传二进制数据,通常用来上传文件或者音频,没有键值对,一次只能上传一个文件 |
2.1 Content-Type: application/x-www-form-urlencoded 的参数映射
multipart/form-data
相比application/x-www-form-urlencoded
多了文件上传的功能,其他基本上都是一样的,所以我就以application/x-www-form-urlencoded
进行演示说明。
2.1.1 参数名映射
Controller:
@PostMapping(value = "/form")
public String form(String name, Integer age, @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime birthDay) {
log.info("请求参数: name = {}, age = {}, time = {}", name, age, birthDay);
return "success";
}
//日志输出:请求参数: name = zhangsan, age = 23, time = 2023-07-31T23:51:23
注意:这里如果要映射成功,确保请求参数名与方法参数名称保持一致。如果不一致,可以使用
@RequestParam
注解来指定.
Controller:
@PostMapping(value = "/form")
public String form(@RequestParam("cname") String name, Integer age) {
log.info("请求参数: name = {}, age = {}", name, age);
return "success";
}
//日志输出:请求参数: name = zhangsan, age = 23
有没有发现,其实和GET请求映射一模一样。
2.1.2 对象映射
@Data
public class Student {
private String name;
private Integer age;
private String fromCity;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime birthDay;
}
前端没有变化,还是之前的请求:
curl --location --request POST 'http://localhost:8080/form'
--header 'Content-Type: application/x-www-form-urlencoded'
--data-urlencode 'name=zhangsan'
--data-urlencode 'age=23'
--data-urlencode 'birthDay=2023-07-31 23:51:23'
后端用对象接收:
@PostMapping(value = "/form")
public String form(Student student) {
log.info("obj请求参数: name = {}, age = {}", student.getName(), student.getAge());
return "success";
}
//日志输出:obj请求参数: name = zhangsan, age = 23, time = 2023-07-31T23:51:23
2.2.3 Restful 风格的参数映射
调整一下请求格式:
curl --location --request POST 'http://localhost:8080/form/zhangxinyu/33'
后端接收:
@PostMapping(value = "/form/{cname}/{age}")
public String form(@PathVariable("cname") String name,
@PathVariable Integer age,
Student student) {
log.info("restful请求参数: name = {}, age = {}, student对象 = {}", name, age, student);
return "success";
}
//日志输出:obj请求参数: name = zhangxinyu, age = 33, student对象 = Student(name=null, age=33, birthDay=null, plays=null)
@PostMapping(value = "/form/{cname}/{age}")
这里的{参数名}要和方法中的参数名保持一致。而且当用单个参数去接收时,必须搭配@PathVariable
注解才可以映射成功,否则将无法映射。当用对象去接收时,无需指定@PathVariable
注解,但是对象的属性名要和Restful的请求{参数名}保持一致才可以映射成功,Student
类中是name
,而Rfestul中的请求参数是cname
, 所以无法映射。和GET
请求是一样的。
2.2 Content-Type: application/json 的参数映射
想要接收
application/json
的数据,后端的方法参数上必须标注@RequestBody
注解
2.2.1 @RequestBody
注解完成参数映射
我们看下后端的接收:
@PostMapping("/application")
public String hello(Integer age, @RequestBody String name, LocalDateTime birthDay){
log.info("请求参数: name = {}, age = {}, birthDay = {}", name, age, birthDay);
return "success";
}
只有name
参数映射上了,这是因为它会把整个body里面的内容映射给标注了@RequestBody
参数,而age
, birthDay
因为没有标注@RequestBody
注解所以无法映射,而且也不能再标注@RequestBody
注解,因为只能给一个参数标注,如果多个参数标注@RequestBody
注解会报错。
那如果想给多个参数都映射成功,怎么处理?可以用自定义对象
去接收或者Map
.
自定义Student
对象去接收:
@Data
public class Student {
private String name;
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") //要用这个注解
//@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") //GET/form 用这个去映射
private LocalDateTime birthDay;
private List plays;
private Course course;
}
@Data
public class Course {
private String id;
private String courseName;
}
Controller:
@PostMapping("/application")
public String hello(@RequestBody Student student){
log.info("请求参数: student对象:{}", student);
return "success" + student.getBirthDay();
}
//日志输出:请求参数: student对象:Student(name=周星驰, age=50, birthDay=2023-08-02T20:36:04, plays=null, course=null)
2.2.2 使用 @JsonProperty
注解映射参数名不一致的情况
javaBean对象:
@Data
public class Student {
//使用JsonProperty("username")注解完成映射
@JsonProperty("username")
private String name;
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
//@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime birthDay;
private List plays;
private Course course;
}
2.2.3 使用@JsonIgnore
注解忽略不需要映射的字段
如果前端不需要展示某个字段,也可以用这个注解标注
JavaBean对象:
@Data
public class Student {
@JsonProperty("username")
private String name;
@JsonIgnore
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
//@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime birthDay;
private List plays;
@JsonIgnore
private Course course;
}
Controller:
@Slf4j
@RestController
public class HelloController {
@PostMapping("/application")
public Student hello(@RequestBody Student student){
log.info("请求参数: student对象:{}", student);
return student;
}
}
//日志输出:请求参数: student对象:Student(name=周星驰, age=null, birthDay=2023-08-02T20:36:04, plays=[swimming, singing], course=null)
看下返回给前端的JSON数据:
像
age
,course
这种标注了@JsonIgnore
注解的属性就不会显示在JSON中了。
好了,关于SpringMVC常见的参数映射就介绍到这里吧,欢迎大家批评指正。