數據校驗是貫穿所有應用程序層(從表示層到持久層)的常見任務。通常在每個層中實現相同的驗證邏輯,這是耗時且容易出錯的。這里我們可以使用Hibernate Validator來幫助我處理這項任務。對此,Hibernate Validator提供了一些注解來作為數據約束,我們只需要將這些注解添加到我們需要校驗的屬性/參數上面,就可以輕松的完成這項任務。
常見注解介紹
常見的注解,這里只是列出了一些常見的屬性上面的約束以及他們所擁有的一些屬性,更加詳細的介紹請看 官方文檔。
注解 | 數據類型 | 屬性 | 注解說明 | |
@NotNull | 字符串 | 添加注解的屬性不能是null | ||
@NotBlank | 字符串 | 檢查字符串是否是null,且去掉空格后長度是否是0 | ||
@AssertTrue | 布爾 | 檢查值是否是true | ||
@AssertFalse | 布爾 | 檢查值是否是false | ||
@DecimalMax | 數字 | 檢查值是否大於設定值 | ||
value | 設置的最大值 | |||
inclusive | 是否等於 | |||
@DecimalMin | 數字 | 檢查值是否小於設定值 | ||
value | 設置的最大值 | |||
inclusive | 是否等於 | |||
@Digits | 數字 | 校驗數字小數點前后位數 | ||
integer |
小數點前幾位 | |||
fraction |
小數點后幾位 | |||
字符串 | 校驗是不是郵箱 | |||
@Future | 時間 | 檢查日期是不是在將來 | ||
@Past | 時間 | 檢查日期是否在過去 | ||
@Max | 數字類型 | 是否大於最大值 | ||
@Min | 數字類型 | 是否小於最小值 | ||
@Pattern | 字符串 | 使用正則校驗 | ||
@Size | 字符串,集合,數組 | 檢查長度 |
簡單的使用
看到上面的那么多注解是不是覺得很實用呢?有沒有想試一試看看好不好用呢?接下來我們開始寫一些代碼來用一用,首先我們需要添加它的依賴。
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.15.Final</version> </dependency> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.el</artifactId> <version>3.0.1-b09</version> </dependency>
接下來定義一個Class,然后在他的屬性上添加Hibernate Validator提供的一些注解
import lombok.Getter; import lombok.Setter; import lombok.ToString; import javax.validation.constraints.*; import java.util.Date; /** * 產品表 * * @author hejiaxuan */ @Getter @Setter @ToString public class Demo { @NotNull @Digits(integer = 0, fraction = 3) private Double aDouble; @Past(message = "time必須在今天之后") private Date time; @Max(value = 5, message = "status不能大於5") @Min(value = 0, message = "status不能小於0") @NotNull(message = "status不能為null") private Integer status; @Size(min = 2, max = 5, message = "name長度必須在2~5之間") @NotBlank(message = "name不能為null") private String name; }
對象定義好了,下面看看怎么用吧。
校驗值:validator.validateValue
上面的代碼中,我們定義的了一個對象,並且在它的每個屬性上面添加了我們需要的校驗規則(注解)。現在說一個不需要實例化對象就可以測試這些規則的方法, 代碼如下:
//單獨校驗Class中的某個屬性和值 Set<ConstraintViolation<Demo>> result = validator.validateValue(Demo.class, "name", "hahahaha"); Iterator<ConstraintViolation<Demo>> iterator = result.iterator(); while (iterator.hasNext()) { ConstraintViolation<Demo> next = iterator.next(); //打印校驗結果 System.out.println(next.getMessage()); } //運行結果 name長度必須在2~5之間
校驗整個對象:validator.validate
這里是校驗這個對象的所有屬性
//待校驗對象 Demo demo = new Demo(); demo.setName("00000000"); demo.setADouble(200.001); demo.setStatus(200); //得到Validator實例 ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); Validator validator = factory.getValidator(); //開始校驗 Set<ConstraintViolation<Demo>> result = validator.validate(demo); Iterator<ConstraintViolation<Demo>> iterator = result.iterator(); while (iterator.hasNext()) { ConstraintViolation<Demo> next = iterator.next(); //打印校驗結果 System.out.println(next.getMessage()); } //運行結果 name不能為null 不能為null status不能為null
因為對象沒有設置任何值,所以校驗結果都是 “某某某字段不能為null”,現在我們給demo對象設置幾個值試一下
demo.setName("00000000"); demo.setADouble(200.001); demo.setStatus(200); //運行結果 數字的值超出了允許范圍(只允許在0位整數和3位小數范圍內) status不能大於5 name長度必須在2~5之間
這里是校驗整個對象的所有屬性,但是如果我們只想校驗一個對象里的部分屬性怎么辦呢?
校驗單個屬性 validator.validateProperty
這里是單獨校驗某一個對象其中的某幾個屬性,代碼如下
//第一個參數是要校驗的對象,后面的參數是要校驗的對象屬性名稱 Set<ConstraintViolation<Demo>> result = validator.validateProperty( demo, "status" ); //輸出結果 status不能大於5
對於方法的校驗
上面講的都是對象屬性的校驗,那么怎樣對一個方法的入參和出參進行校驗呢?這里分為 方法參數的校驗 和 返回值的校驗。下面我們先給Demo.java添加一個方法,並添加約束注解:
public class Demo { /** * 要校驗的方法 * * @param string * @return */ public @Size(min = 3, max = 10, message = "結果長度在3~10之間") String getString(@NotBlank String string) { return string; } }
校驗方法的返回值:executableValidator.validateReturnValue
//對於方法的校驗 ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); ExecutableValidator executableValidator = factory.getValidator().forExecutables(); //實例化對象 Demo object = new Demo(); //獲取對應的方法 Method method = Demo.class.getMethod("getString", String.class); //獲取它的返回值 Object returnValue = method.invoke(object, "這是方法的參數,要大於是個字"); Set<ConstraintViolation<Demo>> violations = executableValidator.validateReturnValue( object, method, returnValue ); //結果 Iterator<ConstraintViolation<Demo>> iterator = violations.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next().getMessage()); } //執行結果 結果長度在3~10之間
校驗方法的入參:executableValidator.validateParameters
//對於方法的校驗 ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); ExecutableValidator executableValidator = factory.getValidator().forExecutables(); //實例化對象 Demo object = new Demo(); //獲取對應的方法 Method method = Demo.class.getMethod("getString", String.class); //方法的入參 Object[] parameters = {null}; Set<ConstraintViolation<Demo>> violations = executableValidator.validateParameters( object, method, parameters ); //結果 Iterator<ConstraintViolation<Demo>> iterator = violations.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next().getMessage()); } //執行結果 不能為空