SpringBoot利用validation實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)完整指南
1. 前言
在我們?nèi)粘i_發(fā)中,后端經(jīng)常需要對請求參數(shù)進(jìn)行校驗(yàn)。比如注冊用戶時(shí),用戶名不能為空、密碼長度要在 6~16 之間、郵箱必須符合格式等等,如果我們不做校驗(yàn),臟數(shù)據(jù)就可能進(jìn)入數(shù)據(jù)庫,造成業(yè)務(wù)問題;如果校驗(yàn)方式不合理,代碼又會變得臃腫
相信很多小伙伴還在 Controller 代碼中寫大量重復(fù)的 if-else 判斷,既冗余又難維護(hù)?。ㄈ绻阋彩沁@樣操作,那一定要看完本篇文章)
下面博主介紹一下Spring Boot 提供的 Validation(基于 JSR 303/380 規(guī)范)讓我們能通過注解的方式優(yōu)雅地完成參數(shù)校驗(yàn),極大地提升了開發(fā)效率和代碼可讀性
2. 沒有使用 Validation 的傳統(tǒng)寫法
下面我們先看看沒用 Validation 的“土法校驗(yàn)”,再對比一下用了注解后的優(yōu)雅寫法。當(dāng)不使用數(shù)據(jù)校驗(yàn)框架時(shí),我們通常會在 Controller 中手動校驗(yàn)參數(shù),代碼會像這樣:
場景:創(chuàng)建用戶接口
定義接受參數(shù)對象UserDto
// UserDTO實(shí)體類
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) {
// 手動校驗(yàn)參數(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 "用戶添加成功";
}
}
可以看出上述寫法的缺點(diǎn):
- 代碼冗長,不利于維護(hù)
- 每個接口都要寫重復(fù)的校驗(yàn)邏輯
- 校驗(yàn)邏輯和業(yè)務(wù)邏輯耦合,不夠優(yōu)雅
3. 使用 Validation 的優(yōu)雅寫法
我們可以在實(shí)體類上加注解,把校驗(yàn)規(guī)則聲明在模型上,讓 Spring 自動完成校驗(yàn)
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 = "郵箱格式不正確") // 自帶郵箱格式校驗(yàn),無需自己寫正則!
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 的字段進(jìn)行校驗(yàn),當(dāng)請求參數(shù)不滿足規(guī)則時(shí),Spring Boot 會自動拋出 MethodArgumentNotValidException 異常,不會進(jìn)入這個方法體。但我們不能直接給用戶返回異常棧,需要統(tǒng)一處理
4. 全局異常處理(友好返回錯誤信息)
剛才我們已經(jīng)說過了參數(shù)校驗(yàn)不滿足規(guī)則,系統(tǒng)會拋出MethodArgumentNotValidException ,那么我們就可以通過 @RestControllerAdvice 捕獲 MethodArgumentNotValidException,來實(shí)現(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 {
/**
* 處理實(shí)體校驗(yàn)異常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, Object> handleValidException(MethodArgumentNotValidException e) {
Map<String, Object> errorResult = new HashMap<>();
errorResult.put("code", 400);
errorResult.put("message", "參數(shù)校驗(yàn)失敗");
// 從異常對象中拿到具體的錯誤信息
// 這里只取第一個錯誤信息,也可以全部返回
String defaultMessage = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
errorResult.put("data", defaultMessage);
return errorResult;
}
}
最后我們可以使用Postman或curl測試,觀察接口返回的JSON異常數(shù)據(jù)
5. 常用校驗(yàn)注解
| 注解 | 功能說明 |
|---|---|
| @NotNull | 值不能為null |
| @NotBlank | 字符串不能為空(trim后長度>0) |
| @NotEmpty | 集合、數(shù)組、Map、String不能為空 |
| @Size(min=, max=) | 檢查字符串、集合、數(shù)組大小 |
| @Min(value) | 數(shù)字最小值 |
| @Max(value) | 數(shù)字最大值 |
| 校驗(yàn)郵箱格式 | |
| @Pattern(regexp=) | 正則表達(dá)式匹配 |
| @Positive | 正數(shù) |
| @Future | 日期必須在未來 |
| @Past | 日期必須在過去 |
6. 分組校驗(yàn)
當(dāng)同一個實(shí)體類在不同場景下有不同的校驗(yàn)規(guī)則時(shí),比如新增時(shí)ID應(yīng)為空,而更新時(shí)ID不能為空,這時(shí)就需要分組校驗(yàn)
定義分組接口(標(biāo)記接口)
public interface CreateGroup {} // 創(chuàng)建分組
public interface UpdateGroup {} // 更新分組
在實(shí)體上指定分組
繼續(xù)改造一下我們的UserDto,這時(shí)候需要增加id字段
public class UserDto {
@Null(groups = CreateGroup.class, message = "創(chuàng)建時(shí)ID必須為空")
@NotNull(groups = UpdateGroup.class, message = "更新時(shí)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àn),讓代碼更加簡潔、優(yōu)雅、易維護(hù)。希望本文能幫助你在項(xiàng)目中更好地應(yīng)用數(shù)據(jù)校驗(yàn)機(jī)制,提升開發(fā)效率和代碼質(zhì)量,是開發(fā)中必不可少的利器!
到此這篇關(guān)于SpringBoot利用validation實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)完整指南的文章就介紹到這了,更多相關(guān)SpringBoot validation校驗(yàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java手動實(shí)現(xiàn)常見數(shù)據(jù)結(jié)構(gòu)的示例代碼
本文介紹了Java中常用數(shù)據(jù)結(jié)構(gòu)的特點(diǎn)和Java實(shí)現(xiàn),包括數(shù)組、動態(tài)數(shù)組、鏈表、棧、隊(duì)列、哈希表、樹、堆、圖、集合、雙向隊(duì)列以及自定義鏈表,幫助開發(fā)者選擇合適的數(shù)據(jù)結(jié)構(gòu)以提升代碼效率,感興趣的朋友一起看看吧2025-02-02
java?-jar啟動服務(wù)并輸出日志常用命令小結(jié)
這篇文章主要介紹了在Linux環(huán)境下運(yùn)行JAR包的幾種方法,包括在命令結(jié)尾添加&使其在后臺運(yùn)行,使用nohup使程序不掛斷運(yùn)行,以及將日志輸出到指定文件或丟棄,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-03-03
SpringBoot URL帶有特殊字符([]/{}等),報(bào)400錯誤的解決
這篇文章主要介紹了SpringBoot URL帶有特殊字符([]/{}等),報(bào)400錯誤的解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02
java中應(yīng)用Stack進(jìn)行算術(shù)運(yùn)算的操作
這篇文章主要介紹了java中應(yīng)用Stack進(jìn)行算術(shù)運(yùn)算的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03
Mybatis中Collection集合標(biāo)簽的使用詳解
這篇文章主要介紹了Mybatis中Collection集合標(biāo)簽的使用詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
SpringBoot3整合WebSocket詳細(xì)指南
SpringBoot 3 整合 WebSocket 提供了一種高效的實(shí)時(shí)通信解決方案,通過本文的配置和示例,可以快速實(shí)現(xiàn),感興趣的哦朋友跟隨小編一起看看吧2024-12-12
MyBatis-Plus?ORM數(shù)據(jù)庫和實(shí)體類映射方式
本文詳細(xì)介紹了MyBatis-Plus(MP)在數(shù)據(jù)庫和Java對象映射方面的功能,包括基本映射、主鍵生成策略、復(fù)雜映射(如嵌套對象和集合類型)以及自定義SQL的使用,MP通過豐富的注解和XML配置,簡化了數(shù)據(jù)庫操作,提高了開發(fā)效率2025-01-01
springboot整合Nginx實(shí)現(xiàn)負(fù)載均衡反向代理的方法詳解
這篇文章主要給大家介紹了關(guān)于springboot整合Nginx實(shí)現(xiàn)負(fù)載均衡反向代理的相關(guān)資料,文中通過圖文以及實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01
Java中基于推、拉模式的sentinel規(guī)則持久化詳解
這篇文章主要介紹了Java中基于推、拉模式的sentinel規(guī)則持久化詳解,推模式是sentinelDashboard?把規(guī)則推給Nacos,Nacos監(jiān)聽規(guī)則的變化推給微服務(wù),拉模式是sentinelDashboard?把規(guī)則直接給微服務(wù),?Nacos定時(shí)的同步微服務(wù)端的規(guī)則,需要的朋友可以參考下2023-09-09

