SpringBoot利用validation實現(xiàn)數(shù)據(jù)校驗完整指南
1. 前言
在我們?nèi)粘i_發(fā)中,后端經(jīng)常需要對請求參數(shù)進行校驗。比如注冊用戶時,用戶名不能為空、密碼長度要在 6~16 之間、郵箱必須符合格式等等,如果我們不做校驗,臟數(shù)據(jù)就可能進入數(shù)據(jù)庫,造成業(yè)務(wù)問題;如果校驗方式不合理,代碼又會變得臃腫
相信很多小伙伴還在 Controller 代碼中寫大量重復(fù)的 if-else 判斷,既冗余又難維護?。ㄈ绻阋彩沁@樣操作,那一定要看完本篇文章)
下面博主介紹一下Spring Boot 提供的 Validation(基于 JSR 303/380 規(guī)范)讓我們能通過注解的方式優(yōu)雅地完成參數(shù)校驗,極大地提升了開發(fā)效率和代碼可讀性
2. 沒有使用 Validation 的傳統(tǒng)寫法
下面我們先看看沒用 Validation 的“土法校驗”,再對比一下用了注解后的優(yōu)雅寫法。當(dāng)不使用數(shù)據(jù)校驗框架時,我們通常會在 Controller 中手動校驗參數(shù),代碼會像這樣:
場景:創(chuàng)建用戶接口
定義接受參數(shù)對象UserDto
// UserDTO實體類
class UserDto {
private String name;
private Integer age;
private String email;
// getter和setter省略
}
要求:用戶名不能為空,長度5-10;郵箱格式必須正確;年齡在18-60之間
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/add")
public String addUser(UserDto user) {
// 手動校驗參數(shù)
if (user.getName() == null || user.getName().trim().isEmpty()) {
return "用戶名不能為空";
}
if (user.getName().length() < 5 || user.getName().length() > 10) {
return "用戶名長度必須在5-10之間";
}
if (user.getAge() == null) {
return "年齡不能為空";
}
if (user.getAge() < 18 || user.getAge() > 60) {
return "年齡必須在18-60之間";
}
if (user.getEmail() == null || user.getEmail().trim().isEmpty()) {
return "郵箱不能為空";
}
if (!user.getEmail().matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$")) {
return "郵箱格式不正確";
}
// 業(yè)務(wù)邏輯處理
return "用戶添加成功";
}
}
可以看出上述寫法的缺點:
- 代碼冗長,不利于維護
- 每個接口都要寫重復(fù)的校驗邏輯
- 校驗邏輯和業(yè)務(wù)邏輯耦合,不夠優(yōu)雅
3. 使用 Validation 的優(yōu)雅寫法
我們可以在實體類上加注解,把校驗規(guī)則聲明在模型上,讓 Spring 自動完成校驗
Maven 依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
UserDto對象加上注解
import javax.validation.constraints.*;
public class UserDto {
@NotBlank(message = "用戶名不能為空")
@Size(min = 2, max = 10, message = "用戶名長度必須在{min}-{max}之間")
private String username;
@NotBlank(message = "郵箱不能為空")
@Email(message = "郵箱格式不正確") // 自帶郵箱格式校驗,無需自己寫正則!
private String email;
@NotNull(message = "年齡不能為空")
@Min(value = 0, message = "年齡最小為{value}")
@Max(value = 150, message = "年齡最大為{value}")
private Integer age;
// 省略 Getter 和 Setter...
}
在Controller參數(shù)前加@Valid或@Validated注解
import javax.validation.Valid;
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/add")
// 關(guān)鍵一步:在 @RequestBody 前加上 @Valid 注解
public String addUser(@Valid @RequestBody UserDto user) {
// 只需關(guān)注核心業(yè)務(wù)
System.out.println("用戶創(chuàng)建成功: " + user);
return "success";
}
}
通過上述使用 validation 改造,Spring 會自動對 UserDto 的字段進行校驗,當(dāng)請求參數(shù)不滿足規(guī)則時,Spring Boot 會自動拋出 MethodArgumentNotValidException 異常,不會進入這個方法體。但我們不能直接給用戶返回異常棧,需要統(tǒng)一處理
4. 全局異常處理(友好返回錯誤信息)
剛才我們已經(jīng)說過了參數(shù)校驗不滿足規(guī)則,系統(tǒng)會拋出MethodArgumentNotValidException ,那么我們就可以通過 @RestControllerAdvice 捕獲 MethodArgumentNotValidException,來實現(xiàn)統(tǒng)一返回錯誤信息
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 處理實體校驗異常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, Object> handleValidException(MethodArgumentNotValidException e) {
Map<String, Object> errorResult = new HashMap<>();
errorResult.put("code", 400);
errorResult.put("message", "參數(shù)校驗失敗");
// 從異常對象中拿到具體的錯誤信息
// 這里只取第一個錯誤信息,也可以全部返回
String defaultMessage = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
errorResult.put("data", defaultMessage);
return errorResult;
}
}
最后我們可以使用Postman或curl測試,觀察接口返回的JSON異常數(shù)據(jù)
5. 常用校驗注解
| 注解 | 功能說明 |
|---|---|
| @NotNull | 值不能為null |
| @NotBlank | 字符串不能為空(trim后長度>0) |
| @NotEmpty | 集合、數(shù)組、Map、String不能為空 |
| @Size(min=, max=) | 檢查字符串、集合、數(shù)組大小 |
| @Min(value) | 數(shù)字最小值 |
| @Max(value) | 數(shù)字最大值 |
| 校驗郵箱格式 | |
| @Pattern(regexp=) | 正則表達式匹配 |
| @Positive | 正數(shù) |
| @Future | 日期必須在未來 |
| @Past | 日期必須在過去 |
6. 分組校驗
當(dāng)同一個實體類在不同場景下有不同的校驗規(guī)則時,比如新增時ID應(yīng)為空,而更新時ID不能為空,這時就需要分組校驗
定義分組接口(標(biāo)記接口)
public interface CreateGroup {} // 創(chuàng)建分組
public interface UpdateGroup {} // 更新分組
在實體上指定分組
繼續(xù)改造一下我們的UserDto,這時候需要增加id字段
public class UserDto {
@Null(groups = CreateGroup.class, message = "創(chuàng)建時ID必須為空")
@NotNull(groups = UpdateGroup.class, message = "更新時ID不能為空")
private Long id;
@NotBlank(message = "用戶名不能為空", groups = {CreateGroup.class, UpdateGroup.class})
private String username;
// ... 其他字段
}
在Controller中使用@Validated指定分組
@PostMapping("/create")
public String create(@Validated(CreateGroup.class) @RequestBody UserDto user) {
// ... 創(chuàng)建邏輯
}
@PostMapping("/update")
public String update(@Validated(UpdateGroup.class) @RequestBody UserDto user) {
// ... 更新邏輯
}
7. 結(jié)語
通過使用 Spring Boot Validation,我們可以告別繁瑣的手動參數(shù)校驗,讓代碼更加簡潔、優(yōu)雅、易維護。希望本文能幫助你在項目中更好地應(yīng)用數(shù)據(jù)校驗機制,提升開發(fā)效率和代碼質(zhì)量,是開發(fā)中必不可少的利器!
到此這篇關(guān)于SpringBoot利用validation實現(xiàn)數(shù)據(jù)校驗完整指南的文章就介紹到這了,更多相關(guān)SpringBoot validation校驗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決idea找不到類could not find artifact問題
本文總結(jié)了解決Java項目中找不到類的問題的常見解決方案,包括刷新Maven項目、清理IDEA緩存、Maven Clean Install、重新Package、解決依賴沖突和手動導(dǎo)入依賴包等方法2025-01-01
Java設(shè)置httponly?cookie的實現(xiàn)示例
本文主要介紹了Java設(shè)置httponly?cookie的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
Java實現(xiàn)的計算最大下標(biāo)距離算法示例
這篇文章主要介紹了Java實現(xiàn)的計算最大下標(biāo)距離算法,涉及java針對數(shù)組的遍歷、運算等相關(guān)操作技巧,需要的朋友可以參考下2018-02-02

