Appearance
SpringMVC教程 - 5 参数绑定
前端或其他客户端在请求接口的时候,肯定会传递参数,这一章主要讲解在 Controller 中如何获取传递的参数。SpringMVC的参数绑定机制可以自动将HTTP请求参数绑定到Controller方法的参数上,大大简化了开发工作。
下面就开始介绍在 Controller 中如何接收数据。
5.1 基本数据类型绑定
1 使用方法
可以直接在方法参数上使用 @RequestParam 注解即可。
举个栗子:
java
package com.foooor.hellospringmvc.controller;
import com.foooor.hellospringmvc.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@Slf4j // 使用lombok引入日志
@RestController
@RequestMapping("/students") // 类级别映射前缀
public class StudentController {
/**
* 创建学生
* POST /students
*/
@PostMapping
public Result createStudent(@RequestParam("stuNo") String stuNo,
@RequestParam("name") String name,
@RequestParam("age") int age) {
log.info("createStudent: stuNo={}, name={}, age={}", stuNo, name, age);
return Result.success("创建学生");
}
// 其他代码...
}- 在参数上通过
@RequestParam指定传递的参数,所以调用的时候,名称要与@RequestParam("xxx")中的参数xxx对应。 @RequestParam("name")也可以写为@RequestParam(value="name")。
测试一下:
下面使用 Apifox 请求该接口,并在 body 中,使用 x-www-form-urlencoded 的方式传递参数:

请求后,在控制台可以打印 Controller 中的参数:
createStudent: stuNo=101001, name=foooor, age=18可以看到非常容易就获取到参数了。
需要注意: @RequestParam 注解不支持使用 JSON 格式的请求体,上面的请求体格式是 <form> 表单的方式提交的。
2 省略@RequestParam
如果方法的参数和传递的参数一致,还可以省略 @RequestParam 注解。
那么方法如下:
java
/**
* 创建学生
* POST /students
*/
@PostMapping
public Result createStudent(String stuNo, String name, int age) {
log.info("createStudent: stuNo={}, name={}, age={}", stuNo, name, age);
return Result.success("创建学生");
}- 传递的时候,只要参数和方法参数对应即可。
但是在 Spring6 中,需要首先在 pom.xml 中添加一下编译配置:
xml
<build>
<plugins>
<!-- 其他配置... -->
<!-- 编译配置 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
<compilerArgs>
<arg>-parameters</arg> <!-- 开启参数名保留,用于反射获取参数名 -->
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>然后,使用 Maven clean 一下项目:

然后再尝试一下请求接口,查看一下 Controller 中是否可以接收到参数。
3 必须选项
在使用 @RequestParam 注解的时候,默认参数是必传的,如果不传递会报错。
如果允许不传递参数,可以使用 required=false 来标识非必须。
举个栗子:
java
@PostMapping
public Result createStudent(@RequestParam("stuNo") String stuNo,
@RequestParam(value="name", required = false) String name, // 可选参数,默认值为 null
@RequestParam("age") int age) {
// ...
}- 参数默认是必须的,但是允许传递空字符串。
4 默认值
对于那些允许不传递值,就使用默认值的参数,可以使用 defaultValue 属性指定默认值。
defaultValue 一旦设置,则 required 自动视为 false。 所以不需要再写 required = false。
java
@PostMapping
public Result createStudent(@RequestParam("stuNo") String stuNo,
@RequestParam(value="name", defaultValue = "foooor") String name,
@RequestParam("age") int age) {
// ...
}5.2 对象参数绑定
当需要处理的参数较多时,使用对象来封装这些参数会更加清晰和易于维护。SpringMVC支持将请求参数自动绑定到 JavaBean 对象上。
先创建一个 JavaBean 对象,例如我创建一个 StudentDto.java,如下:
java
package com.foooor.hellospringmvc.dto;
import lombok.Data;
@Data
public class StudentDto {
private String stuNo;
private String name;
// 建议使用 Integer:未传时为 null,传值时为具体数字
private Integer age;
}DTO(Data Transfer Object)是用于在不同层之间传输数据的对象,通常用于解耦前后端交互或服务间通信,避免直接暴露业务模型。一般不太建议使用与数据库的映射对象来作为数据传输对象,因为可能存在字段不一致、暴露敏感字段等问题。
然后修改 Controller 中的方法,将接收参数直接改为对象即可:
java
/**
* 创建学生
* POST /students
*/
@PostMapping
public Result createStudent(StudentDto student) {
log.info("createStudent: student={}", student);
return Result.success("创建学生");
}测试的时候,和上面的一样,请求的时候需要使用 x-www-form-urlencoded 格式的请求体,Controller中才可以获取到参数。
需要注意,传递的参数名称需要和对象中的名称对应,更准确的说法,是需要和对象中的setter方法名称对象,传递参数为 xxx,类中需要有 setXxx 方法。
5.3 @RequestBody接收JSON格式数据
上面的 @RequestParam 注解和接收对象参数的方式都不支持调用者使用 JSON 请求体传递参数。
但是现在的前端请求,一般都是通过 JSON 格式的请求体来传递参数的,所以这里就需要用到一个注解 @RequestBody 。
例如前端或调用者通过如下方式调用接口,body 数据格式选择 JSON:

Controller 的方法参数需要使用 @RequestBody 注解:
java
/**
* 创建学生
* POST /students
*/
@PostMapping
public Result createStudent(@RequestBody StudentDto student) {
log.info("createStudent: student={}", student);
return Result.success("创建学生");
}SpringMVC 会使用 HttpMessageConverter 完成数据的反序列化(JSON字符串转对象),默认使用 MappingJackson2HttpMessageConverter 来解析 JSON 字符串。
@RequestBody 还支持集合、Map类型,所以上面的方法还可以这样写:
java
/**
* 创建学生
* POST /students
*/
@PostMapping
public Result createStudent(@RequestBody Map<String, Object> student) {
log.info("createStudent: student={}", student);
return Result.success("创建学生");
}- 通过 Map 接收参数。
如果请求的格式是集合格式,例如:
java
// 请求体:
[
{"stuNo": "101002", "name": "Tom", "age": 20},
{"stuNo": "101002", "name": "Jerry", "age": 22}
]那么 Controller 中可以使用 List 来接收:
java
/**
* 创建学生
* POST /students
*/
@PostMapping
public Result createStudent(@RequestBody List<StudentDto> students) {
// ...略
}- 从上面也可以看到
@RequestBody是支持数据格式的嵌套的,也就是对象属性也是对象,只要和 JSON 格式对应即可。
5.4 @RequestHeader接收请求的header数据
在发送请求数据的时候,包括请求头和请求体,一般情况下请求数据是放在请求体中的。我们还可以将一些数据放在请求头中,那么在 Controller 中,可以通过 @RequestHeader 注解来接收参数。
举个栗子:
java
/**
* 创建学生
* POST /students
*/
@PostMapping
public Result createStudent(@RequestBody StudentDto student, @RequestHeader("token") String token) {
log.info("createStudent: students={}, token={}", student, token);
return Result.success("创建学生");
}- 我们在请求的时候,可以在请求头中添加
token属性(Apifox也可以添加),在Controller中可以通过@RequestHeader("token")接收到数据。 @RequestHeader同样支持value、required、defaultValue属性,和@RequestParam注解是一样的。

SpringMVC 还有一个 @CookieValue 注解,用于接收 Cookie 参数, 使用方法和 @RequestHeader 类似,了解一下。
5.5 RESTful API完善
前面实现 Restful 风格 API 的时候,没有传递参数,现在学习了参数绑定,我们可以将方法的参数添加上:
- 列表查询的方法,需要传递查询参数;
- 新增和修改需要传递具体的信息。
具体如下:
java
package com.foooor.hellospringmvc.controller;
import com.foooor.hellospringmvc.common.Result;
import com.foooor.hellospringmvc.dto.Student;
import com.foooor.hellospringmvc.dto.StudentDto;
import com.foooor.hellospringmvc.dto.StudentQueryDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/students")
@Validated
public class StudentController {
/**
* 查询学生列表(分页+条件)
* GET /students?name=xxx&email=xxx&page=1&size=20
* 可以通过创建StudentQueryDto类来接收查询参数
*/
@GetMapping
public Result listStudents(StudentQueryDto queryDto) {
log.info("查询学生列表, 参数: {}", queryDto);
// TODO 调用Service查询学生列表,然后返回
List<Student> studentList = new ArrayList<>();
return Result.success(studentList);
}
/**
* 查询学生详情
* GET /students/{id}
*/
@GetMapping("/{id}")
public Result getStudentDetail(@PathVariable("id") Long id) {
log.info("查询学生详情, ID: {}", id);
// TODO 调用Service查询学生详情,然后返回
// 模拟返回数据
Student student = null;
return Result.success(student);
}
/**
* 创建学生
* POST /students
*/
@PostMapping
public Result createStudent(@RequestBody StudentDto createDto) {
log.info("创建学生, 参数: {}", createDto);
// TODO 调用Service创建学生
return Result.success();
}
/**
* 更新学生
* PUT /students/{id}
*/
@PutMapping("/{id}")
public Result updateStudent(@PathVariable("id") Long id, @RequestBody StudentDto updateDto) {
log.info("更新学生, ID: {}, 参数: {}", id, updateDto);
// TODO 调用Service更新学生信息
// 模拟更新操作
return Result.success();
}
/**
* 删除学生
* DELETE /students/{id}
*/
@DeleteMapping("/{id}")
public Result deleteStudent(@PathVariable("id") Long id) {
log.info("删除学生, ID: {}", id);
// TODO 调用Service删除学生
return Result.success();
}
/**
* 批量删除学生
* DELETE /students/batch?ids=1&ids=2&ids=3
*/
@DeleteMapping("/batch")
public Result batchDeleteStudents(@RequestParam List<Long> ids) {
log.info("批量删除学生, IDs: {}", ids);
// TODO 调用Service删除学生
// 返回删除成功结果
return Result.success();
}
}- 针对查询参数,我们可以创建一个查询参数的类
StudentQueryDto,前端传递参数,使用这个类的对象来接收,然后根据传递的查询条件查询学生列表返回。 - 同样针对具体的学生信息,也是创建了
StudentDto来接收信息。
一般在项目中,会涉及到三种对象,一种是 pojo/Entity 实体类,类中的属性和数据库中的字段是对应的,在执行数据库查询的时候,返回的是这个对象,但是一般不会将对象直接返回给前端,因为其中的字段可能存在敏感信息(例如密码),所以一般会将其转换为 VO 对象。
VO(View Object)用于返回给前端的数据(输出层),负责封装和展示数据,隐藏敏感字段,如查询结果UserVO 。
而 DTO(Data Transfer Object)用于接收前端传入的数据(输入层),负责参数校验和数据转换,如注册时的UserRegisterDTO。
但是项目中具体怎么用,还是要结合实际情况,因为有的人觉得太繁琐了,直接使用 pojo。