SpringMvc資料校驗@Valid等註解的使用與工具類抽取
最近在重構老專案的程式碼,發現校驗入參佔用了很多程式碼,之前我對這一塊的認識侷限於使用StringUtils等工具來多個if塊進行判斷,程式碼是沒什麼問題,但是總寫這些令人生煩,畢竟寫程式碼也要講究優雅的嘛,於是呢我就研究了一下JavaEE Api 上的校驗類,基本上推翻了我之前對校驗註解之類的認識,在這裡記錄一下所得。
@NotNull
@NotBlank
@NotEmpty
這三個註解的區別以及使用@NotNull
:校驗入參不能為空,無法正確校檢長度為0的字串或以完全為空格的字串@NotBlank
: 包含@NotNull
的功能,可以校驗字串內容是否為空@NotEmpty
: 校驗傳入集合是否為空當以上幾個註解校驗不被滿足的時候,就會丟擲異常,打印出預設的訊息內容,
如
age not be null
這樣的錯誤資訊想自定義錯誤資訊可以如:
@NotNull(message = "資訊不能為空")
來定義@Valid
的使用如果入參為一個物件,想校驗這個物件內容是否正確的時候,會用到1節中所講的幾個註解,
但是此時會有一個問題:如果不使用
@Valid
註解,1節中的註解在入參過程中是不生效的,只有儲存的時候才會被校驗(不排除PO和DTO是同一個物件的情況)當然,這有一個大前提,就是沒有其它對入參校驗的方法執行。
**所以如果是簡單為了讓異常報出來而不是直接返回的時候可以只用
@Valid
自定義校驗與錯誤資訊的處理
(1)使用
BindingResult
物件接收被@Valid
校驗不通過的錯誤資訊/** * 使用BindingResult與@Valid配合的方式 * 拿到錯誤資訊,帶部分堆疊 */ @PostMapping("/validationTest6") public String validationTest6(@RequestBody @Valid User user, BindingResult result){ if(result.hasErrors()){ //取一條錯誤資訊 ObjectError next = result.getAllErrors().iterator().next(); log.error("error={}", next); //後邊可以自己返回錯誤資訊也可以自定義 return next.toString(); } //do somethings return "校驗通過"; } /** * 使用BindingResult與@Valid配合的方式 * 只拿到錯誤資訊 */ @PostMapping("/validationTest7") public String validationTest7(@RequestBody @Valid User user, BindingResult result){ if(result.hasErrors()){ //取一條錯誤資訊 ObjectError next = result.getAllErrors().iterator().next(); String defaultMessage = next.getDefaultMessage(); log.error("error={}", defaultMessage); //後邊可以自己返回錯誤資訊也可以自定義 return defaultMessage; } //do somethings return "校驗通過"; }
(2)使用Validator物件,不信賴於
@Valid
的實現/** * 使用Validator未抽取工具類時的實現 */ @PostMapping("/validationTest9") public String validationTest9(@RequestBody User user){ ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); Validator validator = factory.getValidator(); Set<ConstraintViolation<User>> validate = validator.validate(user); if(!validate.isEmpty()){ ConstraintViolation<User> next = validate.iterator().next(); String message = next.getMessage(); log.error("error={}",message); return message; } //do somethings return "校驗通過"; }
上邊給大家介紹了兩種方法,其中第二種看起來程式碼更多一些,其實這應該就是沒有使用
@Valid
的問題了,因為你並不知道@Valid
註解校驗錯誤程式碼有多少。效率基本差不多少下邊為大家提供一個工具類,分別提供了上邊兩種方式的封裝,如果只想使用
BindingResult
方式,那麼大可以去除用不到的程式碼封裝的工具類與使用
(1)工具類程式碼
package com.cnblogs.hellxz.myutils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; import java.util.Set; /** * <b>類名</b>: ValidatorUtils * <p><b>描 述</b> 校驗入參 </p> * * <p><b>建立日期</b>: 8/24/18 12:54 PM </p> * * @author HELLXZ 張 * @version 1.0 * @since jdk 1.8 */ public class ValidatorUtils { private static final Logger log = LoggerFactory.getLogger(ValidatorUtils.class); private static final Validator validator; static { ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); validator = factory.getValidator(); } /** * 分組進行校驗或完整校驗 * 區別在於是否傳groups類 * ps:分組的好處在於同一個DTO分別給不同的方法指定不同的校驗引數時候非常有用 * 也就不用再去重寫一個新的相同欄位的DTO指定不同校驗欄位的操作,更靈活 * @param object 被校驗的DTO物件 * @param groups 分組類,可以是介面也可以是類,僅作為標識 * @return 想要返回的結果 */ public static <T> String validEntity(final T object, Class... groups) { Set<ConstraintViolation<T>> violations = validator.validate(object, groups); if (!violations.isEmpty()) { //這裡只取第一條錯誤,防止返回引數過多 ConstraintViolation<T> violation = violations.iterator().next(); log.error(violation.getMessage()); //下面的程式碼可以使用公司或個人習慣的返回工具類也可以 return "{\"code\":\"400\",\"msg\":\"" + violation.getMessage() + "\"}"; } return null; } /** * 校驗入參物件的某個屬性是否滿足要求,跳過其它校驗, 支援分組 * @param object 被校驗的DTO物件 * @param propertyName DTO物件內的屬性名 * @param groups 分組名 * @return 校驗出錯返回的結果 */ public static <T> String validProperty(final T object, String propertyName, Class... groups) { Set<ConstraintViolation<T>> violations = validator.validateProperty(object, propertyName, groups); if (!violations.isEmpty()) { //這裡只取第一條錯誤,防止返回引數過多 ConstraintViolation<T> violation = violations.iterator().next(); log.error(violation.getMessage()); //下面的程式碼可以使用公司或個人習慣的返回工具類也可以 return "{\"code\":\"400\",\"msg\":\"" + violation.getMessage() + "\"}"; } return null; } /** * 使用BindingResult與@Valid註解一起使用實現的工具類 * @param result BindingResult物件 * @return 結果串 */ public static String validEntity(BindingResult result){ if(result.hasErrors()){ //取一條錯誤資訊 ObjectError next = result.getAllErrors().iterator().next(); String defaultMessage = next.getDefaultMessage(); log.error("error={}", defaultMessage); //後邊可以自己返回錯誤資訊也可以自定義 return "{\"code\":\"400\",\"msg\":\"" + defaultMessage + "\"}"; } return null; } }
(2) 工具類的使用
private static Logger log = LoggerFactory.getLogger(ValidateController.class); /** * 檢查User物件註解在A組內的校驗 */ @PostMapping("/validationTest1") public String validationTest1(@RequestBody User user){ String valid = ValidatorUtils.validEntity(user, A.class); if(null != valid) return valid; //do somethings return "校驗通過"; } /** * 檢查User物件註解在B組內的校驗 */ @PostMapping("/validationTest2") public String validationTest2(@RequestBody User user){ String valid = ValidatorUtils.validEntity(user, B.class); if(null != valid) return valid; //do somethings return "校驗通過"; } /** * 檢查User物件註解在A組和B組內的校驗 * ps: 是A組內校驗加上B組內校驗,不是校驗同時在兩個組! */ @PostMapping("/validationTest3") public String validationTest3(@RequestBody User user){ String valid = ValidatorUtils.validEntity(user, A.class, B.class); if(null != valid) return valid; //do somethings return "校驗通過"; } /** * 校驗入參物件中指定欄位 * 其中分組可以不傳,如果傳的話,請注意該欄位必須在該組下,否則不會被校驗 */ @PostMapping("/validationTest4") public String validationTest4(@RequestBody User user){ String valid = ValidatorUtils.validProperty(user,"age", B.class); if(null != valid) return valid; //do somethings return "校驗通過"; } /** * 驗證上邊Test4的說法 */ @PostMapping("/validationTest5") public String validationTest5(@RequestBody User user){ String valid = ValidatorUtils.validProperty(user,"age", A.class); if(null != valid) return valid; //do somethings return "校驗通過"; } /** * 使用方法7抽的工具類 */ @PostMapping("/validationTest8") public String validationTest8(@RequestBody @Valid User user, BindingResult result){ String errorMsg = ValidatorUtils.validEntity(result); if(StringUtils.isNotBlank(errorMsg)) return errorMsg; //do somethings return "校驗通過"; }
(3) 補充:User類
public class User { @NotBlank(message = "使用者名稱不能為空串",groups = A.class) private String username; @NotNull(message = "年齡不能為空",groups = B.class) private String age; @NotBlank(message = "身高不能為空", groups = {A.class, B.class}) private String height; @NotEmpty(message = "孩子列表不能為空") private List<Object> childs; @Email(message = "email不正確") private String email; //省略get set 方法 }
擴充套件部分
空檢查
@Null
:驗證某引數必須為空 ps: 沒有過 =. = ,其餘的空檢查在上邊已經講了長度檢查
@Size(min=, max=)
: 驗證物件(Array,Collection,Map,String)長度是否在給定的範圍之內@Length(min=, max=)
: 長度是否在範圍內Booelan檢查
@AssertTrue
: 驗證 Boolean 物件是否為 true@AssertFalse
: 驗證 Boolean 物件是否為 false數值檢查:建議用在基礎型別包裝型別上和String型別上
@Min
: 驗證最小值@Max
: 驗證最大值@DecimalMax
:小數數值不能大於設定的值,小數存在精度@DecimalMin
:小數數值不能小於設定的值,小數存在精度@Digits
: 驗證數字和字串組成是否合法範圍檢查
@Range(min=, max=)
:驗證物件最小與最大的範圍號碼檢查
@CreditCardNumber
: 信用卡驗證(hibernate的實現)@Email
: 驗證是否是郵件地址,如果為null,則不進行驗證,通過驗證(validation和hibernate均有實現)日期檢查
@Past
:驗證 Date 和 Calendar 物件是否在當前時間之前,null 被認為是通過驗證@Future
:驗證 Date 和 Calendar 物件是否在當前時間之後 ,null 被認為是通過驗證正則表示式檢查
@Pattern(regexp = "")
: 使用正則表示式驗證String,接受字元序列,regexp必填,所修飾為null時認為是通過驗證終了
憋了一晚上才想通校驗的實際用法,參考了一些的博文,把最大部分的內容引用粘在下面了,基本是官方文件和一個外文網站
https://docs.oracle.com/javaee/7/api/toc.htm
https://docs.jboss.org/hibernate/stable/validator/api/
https://www.baeldung.com/javax-validation
https://blog.csdn.net/yanfeng918/article/details/42618593
本文程式碼:https://github.com/HellxZ/MyUtils.git
宣告:本文內容未經許可可以轉載,但請註明出處
相關推薦
SpringMvc資料校驗@Valid等註解的使用與工具類抽取
最近在重構老專案的程式碼,發現校驗入參佔用了很多程式碼,之前我對這一塊的認識侷限於使用StringUtils等工具來多個if塊進行判斷,程式碼是沒什麼問題,但是總寫這些令人生煩,畢竟寫程式碼也要講究優雅的嘛,於是呢我就研究了一下JavaEE Api 上的校驗類,基本上推翻了我之前對校驗註解之類的認識,在這裡記
SpringMVC資料校驗註解
@AssertFalse 被註解的元素必須為false @AssertTrue 被註解的元素必須為false @DecimalMax(value) 被註解的元素必須為一個數字,其值必須小於等於指定的最小值 @DecimalMin(Value) 被註解的元素必須為一個數字,其值必須大於等於指定的最小值 @Dig
springmvc 資料校驗
private Integer id; @NotEmpty private String lastName; @Email private String email; //1 male, 0 female private Integer gend
SpringMVC資料校驗、檔案上傳
package com.remoa.user.domain; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class UserVOExample implements Seri
Spring Boot 資料校驗@Valid+統一異常處理
1.先在你需要校驗的實體類上面加上所需要的註解 為了測試,我自己就簡單寫了。@NotNull 和 @NotBlank 不能為空 @Entity @Table(name = "User") @Data public class User implement
從深處去掌握資料校驗@Valid的作用(級聯校驗)
每篇一句 NBA裡有兩大笑話:一是科比沒天賦,二是詹姆斯沒技術 相關閱讀 【小家Java】深入瞭解資料校驗:Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validation 6.x使用案例 【小家Spring】讓Controller支援對
springmvc中後端校驗@Valid註解
@Valid註解用於校驗,所屬包為:javax.validation.Valid。① 首先需要在實體類的相應欄位上新增用於充當校驗條件的註解,如:@Min,如下程式碼(age屬於Girl類中的屬性):@Min(value = 20,message = "結婚年齡限制") p
SpringMVC-8 資料型別轉換、資料格式化與資料校驗
1. 資料繫結流程 SpringMVC通過反射機制對目標處理方法進行解析,將請求訊息繫結到處理方法的入參中。其中,資料繫結的核心部件是DataBinder,執行機制如下: 資料繫結的具體流程說明如下: SpringMVC主框架將S
SpringBoot全域性異常與資料校驗
異常處理是每個專案中都繞不開的話題,那麼如何優雅的處理異常,是本文的話題。本文將結合SpringBoot框架一起和大家探討下。 要思考的問題 在現在的前後端互動中,通常都規範了介面返回方式,如返回的介面狀態(成功|失敗)以及要返回的資料在那個欄位取,或者說失敗了以後提示資訊從介面哪裡返回,因
SpringMVC總結--資料格式轉換和資料校驗
SpringMVC資料繫結流程 A:SpingMVC 主框架將 ServletRequest 物件及目標方法的入參例項傳遞 WebDataBinderFactory 例項,以建立DataBinder 例項物件 &nbs
如何優雅的處理異常?SpringBoot全域性異常與資料校驗
要思考的問題 在現在的前後端互動中,通常都規範了介面返回方式,如返回的介面狀態(成功|失敗)以及要返回的資料在那個欄位取,或者說失敗了以後提示資訊從介面哪裡返回,因此,如果想做全域性異常,並且異常發生後能準確的返回給前端解析,那麼需要異常發生時返回給前端的格式與正常失敗場景的格式一致。
SpringMVC的資料轉換、格式化和資料校驗
目錄 5.案例 一、資料轉換 Spring MVC 上下文中內建了很多轉換器,可完成大多數 Java 型別的轉換工作。 1.ConversionService ConversionServ
SpringMVC的資料校驗(一)
什麼是資料校驗 這個比較好理解,就是用來驗證客戶輸入的資料是否合法,比如客戶登入時,使用者名稱不能為空,或者不能超出指定長度等要求,這就叫做資料校驗。資料校驗分為客戶端校驗和服務端校驗 客戶端校驗:js校驗 服務端校驗:springmvc使用validat
【SpringMVC學習06】SpringMVC中的資料校驗
這一篇博文主要總結一下springmvc中對資料的校驗。在實際中,通常使用較多是前端的校驗,比如頁面中js校驗,對於安全要求較高的建議在服務端也要進行校驗。服務端校驗可以是在控制層conroller
CRC校驗碼生成與資料校驗原始碼程式 (包括CRC-4,5,6,7,8,16,32)
C程式碼 收藏程式碼 /******************************************************************** * Name: CRC-4/ITU x4+x+1 *
資料校驗與陣列磁碟
海明校驗碼和 異或校驗是兩種最為常用的 資料校驗演算法。海明校驗碼是由理查德.海明提出的,不僅能檢測錯誤,還能給出錯誤位置並自動糾正。海明校驗的基本思想是: 將有效資訊按照某種規律分成若干組,對每一個組作奇偶測試並安排一個校驗位,從而能提供多位檢錯資訊,以定位錯誤點並糾正
全量資料同步與資料校驗實踐——應對百億量級分庫分表異構庫遷移
在一家發展中的公司搬磚,正好遇到分庫分表,資料遷移的需求比較多,就入坑了。最近有個系統重構,一直做資料重構、遷移、校驗等工作,基本能覆蓋資料遷移的各個基本點,所以趁機整理一下。 資料同步的場景是:資料庫拆分、資料冗餘、資料表重構。 資料重構服務主要包括:全量
SpringMVC學習(三)———— springmvc的資料校驗的實現
一、什麼是資料校驗? 這個比較好理解,就是用來驗證客戶輸入的資料是否合法,比如客戶登入時,使用者名稱不能為空,或者不能超出指定長度等要求,這就叫做資料校驗。 資料校驗分為客戶端校驗和服務端校驗 客戶端校驗:js校驗 服務端校驗:springmvc
springmvc 使用JSR-303進行資料校驗
專案中,通常使用較多的是前端的校驗,比如頁面中js校驗以及form表單使用bootstrap校驗。然而對於安全要求較高點建議在服務端進行校驗。 服務端校驗: 控制層controller:校驗頁面請求的引數的合法性。在服務端控制層controller校驗
SpringMVC實現頁面和java模型的資料互動以及檔案上傳下載和資料校驗
1. 專案結構 2. springMVC-servlet.xml 配置檔案 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org