Hibernate Validator简单使用

介绍

JSR-303 是JAVA EE6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现,提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。

简单校验

添加maven依赖

<dependency>
      <groupId>org.hibernate.validator</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.0.17.Final</version>
</dependency>

hibernate-validator还依赖以下两个

<dependency>
      <groupId>javax.el</groupId>
      <artifactId>javax.el-api</artifactId>
      <version>3.0.0</version>
</dependency>
<dependency>
      <groupId>org.glassfish</groupId>
      <artifactId>javax.el</artifactId>
      <version>3.0.0</version>
</dependency>

实体类

@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class User {

  @NotBlank(message = "用户名不能为空")
  private String username;
  @NotBlank(message = "密码不能为空")
  private String password;
  @NotBlank(message = "密码不能为空")
  @Pattern(regexp = "^1([34578])\\d{9}$", message = "手机号格式错误")
  private String mobile;
  @NotBlank(message = "性别不能为空")
  private String gender;
  @NotNull(message = "年龄不能为空")
  @Range(min = 5, max = 90, message = "年龄必须在5-90之间")
  private Integer age;

  private List<Address> addressList;

  @AllArgsConstructor
  @NoArgsConstructor
  @Setter
  @Getter
  static class Address {

    private String province;
    private String city;
    private String region;
  }
}
public class Client {

  public static void main(String[] args) {
    Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
    User user = new User();
    Set<ConstraintViolation<User>> constraintViolationSet = validator.validate(user);
    for (ConstraintViolation<User> constraintViolation : constraintViolationSet) {
      System.out.println(constraintViolation.getMessage());
    }
  }

}

Validation会通过SPI的方式找到所有ValidationProvider接口的实现,自然就找到hibernate-validator的实现HibernateValidator了。

当然我们也可以自己指定实现,自定义配置

public class Client {

  public static void main(String[] args) {
    Validator validator = Validation.byProvider(HibernateValidator.class)
        .configure()
        .failFast(true) //有一个失败就停止检查
        .buildValidatorFactory()
        .getValidator();
    User user = new User();
    Set<ConstraintViolation<User>> constraintViolationSet = validator.validate(user);
    for (ConstraintViolation<User> constraintViolation : constraintViolationSet) {
      System.out.println(constraintViolation.getMessage());
    }
  }

}

级联校验

实体类

@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class User {

  @NotBlank(message = "用户名不能为空")
  private String username;
  @NotBlank(message = "密码不能为空")
  private String password;
  @NotBlank(message = "密码不能为空")
  @Pattern(regexp = "^1([34578])\\d{9}$", message = "手机号格式错误")
  private String mobile;
  @NotBlank(message = "性别不能为空")
  private String gender;
  @NotNull(message = "年龄不能为空")
  @Range(min = 5, max = 90, message = "年龄必须在5-90之间")
  private Integer age;

  @Valid
  @NotEmpty(message = "地址不能为空")
  private List<Address> addressList;

  @AllArgsConstructor
  @NoArgsConstructor
  @Setter
  @Getter
  static class Address {

    @NotBlank(message = "省不能为空")
    private String province;
    @NotBlank(message = "市不能为空")
    private String city;
    @NotBlank(message = "区不能为空")
    private String region;
  }
}

使用Valid注解实现级联校验

public class Client {

  public static void main(String[] args) {
    Validator validator = Validation.byProvider(HibernateValidator.class)
        .configure()
        .failFast(false) //有一个失败就停止检查
        .buildValidatorFactory()
        .getValidator();
    User user = new User();
    user.setAddressList(Collections.singletonList(new Address()));
    Set<ConstraintViolation<User>> constraintViolationSet = validator.validate(user);
    for (ConstraintViolation<User> constraintViolation : constraintViolationSet) {
      System.out.println(constraintViolation.getMessage());
    }
  }

}

分组校验

实体类

@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class User {

  @NotBlank(message = "用户名不能为空")
  private String username;
  @NotBlank(message = "密码不能为空")
  private String password;
  @NotBlank(message = "密码不能为空")
  @Pattern(regexp = "^1([34578])\\d{9}$", message = "手机号格式错误")
  private String mobile;
  @NotBlank(message = "性别不能为空")
  private String gender;
  @NotNull(message = "年龄不能为空")
  @Range(min = 18, max = 90, message = "年龄必须在18-90之间", groups = Adult.class)
  @Range(min = 5, max = 17, message = "年龄必须在5-17之间", groups = Minor.class)
  private Integer age;

  private List<Address> addressList;

  @AllArgsConstructor
  @NoArgsConstructor
  @Setter
  @Getter
  static class Address {

    private String province;
    private String city;
    private String region;
  }

  /**
   * 成年人
   */
  interface Adult {
  }

  /**
   * 未成年人
   */
  interface Minor {
  }
}

不设置分组,默认为Default分组

public class Client {

  public static void main(String[] args) {
    Validator validator = Validation.byProvider(HibernateValidator.class)
        .configure()
        .failFast(false) //有一个失败就停止检查
        .buildValidatorFactory()
        .getValidator();
    User user = new User();
    user.setAge(7);
    Set<ConstraintViolation<User>> constraintViolationSet = validator
        .validate(user, Default.class, Adult.class); // 设置要校验的分组
    for (ConstraintViolation<User> constraintViolation : constraintViolationSet) {
      System.out.println(constraintViolation.getMessage());
    }
  }

}

不设置也会添加一个默认分组Default

自定义校验器

校验注解

/**
 * 当前值必须在给定的列表中
 */
@Target({FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {ListRangeValidatorForString.class})
public @interface ListRange {

  String message() default "";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};

  String[] value() default {};
}

校验器

public class ListRangeValidatorForString implements ConstraintValidator<ListRange, String> {

  private String[] range;

  @Override
  public void initialize(ListRange listRange) {
    this.range = listRange.value();
  }

  @Override
  public boolean isValid(String value, ConstraintValidatorContext context) {
    if (Objects.isNull(value)) {
      return true;
    }
    return Arrays.asList(range).contains(value);
  }
}

实体类

@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class User {

  @NotBlank(message = "用户名不能为空")
  private String username;
  @NotBlank(message = "密码不能为空")
  private String password;
  @NotBlank(message = "密码不能为空")
  @Pattern(regexp = "^1([34578])\\d{9}$", message = "手机号格式错误")
  private String mobile;
  @NotBlank(message = "性别不能为空")
  @ListRange(value = {"male", "female"}, message = "性别必须在[male,female]之间")
  private String gender;
  @NotNull(message = "年龄不能为空")
  @Range(min = 5, max = 90, message = "年龄必须在5-90之间")
  private Integer age;

  private List<Address> addressList;

  @AllArgsConstructor
  @NoArgsConstructor
  @Setter
  @Getter
  static class Address {

    private String province;
    private String city;
    private String region;
  }
}

性别必须在male和female之间

public class Client {

  public static void main(String[] args) {
    Validator validator = Validation.byProvider(HibernateValidator.class)
        .configure()
        .failFast(false) //有一个失败就停止检查
        .buildValidatorFactory()
        .getValidator();
    User user = new User();
    user.setAge(7);
    user.setGender("ss");
    Set<ConstraintViolation<User>> constraintViolationSet = validator.validate(user);
    for (ConstraintViolation<User> constraintViolation : constraintViolationSet) {
      System.out.println(constraintViolation.getMessage());
    }
  }

}

hibernate-validator会先找内置的注解校验器,找不到就找自定义的校验器。

对国际化的支持

实体类

@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class User {

  @NotBlank(message = "{username.errormsg}")
  private String username;

}

配置文件

文件内容为

username.errormsg=用户名称不能为空

校验

import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;

public class Client {

  public static void main(String[] args) {
    //创建ResourceBundle定位器,从哪里读取配置文件
    ResourceBundleLocator resourceBundleLocator = new ResourceBundleLocator() {
      @Override
      public ResourceBundle getResourceBundle(Locale locale) {
        return ResourceBundle.getBundle("i18n/messages", locale);
      }
    };
    //定义消息interpolator,从ResourceBundle中读取
    ResourceBundleMessageInterpolator interpolator = new ResourceBundleMessageInterpolator(
        resourceBundleLocator);
    Validator validator = Validation.byProvider(HibernateValidator.class)
        .configure()
        .failFast(false) //有一个失败就停止检查
        .messageInterpolator(interpolator)
        .buildValidatorFactory()
        .getValidator();
    User user = new User();
    Set<ConstraintViolation<User>> constraintViolationSet = validator
        .validate(user, Default.class);
    for (ConstraintViolation<User> constraintViolation : constraintViolationSet) {
      System.out.println(constraintViolation.getMessage());//用户名称不能为空
    }
  }

}

我们可以设置校验器的MessageInterpolator,可以看做消息处理器,这里我们从ResourceBundle中读取错误信息。

posted @ 2020-10-24 16:33  strongmore  阅读(6184)  评论(0编辑  收藏  举报