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è)務代碼耦合,難以復用
}問題總結:
- 代碼冗余:相同校驗邏輯重復編寫
- 維護困難:校驗規(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);
}
}效果:自動返回結構化錯誤信息(字段名+錯誤描述)
三、@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 | 嵌套對象校驗 | 用于對象內的子對象屬性 |
比較常用的注解:
| 注解 | 適用類型 | 說明 | 示例 |
|---|---|---|---|
| @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ī)則(如公司內部員工編號)
五、@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)選擇校驗組
七、重點總結
優(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é)作效率
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
vue?vxe-table?實現(xiàn)財務記賬憑證的方案
使用?vxe-table?實現(xiàn)財務記賬憑證非常簡單,實現(xiàn)在線實時編輯的記賬憑證、自動合計金額等,這篇文章主要介紹了vue?vxe-table?實現(xiàn)財務記賬憑證的方案,需要的朋友可以參考下2024-12-12
利用Java異常機制實現(xiàn)模擬借書系統(tǒng)
這篇文章主要給大家介紹了利用Java異常機制實現(xiàn)模擬借書系統(tǒng)的相關資料,文中先對java異常機制進行了簡單介紹,而后通過示例代碼介紹了java語言是如何實現(xiàn)一個控制臺版的模擬借書系統(tǒng),需要的朋友可以參考學習,一起來看看吧。2017-04-04
Java關鍵字finally_動力節(jié)點Java學院整理
java關鍵字finally不管是否出現(xiàn)異常,finally子句總是在塊完成之前執(zhí)行。下面通過實現(xiàn)代碼給大家介紹Java關鍵字finally相關知識,需要的的朋友參考下吧2017-04-04

