Hibernate-validator數據驗證

前言

  數據效驗工作在開發工作中,是非常重要的,保證數據的正確性,可靠性,安全性。不僅在前端進行效驗,還要在後臺繼續進行效驗。

  前端做驗證只是爲了用戶體驗,比如控制按鈕的顯示隱藏,單頁應用的路由跳轉等等。後端纔是最終的保障。總之,一切用戶的輸入都是不可信的

常見的驗證方式

  前端的校驗是必須的,這個很簡單,因爲客戶體驗。後臺的校驗更是必須的,關鍵在於如何與目前我們的分層思想(控制層、業務層、持久層)綜合起來考慮。

  在每層都要進行校驗嗎?還是隻在是某個特定層做就可以了? 是否有好的校驗框架(如前端的jquery校驗框架、springmvc校驗框架)?

  總之校驗框架還是有很多的,原理不就是對後端接收的數據進行特定規則的判斷,那我們怎麼制定規則,有怎麼去檢驗呢?

1、表現層驗證:SpringMVC提供對JSR-303的表現層驗證; 
2、業務邏輯層驗證:Spring3.1提供對業務邏輯層的方法驗證(當然方法驗證可以出現在其他層,但筆者覺得方法驗證應該驗證業務邏輯); 
3、DAO層驗證:Hibernate提供DAO層的模型數據的驗證(可參考hibernate validator參考文檔的7.3. ORM集成)。 
4、數據庫端的驗證:通過數據庫約束來進行; 
5、客戶端驗證支持:JSR-303也提供編程式驗證支持。

Hibernate-validator

  本章主要介紹一下hibernate-validator,下面就一起共同的去學習吧。

what?

注意:hibernate-validator 與 持久層框架 hibernate 沒有什麼關係,hibernate-validator 是 hibernate 組織下的一個開源項目

hibernate-validator 是 JSR 380(Bean Validation 2.0)JSR 303(Bean Validation 1.0)規範的實現。

JSR 380 - Bean Validation 2.0 定義了一個實體和方法驗證的元數據模型和 API。

JavaEE(改名爲:Jakarta EE)中制定了 validation 規範,即:javax.validation-api(現爲 jakarta.validation-api,jar 包的名字改變,包裏面的包名、類名未變,因此使用方式不變)包,

spring-boot-starter-webspring-boot-starter-webflux 包都已引入此依賴,直接使用即可。

有點類似於 slf4j 與 logback(log4j2)的關係,使用的時候,代碼中使用 javax.validate 提供的接口規範功能,加載的時候,根據 SPI 規範加載對應的規範實現類。

它和 hibernate 沒什麼關係,放心大膽的使用吧。

使用的註解

標識註解

1. @Vaild()

  標記用於驗證級聯的屬性、方法參數或方法返回類型。在驗證屬性、方法參數或方法返回類型時,將驗證在對象及其屬性上定義的約束。此行爲是遞歸應用的。

2.@Validated()

  spring 提供的擴展註解,可以方便的用於分組校驗.

約束註解

下面除了列出的參數,每個約束都有參數 message,groups 和 payload。這是 Bean Validation 規範的要求。

其中, message  是提示消息, groups  可以根據情況來分組。

以下每一個註解都可以在相同元素上定義多個。

3. @AssertFalse:  檢查元素是否爲 false,【支持數據類型:boolean、Boolean


4. @AssertTrue:  檢查元素是否爲 true,支持數據類型:boolean、Boolean


5. @DecimalMax(value=, inclusive=)支持數據類型:BigDecimal、BigInteger、CharSequence、(byte、short、int、long 和其封裝類)

  inclusive: boolean,默認 true,表示是否包含,是否等於。
  value 當 inclusive=false ,檢查帶註解的值是否小於指定的最大值。 當 inclusive=true 檢查該值是否小於或等於指定的最大值。參數值是根據 bigdecimal 字符串表示的最大值。


 6. @DecimalMin(value=, inclusive=):【支持數據類型:BigDecimal、BigInteger、CharSequence、(byte、short、int、long 和其封裝類)

  inclusive: boolean,默認 true,表示是否包含,是否等於
  value  當 inclusive=false 時,檢查帶註解的值是否大於指定的最大值。 當 inclusive=true 檢查該值是否大於或等於指定的最大值。參數值是根據 bigdecimal 字符串表示的最小值。


 7. @Digits(integer=, fraction=):【支持的數據類型: BigDecimal, BigInteger, CharSequence, byte, short, int, long 、原生類型的封裝類、任何 Number 子類。

  檢查值是否爲最多包含 integer 位整數 fraction 位小數的數字


 8. @Email ("regexp")【支持的數據類型:CharSequence

  檢查指定的字符序列是否爲有效的電子郵件地址。可選參數 regexp 和 flags 允許指定電子郵件必須匹配的附加正則表達式(包括正則表達式標誌)。


 9. @Max(value=):【支持的數據類型: BigDecimal, BigInteger, byte, short, int, long, 原生類型的封裝類, CharSequence 的任意子類(字符序列表示的數字), Number 的任意子類,

           javax.money.MonetaryAmount 的任意子類

  檢查值是否 小於或等於 指定的 最大值


 10. @Min(value=):【支持的數據類型: BigDecimal, BigInteger, byte, short, int, long, 原生類型的封裝類, CharSequence 的任意子類(字符序列表示的數字), Number 的任意子類,

            javax.money.MonetaryAmount 的任意子類

  檢查值是否 大於或等於 指定的 最大值


 11. @NotBlank:【支持數據類型:CharSequence

  檢查字符序列 是否爲空,以及去空格後的長度是否大於 0。  與@NotEmpty 的不同之處在於,此約束只能應用於字符序列,並且忽略尾隨空格。


 12. @NotNull:【支持數據類型:任何類型

  檢查值是否 null


 13. @NotEmpty:【支持數據類型:CharSequence, Collection, Map, arrays

  檢查元素是否爲 null 或 空


 14. @Size(min=, max=)和:@Length(min=, max=)【支持數據類型:CharSequence,Collection,Map, arrays

  檢查元素個數是否在  min(含)和 max(含)  之間


 15. @Negative:支持數據類型: BigDecimal, BigInteger, byte, short, int, long, 原生類型的封裝類, CharSequence 的任意子類(字符序列表示的數字), Number 的任意子類,

          javax.money.MonetaryAmount 的任意子類

  檢查元素是否 嚴格 爲負數零值被認爲無效。


 16. @NegativeOrZero:【支持數據類型:BigDecimal, BigInteger, byte, short, int, long, 原生類型的封裝類, CharSequence 的任意子類(字符序列表示的數字), Number 的任意子類,

             javax.money.MonetaryAmount 的任意子類

  檢查元素是否爲 負或零。


 17. @Positive:【支持數據類型: BigDecimal, BigInteger, byte, short, int, long, 原生類型的封裝類, CharSequence 的任意子類(字符序列表示的數字), Number 的任意子類,

         javax.money.MonetaryAmount 的任意子類

  檢查元素是否 嚴格 爲正。零值被視爲無效。


 18. @PositiveOrZero:【支持數據類型: BigDecimal, BigInteger, byte, short, int, long, 原生類型的封裝類, CharSequence 的任意子類(字符序列表示的數字), Number 的任意子類,

            javax.money.MonetaryAmount 的任意子類

  檢查元素是否 爲正或零


 19.@Null:【支持數據類型:任何類型

  檢查值是否爲 null


 20.@Future:【支持的數據類型:java.util.D

檢查日期是否在 未來。就是大於當前日期


21. @FutureOrPresent:【支持數據類型:同@Future】

  檢查日期是現在或將來,大於等於當前日期


22. @Past:【支持數據類型:同@Future】

  檢查日期是否在過去,小於當前日期


23.@PastOrPresent:【支持數據類型:同@Future】

  檢查日期是否在過去或現在,小於等於當前日期


24. @Pattern(regex=, flags=):【支持數據類型:CharSequence】

  根據給定的 flag 匹配,檢查字符串是否與正則表達式 regex 匹配


25. @CreditCardNumber:【支持數據類型:String】
  校驗信用卡號碼


 26. @NotEmptyPattern(regex=):【支持數據類型:String】

  在字符串不爲空的情況下,驗證是否匹配正則表達式


 27. @ListStringPattern(regex=):【支持數據類型:List<String>】

  驗證集合中的字符串是否滿足正則表達式


 28. @DateValidator(regex=):【支持數據類型:String】

  驗證日期格式是否滿足正則表達式,Local爲ENGLISH


 29. @DateFormatCheckPattern(regex=):【支持數據類型:String】

  驗證日期格式是否滿足正則表達式,Local爲自己手動指定


 Hibernate-validator的使用

 一、導入maven依賴

 <dependency> 

      <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.2.0.Final</version> </dependency> 

 二、通用的效驗工具

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.wj.exception.ParamException;
import org.apache.commons.collections.MapUtils;
import javax.validation.*;
import javax.validation.groups.Default;
import java.util.*;

public class BeanValidator {
    private static Validator validator=null;
    //獲取Validator對象
    static{
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        validator = validatorFactory.getValidator();
    }

    /**
     * 通過參數,判斷是那種效驗:對象  集合
     * @param obj  效驗的bean
     * @param objects 效驗的集合
     * @return
     */
    public static Map<String,String> validate(Object obj, Object... objects){
        if (objects != null && objects.length > 0){
            return validateList(Lists.asList(obj, objects));
        }else {
            return validateObject(obj, new Class[0]);
        }
    }

    /**
     * 對象數據效驗
     * 使用指定分組
     * @param t 被效驗的bean
     * @param groups 分組
     * @param <T>
     * @return 返回錯誤信息
     */
    public static <T>Map<String,String> validateObject(T t, Class... groups){
        //如果分組爲空,使用默認的分組
        if (groups == null){
            groups = new Class[]{Default.class};
        }
        //獲取實體類驗證後的信息,存放在Set集合。
        //ConstraintViolation類封裝着實體類的每個屬性的效驗之後的信息
        Set<ConstraintViolation<T>> validateResult = validator.validate(t, groups);
        if (validateResult.isEmpty()){
            //如果屬性都符合要求,沒有錯誤信息,返回一個空集合
            return Collections.emptyMap();
        }else {
            HashMap errors = Maps.newHashMap();
            //遍歷集合
            Iterator iterator = validateResult.iterator();
            while (iterator.hasNext()){
                ConstraintViolation violation = (ConstraintViolation) iterator.next();
                //將每個屬性的錯誤信息,添加到HashMap集合中
                errors.put(violation.getPropertyPath().toString(), violation.getMessage());
            }
            return errors;
        }
    }

    /**
     * 檢查集合中的bean
     * @param collection 被效驗的集合
     * @return
     */
    public static Map<String, String> validateList(Collection<?> collection){
        //檢查集合是否爲空
        Preconditions.checkNotNull(collection);
        Map errors = null;
        Iterator iterator = collection.iterator();
        //當集合中沒有數據,返回空集合
        if (!iterator.hasNext()){
            return Collections.emptyMap();
        }
        //遍歷集合
        while (iterator.hasNext()){
            Object object = iterator.next();
            //Collection集合中每個對象的效驗信息 賦值給Map
            errors = validate(object, new Class[0]);
        }
        return errors;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章