詳解Spring中@Valid和@Validated注解用法
案例引入
下面我們以新增一個員工為功能切入點,以常規(guī)寫法為背景,慢慢烘托出 @Valid 和 @Validated 注解用法詳解。
那么,首先,我們會有一個員工對象 Employee,如下 :
/** * 員工對象 * * @author sunnyzyq * @since 2019/12/13 */ public class Employee { /** 姓名 */ public String name; /** 年齡 */ public Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
然后 Cotroller 中會有一個對應(yīng)都新增方法 add(),如下:
@Controller public class TestController { @RequestMapping("/add") @ResponseBody public String add(Employee employee) { // TODO 保存到數(shù)據(jù)庫 return "新增員工成功"; } }
現(xiàn)在要求:員工的名稱不能為空,且長度不能超過10個字符,那么我們以前的做法大致如下:
寫完,我們啟動項目測試下:
(1)名稱為空情況
(2)正常情況
(3)超過長度情況
可以看到,和我們料想中的一樣,毫無問題。
除了名稱外,我們規(guī)定年齡也是必填項,且范圍在1到100歲,那么此時,我們需要增加對應(yīng)判定代碼如下:
那么問題來了,現(xiàn)在員工對象 Employee 就 2 個字段,我們就寫了 10 多行的代碼驗證,要是有20個字段,豈不是要寫 100 多行代碼?通常來說,當(dāng)一個方法中的無效業(yè)務(wù)代碼量過多時,往往代碼設(shè)計有問題,當(dāng)然這不是我們所想看到都結(jié)果。
那么如何解決呢?首先大家應(yīng)該會想到將對應(yīng)的驗證過程抽成一個驗證方法,如下:
這樣來看,我們的業(yè)務(wù)方法就清爽多了。
但這種方式只是抽了一個方法,有一種換湯不換藥的感覺,雖然業(yè)務(wù)方法看起來清爽了很多,但書寫代碼量并沒有下降,反而還多出了一個方法,這也不是我們理想中的樣子。
@Valid 詳解
此時,我們引出 Spring 中的 @valid 注解,這些問題就可以迎刃而解了,具體如下:
首先,我們在 Maven 配置中引入 @valid 的依賴:
如果你是 springboot 項目,那么可以不用引入了,已經(jīng)引入了,他就存在于最核心的 web 開發(fā)包里面。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.0.5.RELEASE</version> </dependency>
如果你不是 springboot 項目,那么引入下面依賴即可:
<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.4.1.Final</version> </dependency>
那么針對上面情景,我們可以對我們的代碼進(jìn)行優(yōu)化了。
首先我們在 Employee 類的屬性上打上如下注解:
package com.zyq.beans; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Range; /** * 員工對象 * * @author sunnyzyq * @since 2019/12/13 */ public class Employee { /** 姓名 */ @NotBlank(message = "請輸入名稱") @Length(message = "名稱不能超過個 {max} 字符", max = 10) public String name; /** 年齡 */ @NotNull(message = "請輸入年齡") @Range(message = "年齡范圍為 {min} 到 {max} 之間", min = 1, max = 100) public Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
然后再 Controller 對應(yīng)方法上,對這個員工標(biāo)上 @Valid 注解,表示我們對這個對象屬性需要進(jìn)行驗證,
既然驗證,那么就肯定會有驗證結(jié)果,所以我們需要用一個東西來存放驗證結(jié)果,做法也很簡單,在參數(shù)直接添加一個BindingResult,具體如下:
對應(yīng)獲取驗證結(jié)果的代碼如下:
OK ! 萬事俱備 !我們進(jìn)行測試下:
(1)名稱為空
(2)名稱正常,年齡為空
(3)名稱超出范圍,年齡正常
(4)名稱正常,年齡超出范圍
可以看到,代碼不但簡潔了很多,結(jié)果和預(yù)期的也一模一樣!很棒吧??!
常用注解:
除了剛剛都注解,最后再附加2個常用注解,我就直接貼圖了,基本上這6個注解可以解決99%的字段,其他注解我就不貼圖了,如果不滿足,自己問百度。
@Validated 詳解
上面,我們講述了 @Valid 注解,現(xiàn)在我們來說說 @Validated 這個注解,在我看來,@Validated 是在 @Valid 基礎(chǔ)上,做的一個升級版。
我們可以看到,我們在使用 @Valid 進(jìn)行驗證的時候,我們需要用一個對象去接收校驗結(jié)果,最后根據(jù)校驗結(jié)果判斷,從而提示用戶。
如果我們把手動校驗的這段代碼刪除或注釋掉,那么即使當(dāng)我們的字段不滿足規(guī)則時,方法種的程序也是能夠被執(zhí)行的。
比如,我們將字段值置空時,正常情況是會進(jìn)行提示的。
當(dāng)我們把校驗邏輯注釋掉后,再次執(zhí)行上面的請求后。
可以看到我們的程序繼續(xù)往后面去執(zhí)行完成了。
現(xiàn)在,我們?nèi)サ舴椒▍?shù)上的 @Valid 注解和其配對的 BindingResult 對象,
然后再校驗的對象前面添加上 @Validated 注解。
這個時候,我們再次請求,可以看到,我們請求報400錯誤了。
而我們通過程序的異常日志來看,提示說是 age 和 name 字段為了空,致使請求失敗。
那么,從這里我們可以得知,當(dāng)我們的數(shù)據(jù)存在校驗不通過的時候,程序就會拋出
org.springframework.validation.BindException 的異常。
在實際開發(fā)的過程中,我們肯定不能講異常直接展示給用戶,而是給能看懂的提示。
于是,我們不妨可以通過捕獲異常的方式,將該異常進(jìn)行捕獲。
首先我們創(chuàng)建一個校驗異常捕獲類 ValidExceptionHandler ,然后打上 @RestControllerAdvice 注解,該注解表示他會去抓所有 @Controller 標(biāo)記類的異常,并在異常處理后返回以 JSON 或字符串的格式響應(yīng)前端。
算了,我直接將這段代碼貼出來吧。
在異常捕捉到后,我們同上面的 @valid 校驗一樣,只返回第一個錯誤提示。
package com.zyq.config; import org.springframework.validation.BindException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice public class ValidExceptionHandler { @ExceptionHandler(BindException.class) public String validExceptionHandler(BindException exception) { return exception.getAllErrors().get(0).getDefaultMessage(); } }
那么,我們現(xiàn)在重啟程序,然后重新請求,就可以發(fā)現(xiàn)界面已經(jīng)不報400錯誤了,而是直接提示了我們的錯誤信息。
@Valid 和 @Validated 比較
最后我們來對 @Valid 和 @Validated 兩個注解進(jìn)行總結(jié)下:
(1)@Valid 和 @Validated 兩者都可以對數(shù)據(jù)進(jìn)行校驗,待校驗字段上打的規(guī)則注解(@NotNull, @NotEmpty等)都可以對 @Valid 和 @Validated 生效;
(2)@Valid 進(jìn)行校驗的時候,需要用 BindingResult 來做一個校驗結(jié)果接收。當(dāng)校驗不通過的時候,如果手動不 return ,則并不會阻止程序的執(zhí)行;
(3)@Validated 進(jìn)行校驗的時候,當(dāng)校驗不通過的時候,程序會拋出400異常,阻止方法中的代碼執(zhí)行,這時需要再寫一個全局校驗異常捕獲處理類,然后返回校驗提示。
(4)總體來說,@Validated 使用起來要比 @Valid 方便一些,它可以幫我們節(jié)省一定的代碼,并且使得方法看上去更加的簡潔。
到此這篇關(guān)于詳解Spring中@Valid和@Validated注解用法的文章就介紹到這了,更多相關(guān)Spring @Valid @Validated內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring如何動態(tài)自定義logback日志目錄詳解
這篇文章主要給大家介紹了關(guān)于Spring如何動態(tài)自定義logback日志目錄的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-10-10因BigDecimal類型數(shù)據(jù)引出的問題詳析
Java在java.math包中提供的API類BigDecimal,用來對超過16位有效位的數(shù)進(jìn)行精確的運(yùn)算,下面這篇文章主要給大家介紹了因BigDecimal類型數(shù)據(jù)引出的問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-08-08