Hibernate Validator 验证框架 简单入门

本文参考自:http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/

声明方式

1. Field-Level

基于属性的校验

public class User{
    [@NotNull](https://my.oschina.net/notnull)
    private String name;
}

2. Property-Level

基于getter的校验

public class User{
    private String name;

    [@NotNull](https://my.oschina.net/notnull)
    public String getName(){
        return name;
    }
}

3. Container Element

容器校验

public class User{
    // 集合中元素须长度 > 2
    private List<@Length(min = 3) String> roles;
}

4. Class-Level

类校验

// 声明注解
@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = {UserNameNotMatchValidator.class})
@Documented
public @interface UserNameNotMatch{
    String message() default "用户不匹配";
    Class<?>[] groups() default {};
    String allowName() default "admin";
    Class<? extends Payload>[] payload() default {};
}

// 编写具体的校验类
public class UserNotMatchValidator implements ConstraintValidator<UserNotMatch, User> {
    private String allowName;

    @Override
    public void initialize(UserNotMatch constraintAnnotation) {
        allowName = constraintAnnotation.allowName();
    }
    @Override
    public boolean isValid(User user, ConstraintValidatorContext constraintValidatorContext) {
	if (allowName.equals(user.getName())) {
	    return true;
	} else {
	    // 屏蔽默认错误信息
	    constraintValidatorContext.disableDefaultConstraintViolation();
	    constraintValidatorContext.buildConstraintViolationWithTemplate("普通用户不允许操作").addConstraintViolation();
	    return false;
	}
    }
}

@UserNameNotMatch
public class User{
    private String name;
}

5. Constraint inheritance

约束继承:当一个类继承另一个类或者实现一个接口,超类中声明的约束与该类本身声明的约束同样有效

public class User{
    @NotNull
    private String name;
}

public class Person extends User{
    @NotNull
    private String sex;
}

6. Object graphs

public class Role{
    @NotNull
    private String auth;
}

public class User{
    @Valid // 标记该注解才会进行校验Role对象,否则只校验User.role
    @NotNull
    private Role role;
}

public class Role{
    private String auth;
}

public class User{
    private Set<@NotNull @Valid Role> roleSet;
}

开始验证

手动创建Validator

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();

Spring Boot

引入spring-boot-starter-web,该依赖中包含 hibernate-validator,自动装配Validator Bean

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

注入Validator (javax.validation)

@Autowired
private Validator validator

验证

Validator#validate(T clazz): 校验类(@Valid 仅在使用该方法时有效)
Validator#validateProperty(T clazz,String propertyName): 校验属性
Validator#validateValue(T clazz,String propertyName, String value): 校验属性值

示例

Set<ConstraintViolation<T>> violationSet = validator.validate(tClass);
violationSet.forEach(userConstraintViolation -> log.warn("Validation Err Bean={}, Property = {},Msg = {}", userConstraintViolation.getRootBeanClass(), userConstraintViolation.getPropertyPath(), userConstraintViolation.getMessage()));

ConstraintViolation

ConstraintViolation#getPropertyPath(): 属性名称  
ConstraintViolation#getMessage(): 错误信息

Validation API 提供的约束

  1. @AssertFalse 检查被标记元素是否为 false
  2. @AssertFalse 检查被标记元素是否为 true
  3. @DecimalMax(value=, inclusive=) 检查被标记的元素是否小于(或者等于)指定的最大值。inclusive=false 检查被标记的元素是否小于指定的最大值;如果inclusive=true 检查被标记的值是否小于或者等于指定的最大值(支持的数据类型:BigDecimal, BigInteger, CharSequence, byte, short, int, long
  4. @Digits(integer=, fraction=) 检查被标记的元素,整数位数在integer范围内,小数位数在fraction范围内(支持的数据类型:BigDecimal, BigInteger, CharSequence, byte, short, int, long
  5. @Email(regexp=,flags=) 检查被标记的元素是否是一个有效的电子邮件地址。regexp为正则表达式;flags为正则表达式标志(参考:https://blog.csdn.net/hsttmht/article/details/6964018)
  6. @Future 检查被标记日期是否在将来
  7. @FutureOrPresent 检查被标记日期是否在将来或者当前
  8. @Max(value=) 检查被标记的元素是否小于或者等于指定的最大值(支持的数据类型:BigDecimal, BigInteger, byte, short, int, long
  9. @Min(value=) 检查被标记的元素是否大于或者等于指定的最小值(支持的数据类型:BigDecimal, BigInteger, byte, short, int, long
  10. @NotBlank 检查被标记的字符串是否不为空且trim()后的字符串长度大于0
  11. @NotEmpty 检查被标记的值是否不为Null且长度/大小大于0(支持的数据类型:CharSequence, Collection, Map and arrays
  12. @NotNull 检查被标记的元素是否不为Null
  13. @Negative 检查被标记的元素是否为负数(支持的数据类型:BigDecimal, BigInteger, byte, short, int, long
  14. @NegativeOrZero 检查被标记的元素是否为负数或者0(支持的数据类型:BigDecimal, BigInteger, byte, short, int, long
  15. @Null 检查被标记的值是否为Null
  16. @Past 检查被标记日期是否在过去
  17. @PastOrPresent 检查被标记日期是否在过去或者当前
  18. @Pattern(regex=, flags=) 检查被标记的字符串是否与指定的正则表达式匹配;flags为正则表达式标志(参考:https://blog.csdn.net/hsttmht/article/details/6964018)
  19. @Positive 检查被标记的元素是否为正数(支持的数据类型:BigDecimal, BigInteger, byte, short, int, long
  20. @PositiveOrZero 检查被标记的元素是否为正数或者0(支持的数据类型:BigDecimal, BigInteger, byte, short, int, long
  21. @Size(min=, max=) 检查被标记的元素的大小是否在min和max之间,包括min、max(支持的数据类型:CharSequence,Collection, Map and arrays

错误消息

默认错误消息

ValidationMessages.properties

默认情况下使用JVM默认的语言环境,也可将本地化的ValidationMessages.properties添加到classpath下,覆盖默认语言环境下的配置

使用消息表达式

@Size(
        min = 2,
        max = 14,
        message = "The license plate '${validatedValue}' must be between {min} and {max} characters long"
)
private String licensePlate;

Car car = new Car();
car.setLicensePlate("A");
message = validator.validateProperty( car, "licensePlate" )
    .iterator()
    .next()
    .getMessage();
assertEquals(
    "The license plate 'A' must be between 2 and 14 characters long",
    message

);

分组约束

Requesting groups 组约束

public class Car {
    @NotNull
    private String manufacturer;

    @NotNull
    @Size(min = 2, max = 14)
    private String licensePlate;

    @Min(2)
    private int seatCount;

    @AssertTrue(
        message = "The car has to pass the vehicle inspection first",
        groups = CarChecks.class
    )
    private boolean passedVehicleInspection;
}

//manufacturer、licensePlate、seatCount则不会被校验
constraintViolations = validator.validate( car, CarChecks.class );
assertEquals( 1, constraintViolations.size() );
assertEquals(
    "The car has to pass the vehicle inspection first",
    constraintViolations.iterator().next().getMessage()
);

Group inheritance 组继承

定义Group

public interface Group {
}

定义父类

public class GroupB {

    @NotNull(groups = Group.class)
    private String title;
}

定义子类

public class GroupA extends GroupB{

    @NotEmpty
    private String name;

    @NotNull(groups = Group.class)
    private String desc;
}

验证

constraintViolations = validator.validate( group,Group.class );
assertThat( constraintViolations ).extracting( "message" ).containsOnly(
    "title must not be null",
    "desc must not be null"
);

Defining group sequences 定义组序列

按照组序列的定义顺序,其中一个约束验证失败,其后的约束都不会得到验证

public interface Age {
}

public interface Sing {
}

@GroupSequence({Age.class, Sing.class})
public interface OrderChecks {
}

定义校验类

public class Person {

    @Min(value = 18, groups = Age.class)
    private Long age;

    @AssertTrue(groups = Sing.class)
    private boolean sing;
}

验证

Person person = new Person();
person.setAge(17L);
person.setSing(false);
validate(person, OrderChecks.class);

Redefining the default group sequence 重新定义组序列(@GroupSequence)

重新定义校验类

@GroupSequence标记的类必须声明在@GroupSequence中,如示例中的Person.class

@GroupSequence({Sing.class, Age.class, Person.class})
public class Person {

    @Min(value = 18, groups = Age.class)
    private Long age;

    @AssertTrue(groups = Sing.class)
    private boolean sing;
}

验证

Person person = new Person();
person.setAge(17L);
person.setSing(false);
validate(person);

Redefining the default group sequence 重新定义组序列(@GroupSequenceProvider)

public class PersonGroupSequenceProvider implements DefaultGroupSequenceProvider<Person> {

    @Override
    public List<Class<?>> getValidationGroups(Person person) {
	List<Class<?>> defaultGroupSequence = new ArrayList<>();
	// 必须包含类本身
	defaultGroupSequence.add(Person.class);
	if (null != person) {
	    defaultGroupSequence.add(Sing.class);
	    defaultGroupSequence.add(Age.class);
	}
	return defaultGroupSequence;
    }
}

@GroupSequenceProvider(PersonGroupSequenceProvider.class)
public class Person {

    @Min(value = 18, groups = Age.class)
    private Long age;

    @AssertTrue(groups = Sing.class)
    private boolean sing;
}

Group conversion 组转换

public class Person {

    @Min(value = 18, groups = Age.class)
    private Long age;

    @AssertTrue(groups = Sing.class)
    private boolean sing;

    @NotEmpty(groups = Sing.class)
    private List<String> songs;
}

public class Company {

    @Valid
    @ConvertGroup(from = Sing.class, to = Age.class)
    private Person person;
}

验证

Company company = new Company();
Person person = new Person();
person.setAge(17L);
person.setSing(false);
person.addSong("Trouble is a friend");
company.setPerson(person);
// 验证时传递的组是Sign.class,由于Company#person 定义了@ConvertGroup(from = Sing.class, to = Age.class),最终验证的组是Age.class
validate(company, Sing.class);

转载于:https://my.oschina.net/u/3757402/blog/3058648

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值