@Valid 和 @Validated 比较,以及 SpringBoot 中对 Query、Path、Body 类型参数的校验
在 Spring Boot 中,@Valid 和 @Validated 都用于参数校验,但它们的能力和适用场景不同。
一、@Valid 与 @Validated 对比
| 对比项 | @Valid | @Validated |
|---|---|---|
| 来源 | JSR-303/JSR-380 | Spring |
| 包路径 | jakarta.validation.Valid |
org.springframework.validation.annotation.Validated |
| Bean嵌套校验 | ✅ 支持 | ✅ 支持 |
| 分组校验(Group) | ❌ 不支持 | ✅ 支持 |
| 方法级参数校验 | ❌ 单独使用无效 | ✅ 支持 |
| Spring推荐 | 一般用于DTO字段 | Controller/Service层推荐 |
@Valid
标准 Bean Validation 注解:
import jakarta.validation.Valid;
例如:
@Data
public class UserDTO {
@NotBlank
private String username;
@Min(18)
private Integer age;
}
Controller:
@PostMapping("/user")
public String save(@RequestBody @Valid UserDTO dto) {
return "ok";
}
@Validated
Spring 扩展版:
import org.springframework.validation.annotation.Validated;
支持:
- Bean校验
- 分组校验
- 方法参数校验
@PostMapping("/user")
public String save(@RequestBody @Validated UserDTO dto) {
return "ok";
}
通常项目里统一使用:
@Validated
@RestController
二、分组校验
例如新增和修改规则不同。
定义分组
public interface AddGroup {}
public interface UpdateGroup {}
DTO
@Data
public class UserDTO {
@Null(groups = AddGroup.class)
@NotNull(groups = UpdateGroup.class)
private Long id;
@NotBlank(groups = {AddGroup.class, UpdateGroup.class})
private String username;
}
Controller
新增:
@PostMapping
public void add(
@RequestBody
@Validated(AddGroup.class)
UserDTO dto) {
}
修改:
@PutMapping
public void update(
@RequestBody
@Validated(UpdateGroup.class)
UserDTO dto) {
}
三、Query 参数校验
例如:
GET /user?page=1&size=20
方式1:直接校验单个参数
Controller 必须加:
@Validated
@RestController
public class UserController {
}
否则不会生效。
@GetMapping("/user")
public List<UserVO> list(
@RequestParam
@Min(1)
Integer page,
@RequestParam
@Max(100)
Integer size) {
return List.of();
}
方式2:封装Query对象
推荐。
@Data
public class UserQuery {
@Min(1)
private Integer page;
@Max(100)
private Integer size;
}
Controller:
@GetMapping("/user")
public List<UserVO> list(
@Validated UserQuery query) {
return List.of();
}
Spring 会自动从 QueryString 绑定。
四、Path 参数校验
例如:
GET /user/100
Controller
类上必须有:
@Validated
@RestController
参数:
@GetMapping("/{id}")
public UserVO detail(
@PathVariable
@Min(1)
Long id) {
return null;
}
多个约束:
@GetMapping("/{id}")
public UserVO detail(
@PathVariable
@NotNull
@Min(1)
Long id) {
return null;
}
五、Body 参数校验
最常见。
DTO:
@Data
public class UserCreateRequest {
@NotBlank
private String username;
@Email
private String email;
@Min(18)
private Integer age;
}
Controller:
@PostMapping
public void create(
@RequestBody
@Valid
UserCreateRequest request) {
}
或者:
@PostMapping
public void create(
@RequestBody
@Validated
UserCreateRequest request) {
}
效果一样。
六、嵌套对象校验
很多人容易漏掉。
DTO:
@Data
public class AddressDTO {
@NotBlank
private String city;
}
@Data
public class UserDTO {
@NotBlank
private String username;
@Valid
private AddressDTO address;
}
必须加:
@Valid
private AddressDTO address;
否则:
address.city
不会校验。
七、List 集合校验
校验 List 本身
@PostMapping
public void save(
@RequestBody
@Size(min = 1, max = 100)
List<UserDTO> users) {
}
校验 List 中元素
@PostMapping
public void save(
@RequestBody
List<@Valid UserDTO> users) {
}
或者:
@PostMapping
public void save(
@RequestBody
@Valid
List<UserDTO> users) {
}
Spring Boot 3 推荐:
List<@Valid UserDTO>
八、统一异常处理
Query、Path、Body 的异常类型并不一样。
@RestControllerAdvice
public class GlobalExceptionHandler {
}
Body 校验失败
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Void> handle(
MethodArgumentNotValidException e) {
String msg = e.getBindingResult()
.getFieldError()
.getDefaultMessage();
return Result.fail(msg);
}
对应:
@RequestBody
@Valid
Query / Path 校验失败
@ExceptionHandler(ConstraintViolationException.class)
public Result<Void> handle(
ConstraintViolationException e) {
return Result.fail(e.getMessage());
}
对应:
@RequestParam
@PathVariable
参数绑定失败
例如:
/user/abc
而:
@PathVariable Long id
会抛:
MethodArgumentTypeMismatchException
处理:
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public Result<Void> handle(
MethodArgumentTypeMismatchException e) {
return Result.fail("参数格式错误");
}
九、企业项目推荐写法
Query
@GetMapping
public Result<PageVO<UserVO>> page(
@Validated UserQuery query)
Path
@GetMapping("/{id}")
public Result<UserVO> detail(
@PathVariable
@Min(1)
Long id)
Controller 类:
@Validated
@RestController
Body
@PostMapping
public Result<Void> create(
@RequestBody
@Validated(CreateGroup.class)
UserCreateRequest request)
DTO
@Data
public class UserCreateRequest {
@NotBlank(message = "用户名不能为空")
private String username;
@Email(message = "邮箱格式错误")
private String email;
}
全局异常
统一处理:
MethodArgumentNotValidException(Body)ConstraintViolationException(Query/Path)MethodArgumentTypeMismatchException(类型转换)
这是目前 Spring Boot 3.x 项目里最常见、最完整的一套参数校验方案。

浙公网安备 33010602011771号