日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

[数据校验/数据质量] 数据校验框架:hibernate-validation

發(fā)布時(shí)間:2023/11/16 windows 49 coder
生活随笔 收集整理的這篇文章主要介紹了 [数据校验/数据质量] 数据校验框架:hibernate-validation 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

0 前言

  • 其一,項(xiàng)目中普遍遇到了此問題,故近兩天深入地研究了一下。
  • 其二,能夠自信地說,仔細(xì)看完本篇,就無需再看其他的Java數(shù)據(jù)校驗(yàn)框架的文章了。

1 數(shù)據(jù)校驗(yàn)框架概述

1.0 數(shù)據(jù)校驗(yàn)框架的產(chǎn)生背景

以Web項(xiàng)目為例,用戶需要填寫表單信息保存提交。
頁面輸入信息需要進(jìn)行數(shù)據(jù)格式校驗(yàn),并且返回對(duì)應(yīng)的錯(cuò)誤提示,以此來達(dá)到數(shù)據(jù)校驗(yàn)的目的,從而避免無效數(shù)據(jù)被保存或者提交。
這些檢查工作包括必填項(xiàng)檢查、數(shù)值檢查、長(zhǎng)度檢查、身份證號(hào)碼、手機(jī)號(hào)碼檢查等工作。

當(dāng)請(qǐng)求參數(shù)格式不正確的時(shí)候,需要程序監(jiān)測(cè)到,對(duì)于前后端分離開發(fā)過程中,數(shù)據(jù)校驗(yàn)還需要返回對(duì)應(yīng)的狀態(tài)碼和錯(cuò)誤提示信息。

如果將這些字段校驗(yàn)和業(yè)務(wù)邏輯混合一起寫,則會(huì):

  • 代碼極其臃腫,且不容易維護(hù);
  • 干擾原有邏輯;

接下來將細(xì)述在服務(wù)器端,如何對(duì)API的數(shù)據(jù)校驗(yàn)處理技術(shù)。

1.1 數(shù)據(jù)校驗(yàn)框架的演變過程

1.1.1 JSR/Java 規(guī)范提案:BeanValidation

  • JSR:Java Specification Requests的縮寫,意思是Java 規(guī)范提案。是指向JCP(Java Community Process) 提出新增一個(gè)標(biāo)準(zhǔn)化技術(shù)規(guī)范的正式請(qǐng)求。

  • 任何人都可以提交JSR,以向Java平臺(tái)增添新的API和服務(wù)。JSR已成為Java界的一個(gè)重要標(biāo)準(zhǔn)

  • Bean Validation 是一個(gè)運(yùn)行時(shí)的數(shù)據(jù)驗(yàn)證框架的標(biāo)準(zhǔn),在驗(yàn)證之后驗(yàn)證的錯(cuò)誤信息會(huì)被馬上返回。

    • BeanValidation就是這個(gè)JSR規(guī)范之一。
    • 提到JSR,相信有小伙伴想去看下到底是個(gè)啥。可以看到:
      • 規(guī)范從JSR 303JSR 380
      • 目前最新規(guī)范是Bean Validation 2.0
    • JSR # Bean Validation : https://jcp.org/en/jsr/summary?id=bean+validation

  • JSR303是專家組成員向JCP提交的第1版Bean Validation,即針對(duì)bean數(shù)據(jù)校驗(yàn)提出的一個(gè)規(guī)范,使用注解方式實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)。后面有升級(jí)版本JSR349JSR380。各個(gè)版本的規(guī)范對(duì)應(yīng)關(guān)系如下:
    • JSR 380(Bean Validation 2.0)
      • JSR380伴隨著JAVAEE 8在2017年發(fā)布,完全兼容低版本的JAVA SE,Hibernate實(shí)現(xiàn)版本6.0.1.Final,Apache BVal實(shí)現(xiàn)版本2.0.3(不太確定)
    • JSR 349(Bean Validation 1.1)
      • JSR349伴隨著JAVAEE 7在2013年發(fā)布,Hibernate實(shí)現(xiàn)版本5.1.1.Final,Apache BVal實(shí)現(xiàn)版本1.1.2
      • 每一個(gè)注解都包含message字段,用于校驗(yàn)失敗時(shí)作為提示信息,特殊的校驗(yàn)注解,如Pattern(正則校驗(yàn)),還可以自己添加正則表達(dá)式。
    • JSR 303(Bean Validation 1.0)
      -JSR303伴隨著JAVAEE 6在2009年發(fā)布,Hibernate實(shí)現(xiàn)版本4.3.1.Final,Apache BVal實(shí)現(xiàn)版本0.5

  • 主流 Bean Validation 規(guī)范,使用 hibernate-validation 的實(shí)現(xiàn)。
    • 如果使用 bean validation 2.0 規(guī)范,hibernate-validation 必須選擇6.0.1以上版本

Bean Validation 2.0中包含了22個(gè)注解

  • JSR / Bean Valiadation 與 Hibernate Validation、Spring Valiadation
    • JSR規(guī)定一些校驗(yàn)規(guī)范即校驗(yàn)注解,如@Null,@NotNull,@Pattern,位于javax.validation.constraints包下,只提供規(guī)范不提供實(shí)現(xiàn)。
    • 而hibernate validation是對(duì)這個(gè)規(guī)范的實(shí)踐,提供相應(yīng)的實(shí)現(xiàn),并增加一些其他校驗(yàn)注解,如@Email,@Length,@Range等等,位于org.hibernate.validator.constraints包下。
    • spring對(duì)hibernate validation進(jìn)行二次封裝,顯示校驗(yàn)validated bean時(shí),可以使用spring validation或hibernate validation;
      • 而spring validation另一特性:便是其在springmvc模塊中添加自動(dòng)校驗(yàn),并將校驗(yàn)信息封裝進(jìn)特定的類中。

1.1.2 JAVAX.VALIDATION.API

  • Java 在2009年的 JAVAEE 6 中發(fā)布了 JSR303以及 javax 下的 validation 包內(nèi)容。
<dependency>  
    <groupId>javax.validation</groupId>  
    <artifactId>validation-api</artifactId>  
    <version>${javax.validation-api.version}</version>  
</dependency>

重要版本
javax.validation:validation-api.version = 2.0.1.Final

spring-boot-starter-web/validation:2.1.4.RELEASE | hibernate-alidation:6.0.16.Final 中使用的 validation-api 為:

javax.validation:validation-api:2.0.1.Final

hibernate-alidation:6.0.16.Final 中使用的 validation-api 為:

javax.validation:validation-api:2.0.1.Final

  • 這項(xiàng)工作的【主要目標(biāo)】是為java應(yīng)用程序開發(fā)人員提供 :
    • 基于java對(duì)象的 約束(constraints)聲明
      • 注:每個(gè)約束都有參數(shù) message,groups 和 payload。這是 Bean Validation 規(guī)范的要求。
    • 對(duì)約束的驗(yàn)證工具(validator)
    • 約束元數(shù)據(jù)存儲(chǔ)庫查詢API
    • 默認(rèn)實(shí)現(xiàn)
  • Java8開始,Java EE 改名為Jakarta EE
    • javax.validation相關(guān)的api在jakarta.validation的包下。因此:
      • 大家看不同的版本的時(shí)候,會(huì)發(fā)現(xiàn)以前的版本包javax.validation包下。
      • 最新的版本包在jakarta.validation 包下
    • javase的支持還在jcp(Java Community Process,Java社區(qū)標(biāo)準(zhǔn)過程),Java EE 改名 JakartaE E。
      • JakartaEE的官網(wǎng)及其支持的項(xiàng)目:
        • https://jakarta.ee/

<dependency>  
    <groupId>jakarta.validation</groupId>  
    <artifactId>jakarta.validation-api</artifactId>  
    <version>${jakarta.validation-api.version}</version>  
</dependency>

重要版本
jakarta.validation:jakarta.validation-api.version = 2.0.2

spring-boot-starter-validation:2.3.12.RELEASE | hibernate-alidation:6.1.7.Final 使用的 validation-api 為:

jakarta.validation:jakarta.validation-api:2.0.2

  • Bean Validation 2.0規(guī)范默認(rèn)實(shí)現(xiàn)
    • https://beanvalidation.org/2.0/spec/#whatsnew

1.1.3 HIBERNATE-VALIDATOR

  • hibernate-validator是Hibernate項(xiàng)目中的一個(gè)數(shù)據(jù)校驗(yàn)框架,是Bean Validation參考實(shí)現(xiàn)
    • 【注意】
      • 此處的 Hibernate 不是 Hibernate ORM,二者沒有任何關(guān)系;
      • hibernate-validator 和 hibernate orm 項(xiàng)目 均是 Hibernate 基金會(huì)(org.hibernate)下的項(xiàng)目之一。
  • hibernate-validator除了提供了JSR 303規(guī)范所有內(nèi)置constraint 的實(shí)現(xiàn),還有一些附加的constraint
  • 使用hibernate-validator能夠?qū)?strong>數(shù)據(jù)校驗(yàn)從業(yè)務(wù)代碼中脫離出來,增加代碼可讀性;同時(shí)也讓數(shù)據(jù)校驗(yàn)變得更加方便、簡(jiǎn)單。
  • 項(xiàng)目官網(wǎng):
    • https://hibernate.org/validator/ |
      • 項(xiàng)目官網(wǎng)
    • http://hibernate.org/validator/documentation
      • 官方文檔
    • https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/
      • hibernate-validator的簡(jiǎn)介
    • https://github.com/hibernate/hibernate-validator
      • GitHub 源代碼倉庫
  • 在Java語言中,hibernate-validation已成為【數(shù)據(jù)校驗(yàn)框架】實(shí)質(zhì)上的標(biāo)準(zhǔn)框架標(biāo)準(zhǔn)實(shí)現(xiàn),再無其他框架可望其項(xiàng)背。

spring-boot-starter-web/validation:2.1.4.RELEASE | hibernate-alidation:6.0.16.Final

hibernate-alidation:6.0.16.Final

spring-boot-starter-validation:2.3.12.RELEASE | hibernate-alidation:6.1.7.Final

2 實(shí)踐使用

2.1 基本使用步驟

Step1 編寫實(shí)體類

import lombok.AllArgsConstructor;  
import lombok.Data;  
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotBlank;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
 
    @NotBlank(message = "用戶名不能為空")
    private String name;
 
    @NotBlank(message = "郵箱不能為空")
    private String email;
}

Step2 引入依賴包(數(shù)據(jù)校驗(yàn)的標(biāo)準(zhǔn)框架及實(shí)現(xiàn))

情況1:基于 javax.validation api

基于 javax.validation api 的第三方庫的有:
[1] javax.validation:validation-api : 2.0.1.Final

  • [1] hibernate-alidation : 6.0.16.Final
  • [2] spring-boot-starter-web/validation : 2.1.4.RELEASE
    注:本組件依賴的 hibernate-validation 的組件版本為 6.0.16.Final
<!-- | data validation framework | start -->

<!-- javax.validation-api : data validation api design standard & framework -->
<dependency>  
    <groupId>javax.validation</groupId>  
    <artifactId>validation-api</artifactId>  
    <version>${javax.validation-api.version}</version>  
</dependency>
  
<!-- hibernate-validator | http://hibernate.org/validator/documentation-->  
<dependency>  
    <groupId>org.hibernate</groupId>  
    <artifactId>hibernate-validator</artifactId>  
    <version>${hibernate-validator.version}</version>  
</dependency>

<!-- org.glassfish:javax.el | hibernate-validator 依賴此組件,以防報(bào)錯(cuò):"javax.validation.ValidationException: HV000183: Unable to initialize 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead" --><dependency>  
    <groupId>org.glassfish</groupId>  
    <artifactId>javax.el</artifactId>  
    <version>${glassfish.javax.el.version}</version>  
</dependency>

<!-- | data validation framework | end -->
  • 版本變量取值
    • javax.validation-api.version = 2.0.1.Final
    • hibernate-validator.version = 6.0.16.Final
    • glassfish.javax.el.version = 3.0.1-b09

情況2:基于 jakarta.validation api

基于 jakarta.validation api 的第三方庫的有:
[1] jakarta.validation : jakarta.validation-api : 2.0.2

  • [1] hibernate-alidation : 6.1.7.Final
  • [2] spring-boot-starter-validation : 2.3.12.RELEASE
    注:本組件依賴的 hibernate-validation 的組件版本為 6.1.7.Final

方式1

<!-- | data validation framework | start -->
<!-- jakarta.validation-api : data validation api design standard & framework -->
<dependency>  
    <groupId>jakarta.validation</groupId>  
    <artifactId>jakarta.validation-api</artifactId>  
    <version>${jakarta.validation-api.version}</version>  
</dependency>
  
<!-- hibernate-validator | http://hibernate.org/validator/documentation -->
<dependency>  
    <groupId>org.hibernate</groupId>  
    <artifactId>hibernate-validator</artifactId>  
    <version>${hibernate-validator.version}</version>  
</dependency>

<!-- org.glassfish:javax.el or org.glassfish:jakarta.el [recommend] (2選1即可) | hibernate-validator 依賴此組件,以防報(bào)錯(cuò):"javax.validation.ValidationException: HV000183: Unable to initialize 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead" -->
<!--
<dependency>  
    <groupId>org.glassfish</groupId>  
    <artifactId>javax.el</artifactId>  
    <version>${glassfish.javax.el.version}</version>  
</dependency> -->
<dependency>  
  <groupId>org.glassfish</groupId>  
  <artifactId>jakarta.el</artifactId>  
  <version>${glassfish.jakarta.el.version}</version>  
</dependency>

<!-- | data validation framework | end -->
  • 版本變量取值
    • jakarta.validation-api.version = 2.0.2
    • hibernate-validator.version = 6.1.7.Final
    • glassfish.javax.el.version = 3.0.1-b09 | glassfish.jakarta.el.version = 3.0.3

方式2:直接引用 spring-boot-starter-validation

<!-- | data validation framework | start -->
<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-validation</artifactId>  
    <version>${spring-boot.version}</version>  
</dependency>
<!-- | data validation framework | end -->

版本變量的取值

spring-boot.version := 2.3.12.RELEASE

由上可見:
[1] spring-boot-starter-validation : 2.3.12.RELEASE
依賴 hibernate-validation : 6.1.7.Final
依賴 org.glasssfish : jakarta.el : 3.0.3

由上可見:
[1] hibernate-validation : 6.1.7.Final
依賴了 org.glasssfish : jakarta.el (由于scopeprovided,故具體版本未限制)

Step3 編寫數(shù)據(jù)驗(yàn)證代碼

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

//import org.hibernate.validator.HibernateValidator;

import java.util.Set;

public class Test {

	public static void main(String[] args) {  
	    Student student = new Student("小明", null);  
	    System.out.println(student);  
		
		//方式1
	    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();  
		
		//方式2
	    //ValidatorFactory factory = Validation.byProvider( HibernateValidator.class ).configure()  
	    //.addProperty( "hibernate.validator.fail_fast", "true" ) //true 快速失敗返回模式 | false 普通模式  
	    //.buildValidatorFactory();  
	  
	    Validator validator = factory.getValidator();  
	    Set<ConstraintViolation<Student>> violations = validator.validate(student);  
	    for (ConstraintViolation<Student> violation : violations) {  
	        System.out.println(violation.getMessage());  
	    }  
	}
}

output

Student(name=小明, email=null)
十一月 10, 2023 12:56:58 下午 org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 6.0.16.Final
郵箱不能為空

2.2 支持的POJO校驗(yàn)注解

2.2.1 javax/jakarta.validation 注解列表

在要校驗(yàn)的POJO上加上以下注解即可:

  • 形如:
    • javax.validation.constraints.Email
注解 用途
Valid (最常用的【標(biāo)識(shí)注解】) 遞歸的對(duì)關(guān)聯(lián)的對(duì)象進(jìn)行校驗(yàn)
標(biāo)記用于驗(yàn)證級(jí)聯(lián)的屬性、方法參數(shù)或方法返回類型;在驗(yàn)證屬性、方法參數(shù)或方法返回類型時(shí),將驗(yàn)證在對(duì)象及其屬性上定義的約束。此行為是遞歸應(yīng)用的。
AssertFalse 用于boolean字段,該字段的值只能為false
AssertTrue 用于boolean字段,該字段只能為true
DecimalMax(value) 被注釋的元素必須是一個(gè)數(shù)字,只能大于或等于該值
DecimalMin(value) 被注釋的元素必須是一個(gè)數(shù)字,只能小于或等于該值
Digits(integer,fraction) 檢查是否是一種數(shù)字的(整數(shù),小數(shù))的位數(shù)
Future 檢查該字段的日期是否是屬于將來的日期
FutureOrPresent 判斷日期是否是將來或現(xiàn)在日期
Past 檢查該字段的日期是在過去
PastOrPresent 判斷日期是否是過去或現(xiàn)在日期
Max(value) 該字段的值只能小于或等于該值
Min(value) 該字段的值只能大于或等于該值
Negative 判斷負(fù)數(shù)
NegativeOrZero 判斷負(fù)數(shù)或0
Positive 判斷正數(shù)
PositiveOrZero 判斷正數(shù)或0
NotNull 不能為null
Null 必須為 null
Pattern(value)
@Pattern(regexp = )
被注釋的元素必須符合指定的正則表達(dá)式
Size(max, min) 檢查該字段的size是否在min和max之間,可以是字符串、數(shù)組、集合、Map等
Length(max, min) 判斷字符串長(zhǎng)度
CreditCardNumber 被注釋的字符串必須通過Luhn校驗(yàn)算法,銀行卡,信用卡等號(hào)碼一般都用Luhn計(jì)算合法性
Email 被注釋的元素必須是電子郵箱地址
Length(min=, max=) 被注釋的字符串的大小必須在指定的范圍內(nèi)
NotBlank 只能用于字符串不為null,并且字符串trim()以后length要大于0
NotEmpty 集合對(duì)象的元素不為0,即集合不為空,也可以用于字符串不為null
Range(min=, max=) 被注釋的元素必須在合適的范圍內(nèi)
SafeHtml classpath中要有jsoup包
ScriptAssert 要有Java Scripting API 即JSR 223("Scripting for the JavaTMPlatform")的實(shí)現(xiàn)
URL(protocol=,host=,port=,regexp=,flags=) 被注釋的字符串必須是一個(gè)有效的url
  • 注意
    • @NotEmpty 用在集合類上面
    • @NotBlank 用在String上面
    • @NotNull 用在基本類型上

更多功能,如:自定義校驗(yàn)規(guī)則、分組校驗(yàn)、關(guān)聯(lián)參數(shù)聯(lián)合校驗(yàn)請(qǐng)查看官網(wǎng)文檔。

2.2.2 springframework.validation 注解列表

  • @Validated(spring) | 最常用的【標(biāo)識(shí)注解】
    • 包路徑:
      • org.springframework.validation.annotation.Validated
    • spring 提供的擴(kuò)展注解,可以方便的用于分組校驗(yàn)
    • 其中,message 是提示消息,groups 可以根據(jù)情況來分組。

2.2.3 樣例

public class ParamTestDTO implements Serializable {

    private static final long serialVersionUID = 7123882542534668217L;

    @AssertTrue(message = "Error True")
    private Boolean testTrue;

    @AssertFalse(message = "Error False")
    private Boolean testFalse;

    @DecimalMax(value = "10", message = "Error StrMax")
    private String testStrMax;

    @DecimalMin(value = "1", message = "Error StrMin")
    private String testStrMin;

    @Max(value = 10, message = "Error Max")
    private Integer testMax;

    @Min(value = 1, message = "Error Min")
    private Double testMin;

    @Digits(integer = 2, fraction = 3, message = "Error Dig")
    private BigDecimal testDig;

    @Past(message = "Error Past")
    private Date testPast;

    @Future(message = "Error Future")
    private Date testFuture;

    @Null(message = "Error Null")
    private String testNull;

    @NotNull(message = "Error NonNull")
    private String testNonNull;

    @Pattern(regexp = "^[0-9]?[0-9]$", message = "Error Pattern")
    private String testPattern;

    @Size(min = 1, max = 10, message = "Error Size")
    private List<String> testSize;

    @Length(min = 1, max = 10, message = "Error Length")
    private String testLength;

    @NotBlank(message = "Error Blank")
    private String testBlank;

    @NotEmpty(message = "Error NotEmpty")
    private String testEmpty;

    @Range(min = 1, max = 10, message = "Error Range")
    private String testRange;
}

2.3 應(yīng)用場(chǎng)景

<dubbo:reference id="xxxService" interface="xxx.ValidationService" validation="true" />
  • 在服務(wù)器端驗(yàn)證參數(shù)
<dubbo:service interface="xxx.ValidationService" ref="xxxService" validation="true" />
  • 在代碼里校驗(yàn)入?yún)?/li>
//obj為包含Hibernate Validator注解的POJO
//快速失敗模式
ValidResult validResult = ValidationUtil.fastFailValidate(obj);
//obj為包含Hibernate Validator注解的POJO
//全部校驗(yàn)?zāi)J?ValidResult validResult = ValidationUtil.allCheckValidate(obj);

2.3.2 場(chǎng)景:Web POST Api Controller

@RestController
public class StudentController {
	 // ...
	 
    @RequestMapping(value = "/addStudent",method = RequestMethod.POST)
    public String addStudent(@Valid @RequestBody Student student){
        System.out.println("student = [" + student + "]");
        return "ok";
    }
	
	// ...
	
}
  • 注意
    • POST請(qǐng)求必須要加@Valid
      • @Valid注解:遞歸的對(duì)關(guān)聯(lián)的對(duì)象進(jìn)行校驗(yàn)
    • 區(qū)分請(qǐng)求參數(shù):@RequestBody 和 @RequestParam
      • @RequestBody 獲取的是請(qǐng)求體里面的數(shù)據(jù),一般是前端傳給后端的JSON字符串。
      • @RequestParam 接收的是url里面的查詢參數(shù)(比如xxxxxxx?name=admin)

2.3.3 場(chǎng)景:Web GET Api Controller

import org.springframework.validation.annotation.Validated;

@RestController
@Validated
public class StudentController {
	 //...
	 
    @RequestMapping(value = "/addStudent1",method = RequestMethod.GET)
    public String addStudent1(@NotBlank(message = "name不能為空") String name){
        System.out.println("name = [" + name + "]");
        return "ok addStudent1";
    }
    
	//...
}
  • Get請(qǐng)求需要在類上添加 @Validated
    • org.springframework.validation.annotation.Validated

2.3.4 場(chǎng)景:優(yōu)雅地返回校驗(yàn)信息

2.3.4.1 定義全局異常處理

@ControllerAdvice
public class GlobalExceptionHandler {
 
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResultEntity handleBindException(MethodArgumentNotValidException ex) {
        FieldError fieldError = ex.getBindingResult().getFieldError();
        // 記錄日志。。。
        return ResultEntity.faill(211,fieldError.getDefaultMessage(),null);
    }
    
}

2.3.4.2 定義校驗(yàn)失敗返回模板

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultEntity<T> {
 
    private Integer code;
 
    private String message;
 
    private T data;
 
    public  static <T> ResultEntity<T> faill(Integer code,String msg,T t){
        return new ResultEntity<T>(code,msg,t);
    }
}

2.3.5 場(chǎng)景:對(duì)象級(jí)聯(lián)校驗(yàn)

  • Student
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
 
    @NotBlank(message = "用戶名不能為空")
    private String name;
 
    @Max(150)
    @Min(10)
    @NotNull(message = "年齡不能為空")
    private Integer age;
 
    @Email
    private String email;
 
    @NotNull(message = "user不能為空")
    @Valid
    private User user;
}
  • User
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
 
    private Integer id;
 
    @NotNull(message = "user對(duì)象中的username不能為空")
    private String username;
    
}

2.3.6 場(chǎng)景:分組校驗(yàn)

如果同一個(gè)類,在不同的使用場(chǎng)景下有不同的校驗(yàn)規(guī)則,那么可以使用分組校驗(yàn)。實(shí)際需求,如未成年人是不能喝酒,如何校驗(yàn)?

public class Foo {
   @Min(value = 18, groups = {Adult.class})
   private Integer age;
   public interface Adult { }
   public interface Minor { }
}
@RequestMapping("/drink")
public String drink(@Validated({Foo.Adult.class}) Foo foo, BindingResult bindingResult) {
	if (bindingResult.hasErrors()) {
		for (FieldError item : bindingResult.getFieldErrors()) {
		}
		return "fail";
	}
	return "success";
}

2.3.7 場(chǎng)景:自定義校驗(yàn)

作為示例,自定義校驗(yàn)注解@CannotHaveBlank,實(shí)現(xiàn)字符串不能包含空格的校驗(yàn)限制:

  • 注解 CannotHaveBlank
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
// 自定義注解中指定這個(gè)注解真正的驗(yàn)證者類
@Constraint(validatedBy = {CannotHaveBlankValidator.class})
public @interface CannotHaveBlank {
   // 默認(rèn)錯(cuò)誤消息
   String message() default "不能包含空格";
   // 分組
   Class<?>[] groups() default {};
   // 負(fù)載
   Class<? extends Payload>[] payload() default {};
   // 指定多個(gè)時(shí)使用
   @Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
   @Retention(RUNTIME)
   @Documented
   @interface List {
       CannotHaveBlank[] value();
   }
}
  • 接口 ConstraintValidator
public interface ConstraintValidator<A extends Annotation, T> {
	void initialize(A constraintAnnotation);// 初始化事件方法
	boolean isValid(T value, ConstraintValidatorContext context);// 判斷是否合法
}
  • 實(shí)現(xiàn)ConstraintValidator接口完成定制校驗(yàn)邏輯的類 : CannotHaveBlankValidator
// 所有的驗(yàn)證者都需要實(shí)現(xiàn)ConstraintValidator接口
public class CannotHaveBlankValidator implements ConstraintValidator<CannotHaveBlank, String> {
	@Override
	public void initialize(CannotHaveBlank constraintAnnotation) {
		//...
	}
	
	@Override
	// ConstraintValidatorContext包含認(rèn)證中所有的信息,
	// 獲取默認(rèn)錯(cuò)誤提示信息,禁用錯(cuò)誤提示信息,改寫錯(cuò)誤提示信息等操作。
	public boolean isValid(String value, ConstraintValidatorContext context) {
	    if (value != null && value.contains(" ")) {
	        //獲取默認(rèn)提示信息
	        String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
	        System.out.println("default message :" + defaultConstraintMessageTemplate);
	        //禁用默認(rèn)提示信息
	        context.disableDefaultConstraintViolation();
	        //設(shè)置提示語
	        context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
	        return false;
	    }
	    return true;
	}
}

2.3.8 場(chǎng)景:統(tǒng)一格式化輸出

在驗(yàn)證數(shù)據(jù)時(shí),常常需要給用戶告知錯(cuò)誤信息。通常情況下,錯(cuò)誤信息都是非常簡(jiǎn)短的。為了更好的告知用戶錯(cuò)誤信息,validation-api提供了一種非常好的機(jī)制來格式化錯(cuò)誤信息。

以一個(gè)使用validation-api對(duì)錯(cuò)誤信息進(jìn)行格式化為例子:

public static  String validateAndFormat(T obj) {
    Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
    Set> constraintViolationSet = validator.validate(obj);
    if (constraintViolationSet != null && constraintViolationSet.size() > 0) {
        StringBuilder sb = new StringBuilder();
        for (ConstraintViolation constraintViolation : constraintViolationSet) {
            sb.append(constraintViolation.getPropertyPath()).append(":").append(constraintViolation.getMessage()).append(",");
        }
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();
    } else {
        return "";
    }
}

首先使用validator.validate(obj)方法對(duì)數(shù)據(jù)進(jìn)行驗(yàn)證;
如果有錯(cuò)誤信息,則用StringBuilder將錯(cuò)誤信息格式化后返回。

2.4.1 普通模式

默認(rèn)模式

  • 首先,校驗(yàn)完所有的屬性;
  • 然后,返回所有的驗(yàn)證失敗信息。

2.4.2 快速失敗返回模式

只要有一個(gè)失敗就立馬返回

  • 開啟快速失敗返回模式
@Configuration
public class HibernateValidatorConfiguration {
    @Bean
    public Validator validator(){
        ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
                .configure()
                // true  快速失敗返回模式    false 普通模式
                .addProperty( "hibernate.validator.fail_fast", "true" )
                .buildValidatorFactory();
        Validator validator = validatorFactory.getValidator();
        return validator;
    }
}

測(cè)試驗(yàn)證不通過就會(huì)拋出 ConstraintViolationException 異常,和之前普通模式下拋出的異常不一樣。
所以,為了格式統(tǒng)一還需要自定義的異常處理

2.4.3 全局異常處理

    // 開啟快速失敗返回模式,GET請(qǐng)求校驗(yàn)不通過會(huì)拋出如下異常,在這對(duì)它處理
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public ResultEntity handle(ValidationException exception) {
        if (exception instanceof ConstraintViolationException) {
            ConstraintViolationException exs = (ConstraintViolationException) exception;
 
            Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
            for (ConstraintViolation<?> item : violations) {
                System.out.println(item.getMessage());
                return ResultEntity.faill(212, item.getMessage(), null);
            }
        }
        return ResultEntity.faill(212, "abc", null);
    }

X 參考與推薦文獻(xiàn)

  • JSR # Bean Validation :
    • https://jcp.org/en/jsr/summary?id=bean+validation
    • https://github.com/beanvalidation/beanvalidation-api
  • Jakarta (Java EE)
    • https://jakarta.ee/
    • https://search.maven.org/artifact/jakarta.validation/jakarta.validation-api
  • 項(xiàng)目官網(wǎng):
    • https://hibernate.org/validator/ 【推薦】
      • 項(xiàng)目官網(wǎng)
    • http://hibernate.org/validator/documentation 【推薦】
      • 官方文檔
    • https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/
      • hibernate-validator的簡(jiǎn)介
    • https://github.com/hibernate/hibernate-validator
      • GitHub 源代碼倉庫
  • Hibernate-Validator(數(shù)據(jù)校驗(yàn)框架) - CSDN
  • Hibernate Validator—更簡(jiǎn)潔的參數(shù)校驗(yàn)及一個(gè)util - segmentfault
  • Hibernate validation "Unable to initialize javax.el.ExpressionFactory" error - *
  • SPRINGBOOT項(xiàng)目后端表單驗(yàn)證(JAVAX.VALIDATION.API與HIBERNATE-VALIDATOR) - 灰信網(wǎng) 【推薦】
    • 在springboot項(xiàng)目中,結(jié)合springAOP和AspectJ,實(shí)現(xiàn)通過自定義注解(@BeanValidation) + 自定義注解處理方法(Object validateParamByAnnotation(ProceedingJoinPoint ponit, BeanValidation beanValidation))的方式進(jìn)行數(shù)據(jù)格式驗(yàn)證。
  • 數(shù)據(jù)校驗(yàn)validation - CSDN
  • 【深度思考】如何優(yōu)雅的校驗(yàn)參數(shù)? - Zhihu

總結(jié)

以上是生活随笔為你收集整理的[数据校验/数据质量] 数据校验框架:hibernate-validation的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。