Java后端数据校验学习总结

Java后端校验总结

后端校验注解一直在用,但是感觉不是特别清楚,希望通过写这篇文章搞清楚。

Spring自带的Validation校验框架

Spring提供了Validator接口来校验对象,主要涉及到的方法和类如下:

  1. supports方法:设置校验器能对哪些对象进行校验;
  2. validate方法:对要校验的对象进行校验,并将校验错误记录在errors中;
  3. Errors类:用来存放错误信息的接口。Errors对象包含一系列的FieldError和ObjectError对象。FieldError表示与被获取的对象中的某一属性相关的一个错误;
  4. ValidationUtils:校验工具类,提供多个给Errors对象保存错误的方法;LocalValidatorFactoryBean:该类实现了Spring的Validator接口,也实现了JSR 303的Validator接口;
  5. BeanValidationPostProcessor:它就是个普通的BeanPostProcessor。它能够去校验Spring容器中的Bean,从而决定允不允许它初始化完成;
    Java后端数据校验学习总结_第1张图片

示例代码

实体类

public class MyUser implements Serializable {

    private String username;

    private Integer age;


    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}

UserValidator


/**
 * 用户数据校验类
 */
@Component
public class UserValidator implements Validator {

    /**
     * 对哪个类进行校验,此处仅对User类进行校验
     * @param clazz
     * @return
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return User.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        //对name进行校验
        ValidationUtils.rejectIfEmpty(errors, "username", "500", "name is empty");

        MyUser user = (MyUser) target;
        if (user.getAge() < 0) {
            //
            errors.rejectValue("age", "500", "年龄不能小于0");
        }
    }
}

Controller中的代码

    @Autowired
    private UserValidator userValidator;

    @RequestMapping("/test3")
    public void test1(MyUser user, Errors errors) {
        userValidator.validate(user, errors);
        if (errors.hasErrors()) {
            //如果校验出错,输出错误信息
            List<ObjectError> allErrors = errors.getAllErrors();
            for (ObjectError error : allErrors) {
                System.out.println("test1 error " + error.getCode() + " " + error.getDefaultMessage());
            }
        }
    }

JSR303

JSR 303是Java为Bean数据合法性校验提供的标准框架,已经包含在Java EE 6.0中。JSR是一个规范,它的核心接口是Validator,该接口根据目标对象类中所标注的校验注解进行数据校验,并得到校验结果。
JSR303包含的注解如下:
Java后端数据校验学习总结_第2张图片

示例代码

BindingResult:BindingResult扩展了Errors接口,同时可以获取数据绑定结果对象的信息。@Valid和BindingResult参数是成对出现的,并且在形参中出现的顺序是固定的,一前一后。


public class MyUser implements Serializable {

    @NotNull(message = "username is empty")
    @NotEmpty(message = "username is empty")
    private String username;

    @NotNull(message = "age is empty")
    @Max(value = 150L, message = "年龄最大为150")
    @Min(value = 0L, message = "年龄最小为0")
    private Integer age;


    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}
    @RequestMapping("/test4")
    public void test4(@Valid MyUser myUser, BindingResult result) {
        if (result.hasErrors()) {
            List<ObjectError> allErrors = result.getAllErrors();
            for (ObjectError error : allErrors) {
                System.out.println("error: " + error.getCode() + " " + error.getDefaultMessage());
            }
        }
    }

方法级别的参数校验

JSR和Hibernate validator的校验只能对Object的属性进行校验,不能对单个的参数进行校验,spring 在此基础上进行了扩展,添加了MethodValidationPostProcessor拦截器,可以实现对方法参数的校验。

1、注入Bean

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }

2、在controller上添加@Validated注解
Java后端数据校验学习总结_第3张图片

3、方法参数上加上注解校验

    @RequestMapping("/test5")
    public void test5(@NotNull(message = "username is empty")  @NotEmpty(message = "username is empty")
                                   @RequestParam String username, @NotNull(message = "age is empty") @Max(value = 150L, message = "年龄最大为150")
                                    @Min(value = 0L, message = "年龄最小为0") @RequestParam  Integer age) {
        System.out.println("username: " + username + " age: " + age);
    }

分组校验

1、定义两个分组

public interface MyUserAddVo {
}


public interface MyUserUpdateVo {
}

2、指定分组,age属性的@NtoNull注解指定了MyUserAddVo.class, MyUserUpdateVo.class两个分组,而@Min指定了一个分组

public class MyUser implements Serializable {

    @NotNull(groups = {MyUserAddVo.class, MyUserUpdateVo.class}, message = "username is empty")
    @NotEmpty(groups = {MyUserAddVo.class, MyUserUpdateVo.class}, message = "username is empty")
    private String username;

    @NotNull(groups = {MyUserAddVo.class, MyUserUpdateVo.class}, message = "age is empty")
    @Max(groups = {MyUserAddVo.class, MyUserUpdateVo.class}, value = 150L, message = "年龄最大为150")
    @Min(groups = {MyUserAddVo.class}, value = 0L, message = "年龄最小为0")
    private Integer age;


    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}

3、在Controller中具体指定使用哪个分组的校验,代码中指定使用MyUserUpdateVo分组

    /**
     * 备注:此处@Validated(PersonAddView.class) 表示使用PersonAndView这套校验规则,若使用@Valid 则表示使用默认校验规则,
     *若两个规则同时加上去,则只有第一套起作用
     *
     **/
    @RequestMapping("/test6")
    public void test6(@Validated({MyUserUpdateVo.class}) MyUser myUser) {
        System.out.println("username: " +  myUser.getUsername() + " age: " + myUser.getAge());
    }

@Valid和@Validated注解的区别

这两个注解都是进行数据校验的标志,区别如下:

  1. @Valid是JSR-303标准规定的;@Validated是Spring校验框架提供的;
  2. @Valid可以在方法/成员变量/构造函数/方法参数上使用;@Validated可以在类/方法/方法参数上使用;区别在于成员变量上是否可以使用;由于@Valid可以在成员变量上使用,因此可以嵌套校验;
  3. @Valid会把校验不通过的信息交给BindingResult中,因此在controller的方法中,@Valid和BindingResult要同时存在;
  4. @Validated可以在类上使用;可以配合MethodValidationPostProcessor实现校验基本数据包装类型和String类型等单独的对象

参考

  • 详述Spring对Bean Validation支持的核心API:Validator、SmartValidator、LocalValidatorFactoryBean…【享学Spring】
  • 《SpringMVC+MyBatis快速开发与项目实战 》
  • Spring数据校验(LocalValidatorFactoryBean和MethodValidationPostProcessor的区别/@Valid和@Validated的区别)
  • Java Bean Validation 最佳实践

你可能感兴趣的:(JavaEE,java,学习,spring)