基于Spring Validation實現(xiàn)全局參數(shù)校驗異常處理的示例詳解
在 Spring Boot 項目開發(fā)中,接口參數(shù)校驗是保障數(shù)據(jù)合法性的關(guān)鍵環(huán)節(jié)。Spring Validation 提供了便捷的參數(shù)校驗?zāi)芰Γ之惓L幚韯t能統(tǒng)一規(guī)范校驗失敗的響應(yīng)格式,提升接口友好性。本文將完整介紹如何整合兩者,實現(xiàn)高效的參數(shù)校驗與異常處理。
一、核心依賴引入
首先需在pom.xml(Maven)或build.gradle(Gradle)中引入 Spring Validation 核心依賴,用于支持參數(shù)校驗注解。
Maven 依賴
<!-- Spring Validation 核心依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Web依賴(若項目已引入可忽略) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
二、參數(shù)校驗基礎(chǔ)使用(注解式校驗)
通過在實體類字段或接口方法參數(shù)上添加校驗注解,實現(xiàn) “聲明式” 參數(shù)校驗,無需手動編寫校驗邏輯。
1. 實體類參數(shù)校驗(常用場景)
在接收請求體的 DTO(數(shù)據(jù)傳輸對象)中,為字段添加@NotNull、@NotBlank、@Min等注解,定義校驗規(guī)則。
import jakarta.validation.constraints.*; // Spring Boot 3.x使用jakarta包,2.x為javax包
public class UserDTO {
// 主鍵非空
@NotNull(message = "用戶ID不能為空")
private Long id;
// 用戶名非空且長度1-20
@NotBlank(message = "用戶名不能為空")
@Size(min = 1, max = 20, message = "用戶名長度需在1-20字符之間")
private String username;
// 年齡18-60歲
@Min(value = 18, message = "年齡不能小于18歲")
@Max(value = 60, message = "年齡不能大于60歲")
private Integer age;
// 郵箱格式合法
@Email(message = "郵箱格式不正確")
private String email;
// getter/setter省略
}
2. 接口方法添加校驗觸發(fā)注解
在 Controller 接口的參數(shù)前添加@Valid(或@Validated)注解,觸發(fā) Spring Validation 的校驗邏輯。
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import jakarta.validation.Valid;
@RestController
public class UserController {
// 新增用戶接口,@Valid觸發(fā)UserDTO的校驗
@PostMapping("/user/add")
public String addUser(@Valid @RequestBody UserDTO userDTO) {
// 校驗通過后執(zhí)行業(yè)務(wù)邏輯
return "用戶新增成功:" + userDTO.getUsername();
}
}
三、全局參數(shù)校驗異常處理(核心)
若參數(shù)校驗失敗,Spring 會拋出MethodArgumentNotValidException(請求體參數(shù)校驗失?。┗?code>ConstraintViolationException(路徑 / 請求參數(shù)校驗失?。Mㄟ^@RestControllerAdvice定義全局異常處理器,統(tǒng)一捕獲并處理這些異常,返回標準化響應(yīng)。
1. 定義標準化響應(yīng)體
先創(chuàng)建統(tǒng)一的接口響應(yīng)類,確保異常響應(yīng)與正常響應(yīng)格式一致。
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Result<T> {
// 狀態(tài)碼:200成功,400參數(shù)錯誤,500系統(tǒng)錯誤
private Integer code;
// 提示信息
private String message;
// 響應(yīng)數(shù)據(jù)(成功時返回,失敗時為null)
private T data;
// 靜態(tài)工廠方法:參數(shù)錯誤響應(yīng)
public static Result<Void> paramError(String message) {
return new Result<>(400, message, null);
}
// 靜態(tài)工廠方法:成功響應(yīng)(可省略)
public static <T> Result<T> success(T data) {
return new Result<>(200, "success", data);
}
}
2. 全局異常處理器實現(xiàn)
通過@RestControllerAdvice注解標識全局異常處理類,用@ExceptionHandler指定捕獲的異常類型,編寫處理邏輯。
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import java.util.stream.Collectors;
// 全局異常處理,作用于所有@RestController
@RestControllerAdvice
public class GlobalValidationExceptionHandler {
/**
* 處理請求體參數(shù)校驗失?。ˊRequestBody + @Valid)
* 異常類型:MethodArgumentNotValidException
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Void> handleMethodArgumentNotValid(MethodArgumentNotValidException e) {
// 提取所有字段的錯誤信息(如多個參數(shù)校驗失敗,合并提示)
String errorMsg = e.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage) // 獲取每個字段的自定義錯誤信息
.collect(Collectors.joining(";")); // 用“;”分隔多個錯誤
// 返回參數(shù)錯誤響應(yīng)
return Result.paramError(errorMsg);
}
/**
* 處理路徑參數(shù)/請求參數(shù)校驗失敗(如@RequestParam/@PathVariable)
* 異常類型:ConstraintViolationException
*/
@ExceptionHandler(ConstraintViolationException.class)
public Result<Void> handleConstraintViolation(ConstraintViolationException e) {
// 提取參數(shù)錯誤信息
String errorMsg = e.getConstraintViolations().stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.joining(";"));
return Result.paramError(errorMsg);
}
}
四、效果測試與常見場景
1. 請求體參數(shù)校驗失敗示例
向/user/add接口發(fā)送如下請求(用戶名空、年齡 17):
{
"id": 1,
"username": "",
"age": 17,
"email": "invalid-email"
}
全局異常處理器會返回響應(yīng):
{
"code": 400,
"message": "用戶名不能為空;年齡不能小于18歲;郵箱格式不正確",
"data": null
}
2. 路徑參數(shù)校驗失敗示例
若接口用@PathVariable接收參數(shù)并校驗:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import jakarta.validation.constraints.Min;
@GetMapping("/user/{userId}")
public String getUser(@Min(value = 1, message = "用戶ID不能小于1") @PathVariable Long userId) {
return "查詢用戶ID:" + userId;
}
訪問/user/0時,會返回:
{
"code": 400,
"message": "用戶ID不能小于1",
"data": null
}
五、關(guān)鍵注意事項
- 注解包路徑問題:Spring Boot 3.x 版本校驗注解從
javax.validation.constraints遷移到jakarta.validation.constraints,引入依賴時需注意包名匹配,避免類找不到異常。 - @Valid 與 @Validated 區(qū)別:
@Valid是 JSR-380 標準注解,支持嵌套校驗(如 DTO 內(nèi)部包含另一個需要校驗的對象);@Validated是 Spring 擴展注解,支持分組校驗,兩者均可觸發(fā)校驗。 - 分組校驗擴展:若同一 DTO 在不同接口需不同校驗規(guī)則(如 “新增用戶” 無需 ID,“修改用戶” 必須有 ID),可通過 “分組” 實現(xiàn),需在注解中指定
groups屬性,并在@Validated中指定分組。
通過以上步驟,可實現(xiàn) “注解式參數(shù)校驗 + 全局異常統(tǒng)一處理” 的完整方案,既減少重復(fù)校驗代碼,又保證接口響應(yīng)格式統(tǒng)一,大幅提升開發(fā)效率與接口健壯性。
到此這篇關(guān)于基于Spring Validation實現(xiàn)全局參數(shù)校驗異常處理的示例詳解的文章就介紹到這了,更多相關(guān)Spring Validation參數(shù)校驗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot結(jié)合prometheus自定義埋點方式
文章介紹了如何使用Spring Actuator、Prometheus和Grafana進行度量統(tǒng)計收集、數(shù)據(jù)收集和數(shù)據(jù)展示,以監(jiān)控生成環(huán)境機器的性能指標和業(yè)務(wù)數(shù)據(jù)指標2024-12-12
Mybatis-plus實現(xiàn)join連表查詢的示例代碼
mybatis-plus在連表查詢上是不行的,如果需要連表查詢,就得乖乖的去寫xml文件了,本文介紹了mybatis-plus-join框架,它支持連表查詢,感興趣的可以了解一下2023-08-08
springmvc處理模型數(shù)據(jù)ModelAndView過程詳解
這篇文章主要介紹了springmvc處理模型數(shù)據(jù)ModelAndView過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-01-01
為什么在foreach循環(huán)中JAVA集合不能添加或刪除元素
今天給大家?guī)淼奈恼率顷P(guān)于Java的相關(guān)知識,文章圍繞著為什么在foreach循環(huán)中JAVA集合不能添加或刪除元素展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下2021-06-06

