JAVA校驗(yàn)之@Valid和@Validated實(shí)踐指南
概述
區(qū)別
- 來源 (規(guī)范與框架綁定) -
@Validated
: 它是 Spring 框架特有的注解,屬于 Spring 自身提供的一個功能增強(qiáng)。它基于 JSR 303 (Bean Validation 1.0) / JSR 380 (Bean Validation 2.0) 規(guī)范,但在其基礎(chǔ)上進(jìn)行了擴(kuò)展,特別適用于 Spring 環(huán)境。
-@Valid
: 這是一個標(biāo)準(zhǔn)的 Java EE 注解,是 JSR 303 / JSR 380 (Bean Validation) 規(guī)范的核心組成部分。它不依賴于任何特定的框架,可以在任何支持 Bean Validation 的環(huán)境中(如 Hibernate Validator、CDI 等)使用。 - 注解位置 (適用范圍) -
@Validated
: 主要用于類(聲明在類上時,會對其所有公共方法參數(shù)進(jìn)行校驗(yàn))、方法和方法參數(shù)。它不能直接用于成員屬性(字段)。當(dāng)用于類上時,通常與 Spring 的 AOP 攔截結(jié)合使用。
-@Valid
: 可以用于方法、構(gòu)造函數(shù)、方法參數(shù)以及成員屬性(字段)。當(dāng)用于成員屬性時,它會觸發(fā)對該屬性所引用對象的級聯(lián)校驗(yàn)。 - 分組 (靈活性) -
@Validated
: 支持分組驗(yàn)證。這是其相比@Valid
的一個重要優(yōu)勢。你可以通過在@Validated
注解中指定一個或多個接口類來定義校驗(yàn)組,從而在不同的業(yè)務(wù)場景(如創(chuàng)建、更新)中應(yīng)用不同的校驗(yàn)規(guī)則。
-@Valid
: 僅支持標(biāo)準(zhǔn)的 Bean Validation 功能,不支持分組驗(yàn)證。當(dāng)它觸發(fā)校驗(yàn)時,它會執(zhí)行目標(biāo)對象上所有未指定分組的(即默認(rèn)組Default.class
)以及任何被顯式指定為Default.class
的約束。 - 嵌套驗(yàn)證 (遞歸校驗(yàn)) -
@Validated
: 單獨(dú)使用時,@Validated
本身不支持嵌套驗(yàn)證。它通常需要與@Valid
配合使用才能實(shí)現(xiàn)對復(fù)雜對象內(nèi)部嵌套屬性的校驗(yàn)。@Validated
主要負(fù)責(zé)激活校驗(yàn)器并指定校驗(yàn)組,而@Valid
則負(fù)責(zé)遞歸遍歷對象圖。
-@Valid
: 支持嵌套驗(yàn)證。當(dāng)一個對象的屬性本身也是一個需要被校驗(yàn)的對象時,你可以在該屬性上添加@Valid
,這樣在父對象被校驗(yàn)時,其內(nèi)部的嵌套屬性也會被自動遞歸校驗(yàn)。
校驗(yàn)類型
@NotNull
: 被注解的元素不能為null
。
適用類型: 任何類型(對象、基本類型包裝類、集合、數(shù)組等)。@NotEmpty
: 被注解的元素不能為null
且其大小/長度必須大于零。
適用類型:CharSequence
(字符串)、Collection
(集合如List
,Set
)、Map
、Array
(數(shù)組)。@NotBlank
: 被注解的String
類型不能為null
,不能是空字符串 (""
),且不能只包含空白字符(如空格、制表符)。
適用類型:CharSequence
(字符串)。@Min(value)
: 被注解的元素必須是一個數(shù)字,且其值必須大于或等于指定值value
。
適用類型:BigDecimal
,BigInteger
,Byte
,Short
,Integer
,Long
,Float
,Double
及其包裝類。@Max(value)
: 被注解的元素必須是一個數(shù)字,且其值必須小于或等于指定值value
。
適用類型:BigDecimal
,BigInteger
,Byte
,Short
,Integer
,Long
,Float
,Double
及其包裝類。@DecimalMin(value, inclusive=true)
: 被注解的元素必須是一個數(shù)字,且其值必須大于或等于指定值value
(默認(rèn)inclusive=true
)。如果inclusive=false
,則表示大于value
。
適用類型:BigDecimal
,BigInteger
,Byte
,Short
,Integer
,Long
,Float
,Double
及其包裝類,以及String
(其內(nèi)容必須是數(shù)字)。@DecimalMax(value, inclusive=true)
: 被注解的元素必須是一個數(shù)字,且其值必須小于或等于指定值value
(默認(rèn)inclusive=true
)。如果inclusive=false
,則表示小于value
。
適用類型:BigDecimal
,BigInteger
,Byte
,Short
,Integer
,Long
,Float
,Double
及其包裝類,以及String
(其內(nèi)容必須是數(shù)字)。@Positive
: 被注解的元素必須是正數(shù)(大于 0)。
適用類型:BigDecimal
,BigInteger
,Byte
,Short
,Integer
,Long
,Float
,Double
及其包裝類。@PositiveOrZero
: 被注解的元素必須是正數(shù)或零(大于等于 0)。
適用類型:BigDecimal
,BigInteger
,Byte
,Short
,Integer
,Long
,Float
,Double
及其包裝類.@Negative
: 被注解的元素必須是負(fù)數(shù)(小于 0)。
適用類型:BigDecimal
,BigInteger
,Byte
,Short
,Integer
,Long
,Float
,Double
及其包裝類.@NegativeOrZero
: 被注解的元素必須是負(fù)數(shù)或零(小于等于 0)。
適用類型:BigDecimal
,BigInteger
,Byte
,Short
,Integer
,Long
,Float
,Double
及其包裝類.@Size(min, max)
: 被注解的元素大小/長度必須在指定范圍(min
到max
)之內(nèi)。
適用類型:CharSequence
(字符串)、Collection
(集合)、Map
、Array
(數(shù)組)。@Digits(integer, fraction)
: 被注解的元素必須是一個數(shù)字,其整數(shù)部分的位數(shù)不能超過integer
位,小數(shù)部分的位數(shù)不能超過fraction
位。
適用類型:BigDecimal
,BigInteger
,Byte
,Short
,Integer
,Long
,Float
,Double
及其包裝類,以及String
(其內(nèi)容必須是數(shù)字)。@Past
: 被注解的日期或時間必須是一個過去的日期或時間。
適用類型:java.util.Date
,java.util.Calendar
,java.time.LocalDate
,java.time.LocalDateTime
,java.time.LocalTime
,java.time.MonthDay
,java.time.OffsetDateTime
,java.time.OffsetTime
,java.time.Year
,java.time.YearMonth
,java.time.ZonedDateTime
等。@PastOrPresent
: 被注解的日期或時間必須是一個過去的或當(dāng)前的日期或時間。
適用類型: 同@Past
。@Future
: 被注解的日期或時間必須是一個未來的日期或時間。
適用類型: 同@Past
。@FutureOrPresent
: 被注解的日期或時間必須是一個未來的或當(dāng)前的日期或時間。
適用類型: 同@Past
。@Pattern(regexp, flags=Pattern.CASE_INSENSITIVE)
: 被注解的String
必須符合指定的正則表達(dá)式regexp
。
適用類型:CharSequence
(字符串)。@Email
: 被注解的String
必須是有效的郵件地址格式。
適用類型:CharSequence
(字符串)。@AssertTrue
: 被注解的布爾類型必須為true
。通常用于驗(yàn)證復(fù)雜邏輯(如兩個字段間的關(guān)聯(lián)驗(yàn)證),需要一個返回boolean
的 getter 方法。
適用類型:Boolean
或boolean
。@AssertFalse
: 被注解的布爾類型必須為false
。
適用類型:Boolean
或boolean
。
實(shí)踐
分組校驗(yàn)
分組校驗(yàn)允許你根據(jù)不同的業(yè)務(wù)場景(如創(chuàng)建、更新、刪除等)對同一個實(shí)體類應(yīng)用不同的驗(yàn)證規(guī)則,從而實(shí)現(xiàn)更靈活和精細(xì)的控制。
特別注意:
- 定義分組必須使用接口。 這些接口是空的,僅作為校驗(yàn)規(guī)則的標(biāo)識。
- 要校驗(yàn)的字段上的注解必須通過
groups
屬性指定所屬的分組。 如果一個校驗(yàn)注解沒有指定groups
,它將默認(rèn)屬于Default.class
組,并在任何未指定分組或顯式指定Default.class
的校驗(yàn)中生效。 - 在 Controller 方法的
@Validated
注解中指定要激活的分組。
創(chuàng)建分組
// 用于創(chuàng)建操作的校驗(yàn)組 public interface CreationGroup { } // 用于更新操作的校驗(yàn)組 public interface UpdateGroup { } // 你還可以定義其他分組,例如: // public interface DeleteGroup { }
設(shè)置實(shí)體
在實(shí)體類的字段上添加校驗(yàn)注解,并使用 groups
屬性指定該校驗(yàn)規(guī)則屬于哪個分組。一個字段可以屬于多個分組。
@Data public class UserBean { // 創(chuàng)建和更新時都校驗(yàn)用戶名非空 // 默認(rèn)的 Default 組也適用,但如果指定了分組,則只在指定分組下生效 @NotEmpty(message = "用戶名不能為空", groups = {CreationGroup.class, UpdateGroup.class}) private String username; // 年齡校驗(yàn),無分組,默認(rèn)在所有場景(包括未指定分組的 @Validated)下都校驗(yàn) @Min(value = 18, message = "年齡不能小于18歲") private Integer age; // 郵箱格式校驗(yàn),無分組,默認(rèn)在所有場景下都校驗(yàn) @Email(message = "郵箱格式不正確") private String email; // ID 校驗(yàn),只在更新時生效,且必須大于等于1 @NotNull(message = "ID不能為空", groups = UpdateGroup.class) // 更新時ID不能為null @Min(value = 1, message = "ID必須大于0", groups = {UpdateGroup.class}) private Long id; // ... 其他屬性 }
使用校驗(yàn)
在 Controller 方法的參數(shù)上使用 @Validated
注解,并傳入需要激活的校驗(yàn)組。
import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; // 導(dǎo)入 javax.validation.Valid @RestController @RequestMapping("validation") public class ValidationController { /** * 更新用戶接口:只激活 UpdateGroup 組的校驗(yàn)規(guī)則。 * 此時,UserBean 中的 id 字段會根據(jù) UpdateGroup 的規(guī)則進(jìn)行校驗(yàn)。 * username 和 age、email 字段則會根據(jù)它們自身定義的(或默認(rèn)的)規(guī)則進(jìn)行校驗(yàn)。 */ @GetMapping("updateUser") public UserBean updateUser(@Validated({UpdateGroup.class}) UserBean userBean){ // 如果校驗(yàn)失敗,會拋出 MethodArgumentNotValidException,由全局異常處理器捕獲 System.out.println("更新用戶成功: " + userBean); return userBean; } /** * 創(chuàng)建用戶接口:只激活 CreationGroup 組的校驗(yàn)規(guī)則。 * 此時,UserBean 中的 username 字段會根據(jù) CreationGroup 的規(guī)則進(jìn)行校驗(yàn)。 * age 和 email 字段則會根據(jù)它們自身定義的(或默認(rèn)的)規(guī)則進(jìn)行校驗(yàn)。 * id 字段由于不屬于 CreationGroup,將不會被校驗(yàn)。 */ @GetMapping("createUser") public UserBean createUser(@Validated({CreationGroup.class}) UserBean userBean){ // 如果校驗(yàn)失敗,會拋出 MethodArgumentNotValidException,由全局異常處理器捕獲 System.out.println("創(chuàng)建用戶成功: " + userBean); return userBean; } // 注意:如果一個方法參數(shù)不加 @Validated,但實(shí)體類中有 @Valid 注解, // 則會默認(rèn)校驗(yàn)所有無分組的字段(即 Default 組)。 // 例如: // @PostMapping("defaultValid") // public UserBean defaultValid(@Valid @RequestBody UserBean userBean) { // return userBean; // } }
嵌套驗(yàn)證
嵌套校驗(yàn)(Nested Validation) 指的是在驗(yàn)證外部對象時,對其內(nèi)部包含的其他對象進(jìn)行遞歸驗(yàn)證的過程。當(dāng)一個對象中包含另一個對象作為屬性,并且需要對這個被包含的對象也進(jìn)行驗(yàn)證時,就需要進(jìn)行嵌套校驗(yàn)。
嵌套屬性指的是在一個對象中包含另一個對象作為其屬性的情況。換句話說,當(dāng)一個對象的屬性本身又是一個對象(非基本類型),那么這些被包含的對象就可以稱為嵌套屬性。
特別提示:
- 想要嵌套校驗(yàn)生效,必須在嵌套屬性上加 @Valid 注解。這個注解告訴校驗(yàn)器深入到這個屬性對應(yīng)的對象內(nèi)部進(jìn)行校驗(yàn)。
- @Valid 注解默認(rèn)校驗(yàn)無分組的項(xiàng)。它會觸發(fā)嵌套對象上所有屬于
Default.class
組的校驗(yàn)。 - 嵌套驗(yàn)證要支持分組,需要結(jié)合 @Validated({YourGroup.class})。 當(dāng)
@Validated
指定了分組并作用于包含@Valid
屬性的外部對象時,@Valid
會將這個分組信息傳遞給嵌套對象,從而使其內(nèi)部只有對應(yīng)分組的校驗(yàn)規(guī)則生效。
驗(yàn)證嵌套屬性
首先,定義你的嵌套實(shí)體類,并為其字段添加校驗(yàn)規(guī)則:
import lombok.Data; import javax.validation.constraints.NotBlank; @Data public class AddressBean { @NotBlank(message = "國家不能為空") private String country; @NotBlank(message = "城市不能為空") private String city; }
接著,在主實(shí)體類中包含這個嵌套屬性,并在該屬性上添加 @Valid
和 @NotNull
(如果地址對象本身不能為 null):
@Data public class UserBean { @NotEmpty(message = "用戶名不能為空", groups = {CreationGroup.class}) private String username; @Min(value = 18, message = "年齡不能小于18歲") private Integer age; @Email(message = "郵箱格式不正確") private String email; // 嵌套驗(yàn)證必須要加上 @Valid // 同時可以添加 @NotNull 來確保 address 對象本身不為空 @Valid @NotNull(message = "地址信息不能為空") private AddressBean address; // 嵌套屬性 // ... 其他屬性和 getter/setter }
然后在 Controller 中使用 @Validated
來觸發(fā)校驗(yàn):
@RestController @RequestMapping("validation") public class ValidationController { /** * 嵌套驗(yàn)證示例。 * 當(dāng) @RequestBody UserBean userBean 傳入時, * 如果 userBean 內(nèi)部的 address 屬性有 @Valid 注解, * 那么 address 對象自身的校驗(yàn)規(guī)則也會被觸發(fā)。 * 此處如果 address 為 null 或其內(nèi)部字段(country, city)為空,都會觸發(fā)校驗(yàn)失敗。 */ @PostMapping("nestValid") public UserBean nestValid(@Validated @RequestBody UserBean userBean){ // @Validated 也可以不指定分組,則校驗(yàn) Default 組 System.out.println("嵌套驗(yàn)證成功: " + userBean); return userBean; } /** * 帶分組的嵌套驗(yàn)證示例。 * 此時,只有 UserBean 中屬于 CreationGroup 的校驗(yàn)規(guī)則生效, * 并且這個分組也會傳遞給嵌套的 AddressBean,如果 AddressBean 中也有分組校驗(yàn)規(guī)則,它們就會生效。 * 此外,因?yàn)?address 屬性是 @Valid 且 @NotNull,它會始終被校驗(yàn)。 */ @PostMapping("nestValidWithGroup") public UserBean nestValidWithGroup(@Validated(CreationGroup.class) @RequestBody UserBean userBean){ System.out.println("帶分組的嵌套驗(yàn)證成功: " + userBean); return userBean; } }
驗(yàn)證集合
當(dāng)請求體是一個對象的集合(如 List<YourBean>
)時,校驗(yàn)的原理與嵌套驗(yàn)證類似,你需要將 @Valid
放在集合參數(shù)前,而 @Validated
則用于指定校驗(yàn)組(如果需要)。同時,你也可以對集合本身進(jìn)行非空校驗(yàn)。
@RestController @RequestMapping("/metadataTemplate") public class ReMetadataTemplateController { // 假設(shè) reMetadataTemplateService 已注入 /** * 更改元數(shù)據(jù)模板狀態(tài)接口,支持對列表本身非空及列表中每個對象的字段進(jìn)行分組校驗(yàn)。 * * @param list 待更新的元數(shù)據(jù)模板列表 * @return 結(jié)果 */ @PutMapping("/changeStatus") @Validated(EditGroup.class) // 指定激活 EditGroup 組的校驗(yàn) public Void changeStatus( // @Valid 觸發(fā)對 List 中每個 ReMetadataTemplateBo 對象的校驗(yàn) // @NotEmpty(message = "參數(shù)不能為空") 校驗(yàn) List 本身不能為 null 或空集合 @Valid @NotEmpty(message = "元數(shù)據(jù)模板列表不能為空", groups = EditGroup.class) @RequestBody List<ReMetadataTemplateBo> list ) { // 如果校驗(yàn)失敗,會拋出 MethodArgumentNotValidException,由全局異常處理器捕獲 // ... 業(yè)務(wù)邏輯 reMetadataTemplateService.changeStatus(list); } }
異常處理
為了更好地處理校驗(yàn)失敗時拋出的異常,通常需要配置一個全局異常處理器。
引用
- https://cloud.tencent.com/developer/article/2396081
- Spring Boot Validation with @Valid and @Validated
- JSR 303: Bean Validation
- JSR 380: Bean Validation 2.0
到此這篇關(guān)于JAVA校驗(yàn)之@Valid和@Validated實(shí)踐指南的文章就介紹到這了,更多相關(guān)JAVA校驗(yàn)@Valid和@Validated內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 使用@Validated和@Valid 解決list校驗(yàn)的問題
- Java中的三種校驗(yàn)注解的使用(@Valid,@Validated和@PathVariable)
- spring @Validated 注解開發(fā)中使用group分組校驗(yàn)的實(shí)現(xiàn)
- Java參數(shù)校驗(yàn)@Validated、@Valid介紹及使用詳解
- SpringBoot參數(shù)校驗(yàn)之@Validated的使用詳解
- @Valid和@Validated注解校驗(yàn)以及異常處理方式
- 使用@Validated注解進(jìn)行校驗(yàn)卻沒有效果的解決
- Spring 中@Validated 分組校驗(yàn)的使用解析
- Spring利用@Validated注解實(shí)現(xiàn)參數(shù)校驗(yàn)詳解
相關(guān)文章
Spring事務(wù)失效的一種原因關(guān)于this調(diào)用的問題
這篇文章主要介紹了Spring事務(wù)失效的一種原因關(guān)于this調(diào)用的問題,本文給大家分享問題原因及解決辦法,通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-10-10springboot vue完成發(fā)送接口請求顯示響應(yīng)頭信息
這篇文章主要為大家介紹了springboot+vue完成發(fā)送接口請求顯示響應(yīng)頭信息,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05SpringBoot配置線程池的實(shí)現(xiàn)示例
本文主要介紹了SpringBoot配置線程池的實(shí)現(xiàn)示例,主要包括在Spring Boot中創(chuàng)建和配置線程池,包括設(shè)置線程池的大小、隊(duì)列容量、線程名稱等參數(shù),感興趣的可以了解一下2023-09-09springboot讀取.properties配置文件中的map和list類型配置參數(shù)方式
這篇文章主要介紹了springboot讀取.properties配置文件中的map和list類型配置參數(shù)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-03-03SpringMVC 向jsp頁面?zhèn)鬟f數(shù)據(jù)庫讀取到的值方法
下面小編就為大家分享一篇SpringMVC 向jsp頁面?zhèn)鬟f數(shù)據(jù)庫讀取到的值方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03