入参校验
大家好,我是欧阳方超,公众号同名。

1 概述
在开发中,参数校验是保证数据有效性的重要环节。Spring Boot提供了强大的参数校验功能,通过简单的注解即可实现复杂的检验逻辑。以往开发中经常使用校验功能,但是没有归纳总结过,搭建新项目时或者遇到未使用注解对参数校验的项目而想加入这个功能时,总是需要去搜索一下该怎么使用,本文就介绍下怎么从头(包括依赖引入、常用注解、校验流程)开始使用注解对参数进行校验,希望以后自己再搜索此类问题时搜索到的是自己写的这篇文章。
2 依赖引入
从Spring Boot2.3以后的版本开始,使用@NotBlank、@Valid等校验注解时,需要单独引入spring-boot-starter-validation依赖,它内部集成了hibernate-validator(校验实现)和validation-api(校验注解规范),也许你想我一样,遇到过虽然引入了spring-boot-starter-validation依赖,但是hibernate-validator和validation-api都没被自动引入的情况,别着急,下面会说到这个问题。
maven示例:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
如果你使用了spring-boot-dependencies对Spring Boot的依赖进行了统一版本管理的话,上面的依赖可以不用写version标签。
如果项目使用Spring Boot版本属于2.3之前的,那根本不需要引入上面的spring-boot-starter-validation依赖,就能使用校验注解。
3 校验注解
3.1 常用校验注解
Bean Validation规范和Hibernate Validator实现提供了大量实用注解,常见的如下。
| 注解 | 作用 | 示例 |
|---|---|---|
| @NotNull | 字段值不能为空 | @NotNull(message = “ID不能为空”) |
| @NotBlank | 字符串不能为null且包含至少一个非空白字符(空格、tab就属于空白字符) | @NotBlank(message = “用户名不能为空”) |
| @NotEmpty | 集合、数组、Map、字符串等不能为null | @NotEmpty(message = “角色列表不能为空”) |
| @Size | 检查字符串、集合、数组、Map等的大小 | @Size(min = 6, max = 20, message = “密码长度必须在6-20个字符之间”) |
| @Min | 数字最小值 | @Min(value = 18, message = “年龄不能小于18岁”) |
| @Max | 数字最大值 | @Max(value = 100, message = “年龄不能大于100岁”) |
| @Pattern | 正则表达式 | @Pattern(regexp = “^1[3-9]\d{9}$”, message = “手机号格式不正确”) |
| 邮箱格式校验 | @Email(message = “邮箱格式不正确”) | |
| @Past | 日期必须在过去 | @Past(message = “生日必须是过去的时间”) |
| @Future | 日期必须在将来 | @Future(message = “过期时间必须是将来的时间”) |
3.2 自定义校验注解
当内置注解不满足需求时,可以自定义校验注解:
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.regex.Pattern;
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneNumberValidator.class)
public @interface PhoneNumber {
String message() default "手机号格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
需要有一个类跟自定义注解搭配使用:
public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber, String> {
private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
return PHONE_PATTERN.matcher(value).matches();
}
}
4 注解使用
4.1 基本使用
一般都是在Controller中使用注解进行参数校验,Spring Boot支持通过@Valid(JSR标准)和@Validated(Spring扩展,支持分组校验)注解触发校验。
4.1.1 GET请求校验
GET请求类型的接口,一般参数是简单类型,参数的校验通过在方法形参前加注解实现,比如验证字符串非空的@NotBlank,注意,这种场景下一定要搭配@RequestParam注解使用,否则校验注解不生效。
@RestController
public class UserController {
@GetMapping("getUser")
public String getUser(@NotBlank(message = "用户名不能为空") @RequestParam String username,
@Min(value = 18, message = "年龄不能小于18") @RequestParam Integer age) {
return "User: " + username + ", age: " + age;
}
}
上面的示例代码是对GET类型的请求进行参数校验的示例,如果缺少必须的@RequestParam参数会导致MissingServletRequestParameterException异常,这类异常需要在全局异常处理器中进行捕获并处理。
4.1.2 POST请求校验
POST类型的请求,参数一般放在请求体中,通常使用@RequestBody注解接收一个DTO对象,这种情况下的校验一般是DTO对象,因此校验注解写在DTO的字段上,然后使用@Valid或@Validated注解触发校验。
import org.springframework.validation.annotation.Validated;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/users")
public class UserController {
@PostMapping
public String createUser(@Valid @RequestBody UserRequest userRequest) {
// 如果校验失败,程序会自动抛出异常
return "User is valid";
}
}
@Data
class UserDTO {
@NotBlank(message = "名称不能为空")
private String username;
@Min(18, message = "年龄不应低于18")
private Integer age;
}
当请求体中的数据不满足校验要求时,Spring Boot默认抛出MethodArgumentNotValidException异常。
4.1.3 嵌套校验(级联校验)
特别地,如果在POST请求中,请求体DTO类中包含了其他组合对象(即一个DTO中引用了另一个DTO作为字段),通常需要在这个组合对象的字段上加@Valid注解,以便触发该组合对象的递归校验(也叫嵌套校验)。
组合对象未加@Valid时,Spring Boot校验器只会校验当前DTO的基本字段注解,不会对组合对象中对应的字段的校验注解生效,也就是说组合对象里的字段会被忽略。在组合对象对应的字段上加上@Valid注解后,Spring Boot校验器会递归进入这个组合对象,执行该对象中字段的校验注解,从而实现多层级、复杂对象的完整校验。
@Data
public class Address {
@NotBlank(message = "地址不能为空")
private String street;
@NotBlank(message = "城市不能为空")
private String city;
}
@Data
public class UserDTO {
@NotBlank(message = "用户名不能为空")
private String username;
@Valid // 组合对象字段加@Valid,触发嵌套校验
private Address address;
}
上面的代码示例中,如果UserDTO中的address字段没有加@Valid,那么address对象里的@NotBlank注解不会生效。
5 总结
介绍了Spring Boot中如何使用注解对参数进行校验。Spring Boot通过注解校验简化了数据有效性验证。使用时需引入 spring-boot-starter-validation 依赖(2.3及以后版本),它整合了hibernate-validator和validation-api。常见注解有@NotNull、@NotBlank、@Size、@Min等,满足大部分校验需求。
入参校验&spm=1001.2101.3001.5002&articleId=150338292&d=1&t=3&u=8fcbca654ad9457697722bb8b6843fbd)
4651

被折叠的 条评论
为什么被折叠?



