一:前言

  • SpringValidation是对hibernate validation的二次封装,添加自动校验的功能,并将校验结果封装到特定的结果类中。
  • hibernate validation是校验框架,是JSR303标准的实践结果。
  • 引入hibernate validatior:导入spring-boot-starter-web依赖即可,已经包括所需jar包。
<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

二:Demo

2.1 简单Demo

常用的检验规则:

JSR提供的校验注解:         
@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(regex=,flag=)      被注释的元素必须符合指定的正则表达式    

Hibernate Validator提供的校验注解:  
@NotBlank(message =)        验证字符串非null,且长度必须大于0    
@Email                      被注释的元素必须是电子邮箱地址    
@Length(min=,max=)          被注释的字符串的大小必须在指定的范围内    
@NotEmpty                   被注释的字符串的必须非空    
@Range(min=,max=,message=)  被注释的元素必须在合适的范围内

在实体类上添加校验规则:

@Data
@AllArgsConstructor
public class User {
    @NotBlank(message = "用户姓名不能为空")
    private String name;
    @Min(value = 18,message = "18岁以下禁止入内")
    private int age;
}

在controller上添加注解:@validated

@RestController
@RequestMapping("user")
@Slf4j
public class UserController {

    @GetMapping("validate")
    public void userValidates(@RequestBody @Validated() User user, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            bindingResult.getAllErrors().forEach(s->System.out.println(s.getDefaultMessage()));
            //我们可以在这里抛出一个异常
            log.info("用户登录信息出现异常");
        }
    }
}

校验错误的结果会封装到BindingResult 对象中,每一个校验的对象对应着一个结果对象。

2.2:分组校验

有时候我们对不同场景需要有不同的校验。
bean:

@Data
@AllArgsConstructor
public class User {
    @NotBlank(message = "用户姓名不能为空")
    @EndName
    private String name;
    @Min(value = 18,message = "18岁以下禁止入内",groups = {admin.class})
    private int age;
	//这里定义一个接口
    public interface admin{}
}

这样就会出现两个分组default和admin。
controller:

@GetMapping("validate2")
    public void userValidates2(@RequestBody @Validated(value = User.admin.class) User user, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            bindingResult.getAllErrors().forEach(s->System.out.println(s.getDefaultMessage()));
            //我们可以在这里抛出一个异常
            log.info("用户登录信息出现异常");
        }
    }
2.3 自定义校验

目标: 用户输入的名称必须包含我们所规定的文字。
我们通过这个注解校验@EndName(value = “哈哈”,message = “名字必须包含哈哈”)。

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
//实现类
@Constraint(validatedBy = {EndNameValidator.class})
public @interface EndName {
    //返回一个值,也就是返回value属性的值
    String value();
    
    //默认错误消息
    String message() default "xxxxx";
    
    //分组
    Class<?>[] groups() default {};
    
    //负载
    Class<? extends Payload>[] payload() default {};
    
    //一个页面可以多个注解
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @Documented
    @interface List {

        EndName[] value();
    }
}

实现类:

public class EndNameValidator implements ConstraintValidator<EndName, String> {

    String value;

    @Override
    public void initialize(EndName constraintAnnotation) {
    	//调用value方法来返回规定包含的字符串
        this.value=constraintAnnotation.value();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context ) {
        if(value.contains(this.value)){
            return true;
        }
        return false;
    }
}

如何需要试一试其他自定义注解的写法,去看看源码就ok了,我这个注解仿照的是@Min注解。

2.4 手动校验

Spring已经对validation全面支持,并封装了LocalValidatorFactoryBean作为validator的实现。So,我们直接拿来用就好了。

//这个是javax.validation.Validator包下的
    @Autowired
    private Validator globalValidator ;
	@GetMapping("hello")
    public void hello(){
    	//校验规则添加在user实体类上
        User user = new User("张三", 24);
        //校验结果都在这里面
        Set<ConstraintViolation<User>> validate = validator.validate(user);
        validate.forEach(s->System.out.println(s));
    }
基于方法的校验:
@Validated
@RestController
@Slf4j
public class validateController {

    @GetMapping("hello")
    public void test(@Min(value = 18,message = "这个不行") @RequestParam("age") int number){
        //这个验证不通过会报错
    }

    @ExceptionHandler(value = ConstraintViolationException.class)
    public void test2(){
        log.info("异常我就收下了");
    }
}

在类上添加@Validated注解,在需要的属性上添加自己的校验规则,当校验不通过的时候,会抛出ConstraintViolationException,我们可以自定义一个异常捕获的方法,来进行捕获。