使用JSR303对数据进行校验【JAVA】

前言

1、SpringBoot项目中Controller的validator做参数校验不生效的问题

解决:

springboot 2.3之前的集成在spring-boot-starter-web里了,所以不需要额外引入包

springboot 2.3之后需要引入 spring-boot-starter-validation


简单校验

流程:

        ①在需要校验的属性上添加校验注解

        ②在controller方法内,在对应的实体类前面添加 @Valid 注解,开启属性校验功能

代码:

public class UserEntity {
    
    @Min(value = 0,message = "年龄不能小于0!")  //@Min该注解表示age的值要大于或等于0
    private Integer age;

    @NotBlank(message = "用户名不能为空!")  //@NotBlank注解表示该属性不能为空
    private String username;

    @NotBlank(message = "密码不能为空!")
    @Length(min = 6,message = "密码不能低于6位!")   //@Length该注解表示长度要大于6
    private String password;

    private String nickname;
}
/**
 * 简单的校验规则
 */
@RestController
public class SimpleValidRule {

    /**
     * @param user   要校验的实体类
     * @param result 如果不满足校验规则,可以通过该类接受异常信息
     * @return
     * @Valid 开启数据校验功能
     */
    @RequestMapping("/simpleSave")
    private Map saveUser(@Valid @RequestBody UserEntity user, BindingResult result) {
        Map map = new HashMap<>();
        if (result.hasErrors()) {
            result.getFieldErrors().forEach(item -> {
                //获取失败信息
                map.put(item.getField(), item.getDefaultMessage());
            });
        } else {
            map.put("data", "数据校验成功");
        }
        return map;
    }

}

分组校验

ps:上面通过简单案例演示了数据校验,但是可以看到属性校验返回的异常信息是跟业务代码写在一起,这样看起来非常不优雅,同时也不利于后面维护,所以对于异常信息,我们应该使用一个全局异常处理。

流程:

        ①还是在需要校验属性的上面添加校验规则,但是这里还添加了一个分组属性。想象一下,如果执行save方法时,我们必须要求用户输入username属性,执行update方法时,必须用户传入age属性,那如果通过上面校验,发现并不能满足这种要求,所以这就是分组的意义。

        ②在controller方法内,通过注解@Validated开启属性校验,通过指定要校验的规则,如果不指定,则跟上面简单校验一样。

代码:

public class UserEntity2 {

    //这里可以看到,该属性校验多了一个groups分组属性
    @Min(value = 0, message = "年龄不能小于0!", groups = UpdateGroup.class)   
    private Integer age;
       
    //可以看到,username跟前面的age属性定义了不同组
    @NotBlank(message = "用户名不能为空!", groups = SaveGroup.class)    
    private String username;

    @NotBlank(message = "密码不能为空!")
    @Length(min = 6, message = "密码不能低于6位!")
    private String password;

    @NotBlank(message = "用户昵称不能为空", groups = {SaveGroup.class})
    private String nickname;
}
/**
 * 指定分组校验
 */
@RestController
public class GroupValidRule {
    
    //这里通过@Validated注解定义了只校验那个分组下的属性,其它分组,包括没写的,不会进行校验
    @PostMapping("/groupSave")
    private String saveUser(@Validated(value = SaveGroup.class) @RequestBody UserEntity user) {
        /* 执行一系列流程... */
        return "数据校验成功";
    }

    @PostMapping("/groupUpdate")
    private String updateUser(@Validated(value = UpdateGroup.class) @RequestBody UserEntity user) {
        /* 执行一系列流程... */
        return "数据校验成功";
    }
}
/**
 * 全局异常处理类
 */
@RestControllerAdvice
public class GlobalException {

    @ExceptionHandler
    public String handlerException(Exception e){
        return "数据校验失败!";
    }
}

上面如果执行saveUser方法,因为使用注解@Validated(value = SaveGroup.class)定义了只校验SaveGroup分组下的属性,所以只有username属性会被进行校验!

自定义校验

可能以上校验规则并不一定符合我们,所以这时候可以通过自定义校验规则

流程:

        ①new一个自定义注解类

        ②创建具体的校验规则类,需要实现ConstraintValidator接口,重写两个方法:initialize()和isValid()

        ③在需要自定义校验属性上添加该注解,并指定校验规则

代码:

@Data
public class UserEntity3 {

    //这里自定义校验规则,要求必须输入name的值为张三
    @CustomValidAnnotation(name = "张三") 
    private String name;
}
/**
 * 自定义校验
 */
@RestController
public class CustomValidRule {

    @RequestMapping("/customSave")
    private String saveUser(@Validated @RequestBody UserEntity user) {
        return "属性校验成功";
    }
}
/**
 * 自定义校验注解
 */
@Constraint(
        validatedBy = {CustomValid.class} //自定义具体的校验器,可以指定多个
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomValidAnnotation {
    String message() default "";

    Class[] groups() default {};

    Class[] payload() default {};

    String name();  //添加一个name属性作为校验规则

}
/**
 * 自定义校验器,需要实现ConstraintValidator并传入两个泛型,第一个是自定义校验的注解,第二个校验属性的类型
 */
public class CustomValid implements ConstraintValidator {
    private String name;

    /**
     * 这个方法可以获取我们自定义校验属性的值,也就是在实体类定义属性校验规则
     * @param constraintAnnotation  自定义注解
     */
    @Override
    public void initialize(CustomValidAnnotation constraintAnnotation) {
        String name = constraintAnnotation.name();  //获取自定义注解上的value
        this.name = name;
    }

    /**
     * 这个方法是获取用户传入的数据,我们可以通过上面拿到的校验规则与用户输入进行校验匹配,判断用户输入是否满足我们要求的参数格式
     * @param s 用户输入的值
     * @param constraintValidatorContext
     * @return 返回false表示输入的数据不合法,true则相反
     */
    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        if (name.equals(name)){
            return true;
        }
        return false;
    }
}

你可能感兴趣的:(java,spring,boot,spring)