SpringBoot參數(shù)校驗(yàn):@Valid與@Validated使用詳解
一、案例(參數(shù)校驗(yàn)的必要性)
傳統(tǒng)方式(無(wú)注解)的缺點(diǎn):
// 需要手動(dòng)校驗(yàn)每個(gè)字段,代碼冗余且易出錯(cuò)
public String register(User user) {
// 手動(dòng)校驗(yàn)每個(gè)字段
if (user.getEmail() == null || !isValidEmail(user.getEmail())) {
throw new IllegalArgumentException("郵箱格式錯(cuò)誤");
}
if (user.getPassword().length() < 8) {
throw new IllegalArgumentException("密碼長(zhǎng)度需≥8位");
}
// 校驗(yàn)邏輯與業(yè)務(wù)代碼耦合,難以復(fù)用
}問(wèn)題總結(jié):
- 代碼冗余:相同校驗(yàn)邏輯重復(fù)編寫
- 維護(hù)困難:校驗(yàn)規(guī)則分散,修改成本高
- 可讀性差:業(yè)務(wù)邏輯被大量
if-else淹沒(méi)
注解方式的優(yōu)勢(shì):
public class User {
@Email(message = "郵箱格式不合法") // 一行注解替代復(fù)雜校驗(yàn)
private String email;
@Size(min = 8, message = "密碼長(zhǎng)度需≥8位")
private String password;
}
@PostMapping("/register")
public String register(@Valid @RequestBody User user) {
// 校驗(yàn)邏輯由框架自動(dòng)處理
return "success";
}核心優(yōu)勢(shì):
- 聲明式校驗(yàn):通過(guò)注解自動(dòng)完成參數(shù)驗(yàn)證
- 代碼簡(jiǎn)潔:減少冗余的
if-else判斷 - 統(tǒng)一規(guī)范:標(biāo)準(zhǔn)化校驗(yàn)規(guī)則,降低維護(hù)成本
二、@Valid 注解
簡(jiǎn)介
- Java標(biāo)準(zhǔn)注解(javax.validation)
- 用于觸發(fā) Bean Validation 校驗(yàn)機(jī)制
- 可校驗(yàn)方法參數(shù)和成員屬性
SpringBoot配置
<!-- pom.xml 必須依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>使用示例
public class User {
@NotNull(message = "用戶名不能為空")
private String name;
@Min(value = 18, message = "年齡必須≥18歲")
private Integer age;
}
@PostMapping("/users")
public String createUser(@Valid @RequestBody User user) { // 觸發(fā)校驗(yàn)
return "success";
}全局異常處理(核心實(shí)踐)
@RestControllerAdvice
public class GlobalExceptionHandler {
// 處理@Valid/@Validated拋出的校驗(yàn)異常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationException(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage()));
return ResponseEntity.badRequest().body(errors);
}
}效果:自動(dòng)返回結(jié)構(gòu)化錯(cuò)誤信息(字段名+錯(cuò)誤描述)
三、@Validated 注解
簡(jiǎn)介
- Spring框架注解(org.springframework.validation.annotation)(@Validated是Spring框架提供的,導(dǎo)入springboot的依賴就會(huì)自動(dòng)導(dǎo)入這個(gè)依賴)
- 支持分組校驗(yàn)(Group Validation)
- 可標(biāo)注在類、方法、參數(shù)上
核心功能
// 分組接口定義
public interface CreateGroup {}
public interface UpdateGroup {}
public class User {
@NotBlank(groups = CreateGroup.class)
private String name;
@NotNull(groups = {CreateGroup.class, UpdateGroup.class})
private Integer age;
}
// 使用分組校驗(yàn)
@PostMapping("/users")
public String createUser(@Validated(CreateGroup.class) @RequestBody User user) {
return "success";
}四、常用校驗(yàn)注解
最常用的注解:
| 注解 | 說(shuō)明 | 示例 |
|---|---|---|
| @NotNull | 值不能為null | @NotNull(message="字段必填") |
| @NotBlank | 字符串非空(trim后) | 適用于用戶名、密碼等 |
| @Min/@Max | 數(shù)值范圍限制 | @Min(18) |
| @Pattern | 正則表達(dá)式校驗(yàn) | @Pattern(regexp="^1[3-9]\\d{9}$") |
| @Valid | 嵌套對(duì)象校驗(yàn) | 用于對(duì)象內(nèi)的子對(duì)象屬性 |
比較常用的注解:
| 注解 | 適用類型 | 說(shuō)明 | 示例 |
|---|---|---|---|
| @Future | Date | 日期必須在未來(lái) | @Future(message="截止時(shí)間無(wú)效") |
| @Digits | 數(shù)值類型 | 整數(shù)位和小數(shù)位限制 | @Digits(integer=3, fraction=2) |
| @Negative | 數(shù)值類型 | 必須為負(fù)數(shù) | 常用于財(cái)務(wù)系統(tǒng) |
| @NotEmpty | 集合/字符串 | 集合非空或字符串長(zhǎng)度>0 | 比@NotBlank更寬松 |
組合注解(自定義)
// 自定義手機(jī)號(hào)校驗(yàn)注解
@Documented
@Constraint(validatedBy = PhoneValidator.class)
@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
public @interface Phone {
String message() default "手機(jī)號(hào)格式不合法";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
// 校驗(yàn)邏輯實(shí)現(xiàn)
public class PhoneValidator implements ConstraintValidator<Phone, String> {
private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value != null && PHONE_PATTERN.matcher(value).matches();
}
}使用場(chǎng)景:復(fù)用企業(yè)特定校驗(yàn)規(guī)則(如公司內(nèi)部員工編號(hào))
五、@Valid 與 @Validated 區(qū)別
| 特性 | @Valid | @Validated |
|---|---|---|
| 標(biāo)準(zhǔn)規(guī)范 | JSR-303/JSR-349 標(biāo)準(zhǔn) | Spring 框架擴(kuò)展 |
| 分組校驗(yàn) | 不支持 | 支持 |
| 嵌套校驗(yàn) | 需要顯式添加@Valid | 不自動(dòng)支持嵌套校驗(yàn) |
| 作用位置 | 方法參數(shù)、成員屬性 | 類、方法、參數(shù) |
六、高頻問(wèn)題與最佳實(shí)踐
常見(jiàn)問(wèn)題排查
注解不生效:
- 檢查是否忘記添加
@Valid/@Validated - 確保校驗(yàn)對(duì)象未被
@RequestBody等注解錯(cuò)誤包裹
嵌套校驗(yàn)失敗:
- 確認(rèn)在嵌套對(duì)象屬性上添加了
@Valid
性能優(yōu)化建議
- 避免過(guò)度校驗(yàn):在Controller層做基礎(chǔ)校驗(yàn),復(fù)雜邏輯放到Service層
- 使用分組校驗(yàn):減少不必要的校驗(yàn)開(kāi)銷
高級(jí)技巧
// 動(dòng)態(tài)分組校驗(yàn)(根據(jù)請(qǐng)求參數(shù)決定校驗(yàn)組)
@Validated
@RestController
public class UserController {
@PostMapping("/users")
public String createUser(
@RequestParam String type,
@Validated({Default.class, type.equals("vip") ? VipGroup.class : Default.class})
@RequestBody User user
) {
return "success";
}
}實(shí)現(xiàn)原理:利用Spring EL表達(dá)式動(dòng)態(tài)選擇校驗(yàn)組
七、重點(diǎn)總結(jié)
優(yōu)先使用場(chǎng)景:
- 優(yōu)先使用
@Valid的場(chǎng)景:嵌套對(duì)象校驗(yàn)、與非Spring框架整合 - 優(yōu)先使用
@Validated的場(chǎng)景:需要分組校驗(yàn)、校驗(yàn)Service層方法參數(shù)
配置要點(diǎn):
- 要想使用
@Valid必須添加spring-boot-starter-validation依賴 - 校驗(yàn)失敗會(huì)拋出
MethodArgumentNotValidException
最佳實(shí)踐:
// 嵌套校驗(yàn)示例
public class Order {
@Valid // 必須顯式添加
private User user;
}
// 分組校驗(yàn)示例
@Validated(UpdateGroup.class)
public void updateUser(@RequestBody User user) {}校驗(yàn)流程:
請(qǐng)求參數(shù) → 注解聲明 → 自動(dòng)校驗(yàn) → 異常處理(@ControllerAdvice)
相較傳統(tǒng)參數(shù)校驗(yàn)優(yōu)勢(shì):
- 減少70%以上的參數(shù)校驗(yàn)代碼量
- 通過(guò)統(tǒng)一異常處理實(shí)現(xiàn)錯(cuò)誤響應(yīng)的標(biāo)準(zhǔn)化
- 提升代碼可維護(hù)性和團(tuán)隊(duì)協(xié)作效率
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- SpringBoot集成Aviator實(shí)現(xiàn)參數(shù)校驗(yàn)的示例代碼
- Springboot項(xiàng)目參數(shù)校驗(yàn)方式(Validator)
- SpringBoot參數(shù)校驗(yàn)之@Valid與@Validated的用法與場(chǎng)景
- SpringBoot如何實(shí)現(xiàn)各種參數(shù)校驗(yàn)
- SpringBoot之controller參數(shù)校驗(yàn)詳解
- SpringBoot參數(shù)校驗(yàn)及原理全面解析
- SpringBoot參數(shù)校驗(yàn)的一些實(shí)戰(zhàn)應(yīng)用
相關(guān)文章
Java之SpringCloud nocos注冊(cè)中心講解
這篇文章主要介紹了Java之SpringCloud nocos注冊(cè)中心講解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
Java多線程Future松獲取異步任務(wù)結(jié)果輕松實(shí)現(xiàn)
這篇文章主要為大家介紹了Java多線程Future松獲取異步任務(wù)結(jié)果輕松實(shí)現(xiàn)方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
Java實(shí)現(xiàn)公用實(shí)體類轉(zhuǎn)Tree結(jié)構(gòu)
這篇文章主要為大家介紹了一個(gè)Java工具類,可以實(shí)現(xiàn)Java公用實(shí)體類轉(zhuǎn)Tree結(jié)構(gòu),文中的示例代碼簡(jiǎn)潔易懂,感興趣的小伙伴可以參考一下2024-10-10
使用springboot整合mybatis-plus實(shí)現(xiàn)數(shù)據(jù)庫(kù)的增刪查改示例
這篇文章主要介紹了使用springboot整合mybatis-plus實(shí)現(xiàn)數(shù)據(jù)庫(kù)的增刪查改示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
通過(guò)實(shí)例了解JavaBean開(kāi)發(fā)及使用過(guò)程解析
這篇文章主要介紹了通過(guò)實(shí)例了解JavaBean開(kāi)發(fā)及使用過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
一篇文中細(xì)看Java多線程的創(chuàng)建方式
隨著計(jì)算機(jī)的配置越來(lái)越高,我們需要將進(jìn)程進(jìn)一步優(yōu)化,細(xì)分為線程,充分提高圖形化界面的多線程的開(kāi)發(fā),這篇文章主要給大家介紹了如何通過(guò)一篇文中細(xì)看Java多線程的創(chuàng)建方式,需要的朋友可以參考下2021-07-07

