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