Hibernate Validator 驗證框架 簡單入門

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

聲明方式

1. Field-Leveljava

基於屬性的校驗git

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

2. Property-Levelweb

基於getter的校驗正則表達式

public class User{
    private String name;

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

3. Container Elementspring

容器校驗ide

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

4. Class-Levelspring-boot

類校驗ui

// 聲明註解
@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 inheritancespa

約束繼承:當一個類繼承另外一個類或者實現一個接口,超類中聲明的約束與該類自己聲明的約束一樣有效

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);
相關文章
相關標籤/搜索