瞧瞧別人家的引數校驗,那叫一個優雅!

👉 這是一個或許對你有用的社群
🐱 一對一交流/面試小冊/簡歷最佳化/求職解惑,歡迎加入芋道快速開發平臺知識星球。下面是星球提供的部分資料:
👉這是一個或許對你有用的開源專案
國產 Star 破 10w+ 的開源專案,前端包括管理後臺 + 微信小程式,後端支援單體和微服務架構。
功能涵蓋 RBAC 許可權、SaaS 多租戶、資料許可權、商城、支付、工作流、大屏報表、微信公眾號、ERPCRMAI 大模型等等功能:
  • Boot 多模組架構:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 微服務架構:https://gitee.com/zhijiantianya/yudao-cloud
  • 影片教程:https://doc.iocoder.cn
【國內首批】支援 JDK 17/21 + SpringBoot 3.3、JDK 8/11 + Spring Boot 2.7 雙版本 

對於開發人員來說,對使用者輸入的引數或者系統引數做校驗,是日常工作之一。
很多小夥伴在寫介面的時候,可能都會碰到一個問題:引數校驗應該怎麼寫?
比如,開發一個使用者註冊介面,需要校驗以下條件:
  • 使用者名稱不能為空,長度在 3 到 20 個字元之間;
  • 密碼不能為空,長度至少為 8 個字元;
  • 年齡必須是正整數,不能超過 120;
  • 郵箱必須符合標準格式。
乍一看,這種校驗邏輯看起來很簡單嘛,直接寫幾個 if 就完事了。
但真的這麼簡單嗎?
接下來我們就從傳統的引數校驗入手,看看問題出在哪,然後再聊聊 Spring Boot 中如何優雅地實現引數校驗 ,希望對你會有所幫助。

一、傳統引數校驗的問題

很多人可能會直接在 Controller 裡手寫校驗邏輯,比如下面這個程式碼:
@RestController
@RequestMapping

(

"/api/users"

)

publicclassUserController

{

@PostMapping

(

"/register"

)

public ResponseEntity<String> register(@RequestBody Map<String, Object> request)

{

        String username = (String) request.get(

"username"

);

if

 (username == 

null

 || username.length() < 

3

 || username.length() > 

20

) {

return

 ResponseEntity.badRequest().body(

"使用者名稱不能為空,且長度必須在3到20之間"

);

        }
        String password = (String) request.get(

"password"

);

if

 (password == 

null

 || password.length() < 

8

) {

return

 ResponseEntity.badRequest().body(

"密碼不能為空,且長度至少為8個字元"

);

        }
        Integer age = (Integer) request.get(

"age"

);

if

 (age == 

null

 || age <= 

0

 || age > 

120

) {

return

 ResponseEntity.badRequest().body(

"年齡必須是正整數,且不能超過120"

);

        }

return

 ResponseEntity.ok(

"註冊成功!"

);

    }

}

這段程式碼乍一看沒什麼問題,但如果仔細分析,會發現一堆隱患:
  1. 程式碼冗餘 :校驗邏輯散落在 Controller 裡,寫起來麻煩,後期維護更是災難。
  2. 重複勞動 :類似的校驗邏輯可能會出現在多個接口裡,導致程式碼重複度極高。
  3. 使用者體驗差 :返回的錯誤資訊不統一、不規範,前端開發還得猜使用者輸入到底哪兒錯了。
  4. 擴充套件性差 :萬一某天需要加新的校驗規則,你可能要到處改程式碼。
所以,這種手寫引數校驗的方式,在簡單場景下勉強能用,但如果業務變複雜,問題會越來越多。
那麼問題來了,那有沒有更優雅的方式來處理這些問題呢?
答:當然是有的。
基於 Spring Boot + MyBatis Plus + Vue & Element 實現的後臺管理系統 + 使用者小程式,支援 RBAC 動態許可權、多租戶、資料許可權、工作流、三方登入、支付、簡訊、商城等功能
  • 專案地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 影片教程:https://doc.iocoder.cn/video/

二、Spring Boot 的引數校驗機制

在 Spring Boot 中,我們可以使用 Hibernate Validator (Bean Validation 的參考實現)來實現引數校驗。
它的核心思路是:把校驗邏輯從業務程式碼裡抽離出來,用註解的方式宣告校驗規則
接下來我們一步步來看怎麼實現。

1. 使用註解進行引數校驗

首先,定義一個用於接收使用者註冊引數的 DTO 物件:
@Data
publicclassUserRegistrationRequest

{

@NotNull

(message = 

"使用者名稱不能為空"

)

@Size

(min = 

3

, max = 

20

, message = 

"使用者名稱長度必須在3到20之間"

)

private

 String username;

@NotNull

(message = 

"密碼不能為空"

)

@Size

(min = 

8

, message = 

"密碼長度至少為8個字元"

)

private

 String password;

@NotNull

(message = 

"年齡不能為空"

)

@Min

(value = 

1

, message = 

"年齡必須是正整數"

)

@Max

(value = 

120

, message = 

"年齡不能超過120"

)

private

 Integer age;

@Email

(message = 

"郵箱格式不正確"

)

private

 String email;

}

這裡我們用了幾個常見的校驗註解:
  • @NotNull:欄位不能為空;
  • @Size:限制字串長度;
  • @Min@Max:限制數值範圍;
  • @Email:校驗郵箱格式。
這些註解由 Hibernate Validator 提供,基本涵蓋了日常開發中的大部分校驗需求。
然後,在 Controller 中這樣寫:
@RestController
@RequestMapping

(

"/api/users"

)

publicclassUserController

{

@PostMapping

(

"/register"

)

public ResponseEntity<String> register(@Valid @RequestBody UserRegistrationRequest request)

{

return

 ResponseEntity.ok(

"註冊成功!"

);

    }

}

注意這裡的 @Valid 註解,它的作用是告訴 Spring:對請求引數進行校驗

2. 統一處理校驗錯誤

如果前端傳的引數不合法,Spring 會丟擲一個 MethodArgumentNotValidException 異常。預設情況下,這個異常返回的資訊不太友好,可能是這樣的:

{

"timestamp"

"2024-01-01T12:00:00.000+00:00"

,

"status"

400

,

"error"

"Bad Request"

,

"message"

"Validation failed for object='userRegistrationRequest'. Error count: 2"

,

"path"

"/api/users/register"

}

為了提升使用者體驗,我們可以用全域性異常處理器來統一格式化錯誤資訊:
@RestControllerAdvice
publicclassGlobalExceptionHandler

{

@ExceptionHandler

(MethodArgumentNotValidException

.

class

)

publicResponseEntity

<

Map

<

String

String

>> 

handleValidationException

(

MethodArgumentNotValidExceptionex

{

        Map<String, String> errors = 

new

 HashMap<>();

        ex.getBindingResult().getFieldErrors().forEach(error -> {

            errors.put(error.getField(), error.getDefaultMessage());

        });

return

 ResponseEntity.badRequest().body(errors);

    }

}

現在,當引數校驗失敗時,返回的錯誤資訊會變成這樣:

{

"username"

"使用者名稱長度必須在3到20之間"

,

"password"

"密碼不能為空"

}

清晰又直觀,使用者一看就明白自己錯在哪兒了。
基於 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的後臺管理系統 + 使用者小程式,支援 RBAC 動態許可權、多租戶、資料許可權、工作流、三方登入、支付、簡訊、商城等功能
  • 專案地址:https://github.com/YunaiV/yudao-cloud
  • 影片教程:https://doc.iocoder.cn/video/

三、應對複雜場景的高階技巧

1. 分組校驗

有些場景下,不同的介面對引數的校驗規則是不一樣的,比如:
  • 註冊介面要求 usernamepassword 是必填項;
  • 更新介面只需要校驗 emailage
這種情況下,可以用 分組校驗 來解決。

定義校驗分組

publicinterfaceRegisterGroup

{}

publicinterfaceUpdateGroup

{}

在欄位上指定分組

publicclassUserRequest

{

@NotNull

(groups = RegisterGroup

.classmessage

"使用者名稱不能為空"

)

@Size

(min = 

3

, max = 

20

, groups = RegisterGroup

.classmessage

"使用者名稱長度必須在3到20之間"

)

private

 String username;

@NotNull

(groups = RegisterGroup

.classmessage

"密碼不能為空"

)

private

 String password;

@Email

(groups = UpdateGroup

.classmessage

"郵箱格式不正確"

)

private

 String email;

@Min

(value = 

1

, groups = UpdateGroup

.classmessage

"年齡必須是正整數"

)

private

 Integer age;

}

在 Controller 中指定分組

@RestController
@RequestMapping

(

"/api/users"

)

publicclassUserController

{

@PostMapping

(

"/register"

)

public ResponseEntity<String> register(@Validated(RegisterGroup.class) @RequestBody UserRequest request) 

{

return

 ResponseEntity.ok(

"註冊成功!"

);

    }

@PutMapping

(

"/update"

)

public ResponseEntity<String> update(@Validated(UpdateGroup.class) @RequestBody UserRequest request) 

{

return

 ResponseEntity.ok(

"更新成功!"

);

    }

}

2. 自定義校驗註解

如果 Hibernate Validator 提供的註解不能滿足需求,還可以自定義校驗註解。例如,校驗手機號格式。

定義註解

@Documented
@Constraint

(validatedBy = PhoneValidator

.

class

)

@

Target

(

{ElementType.FIELD})

@Retention

(RetentionPolicy.RUNTIME)

public@interface

 ValidPhone {

String message()default "手機號格式不正確"

;

    Class<?>[] groups() 

default

 {};

    Class<? extends Payload>[] payload() 

default

 {};

}

實現校驗邏輯

publicclassPhoneValidatorimplementsConstraintValidator<ValidPhoneString

{

privatestaticfinal

 String PHONE_REGEX = 

"^1[3-9]\\d{9}$"

;

@Override
publicbooleanisValid(String value, ConstraintValidatorContext context)

{

return

 value != 

null

 && value.matches(PHONE_REGEX);

    }

}

使用自定義註解

publicclassUserRequest

{

@ValidPhone
private

 String phone;

}

四、總結

優雅的引數校驗不僅能提高程式碼的可維護性,還能顯著提升使用者體驗。
在 Spring Boot 中,透過使用 Hibernate Validator 提供的註解,配合分組校驗、自定義校驗和統一異常處理。
我們可以輕鬆實現簡潔、高效、可擴充套件的引數校驗機制。
優雅的引數校驗的秘籍是:
  1. 註解優先:能用註解解決的校驗,就不要手寫邏輯程式碼。
  2. 分離校驗邏輯:引數校驗應該集中在 DTO 層,避免散落在業務程式碼中。
  3. 全域性統一異常處理:確保錯誤資訊規範化、友好化。
  4. 合理使用分組校驗:根據介面需求靈活調整校驗規則。
  5. 覆蓋邊界條件:透過單元測試驗證校驗邏輯,確保沒有漏網之魚。
如果看了這篇文章有些收穫,記得給我點贊和轉發喔。

歡迎加入我的知識星球,全面提升技術能力。
👉 加入方式,長按”或“掃描”下方二維碼噢
星球的內容包括:專案實戰、面試招聘、原始碼解析、學習路線。
文章有幫助的話,在看,轉發吧。
謝謝支援喲 (*^__^*)

相關文章