網頁

2018/8/7

Java 使用自訂的Java Bean Validation Annotation來驗證Bean屬性範例

Java Bean Validation可以在Java Bean的屬性掛上注釋(Annotation)來進行驗證。

例如有一個Customer Java Bean,有一個屬性custId的長度必須為10,所以我們可以自訂一個annotation @CustIdLength來進行驗證。

使用前要匯入Java Validation API的jar,以及其實作Hibernate Validator的jar。這裡使用Maven的pom.xml

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.0.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.2.4.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator-annotation-processor</artifactId>
    <version>5.2.4.Final</version>
</dependency>

Customer.java

package idv.matt.model;

import javax.validation.constraints.NotNull;

import idv.matt.annotation.CustIdLength;

public class Customer {
  
  @CustIdLength // 自訂的annotation
  private String custId;
  
  @NotNull // Java Bean Validation的annotation
  private String custName;
  
  // getter and setter ommitted
  
}

@CustIdLength

package idv.matt.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;

import idv.matt.annotation.validator.CustIdLengthValidator;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Constraint(validatedBy = { CustIdLengthValidator.class })
@ReportAsSingleViolation
public @interface CustIdLength {

  String message() default "custId length should be 10";

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

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

}

CustIdLengthValidator.java

package idv.matt.annotation.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import idv.matt.annotation.CustIdLength;

public class CustIdLengthValidator implements ConstraintValidator<CustIdLength, String> {

  @Override
  public void initialize(CustIdLength constraintAnnotation) {
    
  }

  @Override
  public boolean isValid(String custId, ConstraintValidatorContext ctx) {
    if (custId == null) {
      return true; // 通過
    }

    if (custId.length() == 10) {
      return true; // 通過
    }

    return false; // 不通過
  }

}

測試

package idv.matt.main;

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import idv.matt.model.Customer;

public class Main {

  public static void main(String[] args) {

    ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
    Validator validator = vf.getValidator();

    Customer customer = new Customer();
    customer.setCustId("1234567890XX");

    validate(validator, customer);

    vf.close();
 
  }

  private static void validate(Validator validator, Customer customer) {
    Set<ConstraintViolation<Customer>> violations = validator.validate(customer);
    if (violations.isEmpty()) {
      System.out.println("Valid customer: " + customer.getCustId());
    } else {
      for (ConstraintViolation<Customer> violation : violations) {
        System.out.println(violation.getMessage());
      }
      throw new ConstraintViolationException(violations);
    }
  }
}

執行後訊息如下

custId length should be 10
may not be null
Exception in thread "main" javax.validation.ConstraintViolationException: custId: custId length should be 10, custName: may not be null
 at idv.matt.main.Main.validate(Main.java:xx)
 at idv.matt.main.Main.main(Main.java:xx)

後來發現不用那麼麻煩自己寫Validator,改用@Size(max=10, min=10)即可。

package idv.matt.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;
import javax.validation.constraints.Size;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Constraint(validatedBy = {})
@Size(max=10, min=10)
@ReportAsSingleViolation
public @interface CustIdLength {

  String message() default "custId length should be 10";

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

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

}

參考:

沒有留言:

張貼留言