参数校验
在日常开发中,经常需要对前端传过来的数据进行,非空等有效校验。但是如果使用if (username == null)
的方式进行手动判断,会十分麻烦并且每次都需要校验;
于是Validator框架应运而生,提供了很多方便的校验注解(非空、邮箱是否有效、长度限制等)
详细使用
一般SpringBoot的项目会使用Spring Validation,它是对Hibernate Validation的二次封装。在SpringMVC模块中添加了自动校验。并将校验信息封装到特定的类中。
提供的校验注解:
@Null
被注释的元素必须为null
@NotNull
被注释的元素必须不为null
@AssertTrue
被注释的元素必须为true
@AssertFalse
被注释的元素必须为false
@Min(value)
被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)
被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)
被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)
被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min)
被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction)
被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past
被注释的元素必须是一个过去的日期
@Future
被注释的元素必须是一个将来的日期
@Pattern(value)
被注释的元素必须符合指定的正则表达式
@NotBlank(message =)
验证字符串非 null,且长度必须大于 0
@Email
被注释的元素必须是电子邮箱地址
@Length(min=,max=)
被注释的字符串的大小必须在指定的范围内
@NotEmpty
被注释的字符串的必须非空
@Range(min=,max=,message=)
被注释的元素必须在合适的范围内
基本使用
首先导入依赖
1 2 3 4 5
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
|
给需要校验的实体类添加校验注解
TestDemo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import lombok.Data;
import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Size;
@Data public class TestDemo { @NotNull(message = "id必须非空") private Long id;
@NotBlank(message = "用户名不能为空,并且长度必须大于0") @Size(min = 6, max = 11, message = "用户名长度必须是6-11个字符") private String username;
@NotBlank(message = "用户密码不能为空,并且长度必须大于0") @Size(min = 6, max = 16, message = "密码长度必须是6-16个字符") private String password;
@Email(message = "邮箱格式错误") @NotBlank(message = "邮箱不能为空,并且长度必须大于0") private String email;
@Valid @NotNull private Test02 test02; }
|
Test02:
1 2 3 4 5 6 7 8 9 10
| import lombok.Data;
import javax.validation.constraints.NotNull;
@Data public class Test02 {
@NotNull(message = "id必须非空") private Long id; }
|
测试校验
1 2 3 4 5 6 7 8 9 10
| @PostMapping("/insert") public String insertTestUser(@RequestBody @Validated TestDemo testUser, BindingResult bindingResult){ for (ObjectError error : bindingResult.getAllErrors()) { return error.getDefaultMessage(); } log.info("用户名{}的邮箱为{}", testUser.getUsername(),testUser.getEmail()); return "success"; }
|
@Valid注解与@Validated注解功能差不多
不同点在于:
- @Valid属于javax包下,而@Validated属于Spring下
- @Valid支持嵌套校验、而@Validated不支持
- @Validated支持分组,而@Valid不支持
自定义校验注解
定义自定义注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint( validatedBy = PhoneValidator.class ) public @interface Phone { String message() default "手机格式不正确!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
|
定义该注解的校验器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.util.regex.Matcher; import java.util.regex.Pattern;
public class PhoneValidator implements ConstraintValidator<Phone, String> { @Override public boolean isValid(String phoneNum, ConstraintValidatorContext constraintValidatorContext) { if (phoneNum == null && phoneNum.length() == 0) { return true; } Pattern p = Pattern.compile("^(13[0-9]|14[5|7|9]|15[0|1|2|3|5|6|7|8|9]|17[0|1|6|7|8]|18[0-9])\\d{8}$"); Matcher matcher = p.matcher(phoneNum); return matcher.matches(); } }
|
分组校验
比如当更新时需要带用户id,但当插入时不需要,这个时候就需要分组校验来处理
定义分组
1 2 3 4
| import javax.validation.groups.Default;
public interface Update extends Default { }
|
指定分组
1 2 3 4 5
|
@NotNull(message = "id必须非空",groups ={Update.class}) private Long id;
|
测试使用
1 2 3 4 5 6 7 8 9
| @PostMapping("/insert") public String insertTestUser(@RequestBody @Validated(value = Update.class) TestDemo testUser, BindingResult bindingResult){ for (ObjectError error : bindingResult.getAllErrors()) { return error.getDefaultMessage(); } log.info("用户名{}的邮箱为{}", testUser.getUsername(),testUser.getEmail()); return "success"; }
|
Tip:当不使用BindingResult时,校验失败会引发MethodArgumentNotValidException异常,这样就正好可以使用SpringBoot全局异常处理
快速失败(failFast)
SpringValidation框架默认是关闭快速失败的,也就是说当一个参数校验不通过的时候它不会直接停止,而是会继续校验剩余的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Configuration public class ValidatorConfiguration {
@Bean public Validator validator(AutowireCapableBeanFactory springFactory) { try (ValidatorFactory factory = Validation.byProvider(HibernateValidator.class) .configure() .failFast(true) .constraintValidatorFactory(new SpringConstraintValidatorFactory(springFactory)) .buildValidatorFactory()) { return factory.getValidator(); } } }
|
参考