springboot實現(xiàn)請求參數(shù)驗證的多種方法
注解
設(shè)置依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
注解
以下是 validation-api中提供的可用的注解列表
| 注解 | 含義 |
|---|---|
| @Null | 驗證對象必須為 null |
| @NotNull | 驗證對象不為 null |
| @NotBlank | 驗證字符串不能為空null或"",只能用于字符串驗證 |
| @NotEmpty | 驗證對象不得為空,可用于Map和數(shù)組 |
| @Pattern | 驗證字符串是否滿足正則表達式 |
| @AssertTrue | 驗證 boolean 類型值為 true |
| @AssertFalse | 驗證 boolean 類型值為 false |
| @Min(value) | 驗證數(shù)字的大小是否大于等于指定的值 |
| @Max(value) | 驗證數(shù)字的大小是否小于等于指定的值 |
| @DecimalMin(value) | 驗證數(shù)字的大小是否大于等于指定的值,小數(shù)存在精度 |
| @DecimalMax(value) | 驗證數(shù)字的大小是否小于等于指定的值,小數(shù)存在精度 |
| @Size(max, min) | 驗證對象(字符串、集合、數(shù)組)長度是否在指定范圍之內(nèi) |
| @Digits(integer, fraction) | 驗證數(shù)字是否符合指定格式 |
| @Pattern(value) | 驗證字符串是否符合正則表達式的規(guī)則 |
| @ParameterScriptAssert | 可以在方法參數(shù)級別上執(zhí)行腳本驗證,以驗證傳遞給方法的參數(shù)是否符合指定的條件。該注解可以與 JSR 223 兼容的腳本引擎一起使用,例如 JavaScript、Groovy、Python 等。- script:腳本表達式,用于執(zhí)行參數(shù)驗證。該表達式應(yīng)該返回一個 boolean 類型的值,表示驗證是否通過。- lang:腳本語言的名稱,默認為 "groovy"。 |
| 驗證字符串是否符合電子郵件地址的格式。 | |
| @Future | 驗證一個日期或時間是否在當前時間之后。 |
| @FutureOrPresent | 驗證一個日期或時間是否在當前時間之后或等于當前時間。 |
| @past | 驗證一個日期或時間是否在當前時間之前。 |
| @PastOrPresent | 驗證一個日期或時間是否在當前時間之前或等于當前時間。 |
| @Positive | 驗證數(shù)字是否是正整數(shù),0無效 |
| @PositiveOrZero | 驗證數(shù)字是否是正整數(shù) |
| @Negative | 驗證數(shù)字是否是負整數(shù),0無效 |
| @NegativeOrZero | 驗證數(shù)字是否是負整數(shù) |
以上大致就是validation-api默認提供的參數(shù)驗證注解。示例如下:

另外需要注意的是,在每個注解中基本上都一個分組屬性:Class<?>[] groups() default { };
其作用就是對對象屬性分組,用于在不同的場景下支持不同的參數(shù)驗證。我們來舉一個列子:
比如我們新增和更新數(shù)據(jù)的操作一般都用同一個對象來接收前端傳入?yún)?shù)。那么新增時的Id可能為空,而編輯時的Id不能為空,我們對參數(shù)的驗證規(guī)則是不一樣的。那么怎么實現(xiàn)呢?這里就需要用到我們的groups()了。代碼如下:
@RequestMapping("create")
@ResponseBody
public String create(@RequestBody @Validated(Create.class) User user) {
return "create success";
}
@RequestMapping("update")
@ResponseBody
public String update(@RequestBody @Validated(Update.class) User user) {
return "update success";
}
@Data
public static class User {
@NotBlank(message = "id不能為空", groups = {Update.class})
private String id;
@NotNull(message = "用戶名不能為空", groups = {Create.class, Update.class})
private String username;
@NotNull(message = "密碼不能為空")
private String password;
}
public interface Create {
}
public interface Update {
}
根據(jù)需求,我們在 User 的 id 屬性上標記上 groups = {Update.class},在 username 屬性上標記 groups = {Create.class, Update.class}。則表明我們對id只在 @Validated(Update.class) 時驗證id的值;username 則在 @Validated(Update.class) 或者 @Validated(Create.class) 時都需要驗證。
自定義驗證
首先,定義一個自定義注解,例如 @ValidEnum:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidEnumValidator.class)
public @interface ValidEnum {
String message() default "無效的枚舉值";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<? extends Enum<?>> value();
}
@ValidEnum 注解用于驗證一個枚舉類型的值是否在指定的枚舉類型中,使用 ValidEnumValidator 類對其進行驗證。
接下來,定義一個 ValidEnumValidator 類,實現(xiàn)對 @ValidEnum 注解的驗證邏輯:
public class ValidEnumValidator implements ConstraintValidator<ValidEnum, Object> {
private Set<String> validValues = new HashSet<>();
@Override
public void initialize(ValidEnum constraintAnnotation) {
Class<? extends Enum<?>> enumClass = constraintAnnotation.value();
Enum<?>[] enumValues = enumClass.getEnumConstants();
for (Enum<?> enumValue : enumValues) {
validValues.add(enumValue.name());
}
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
return validValues.contains(value.toString());
}
}
ValidEnumValidator 類實現(xiàn)了 ConstraintValidator 接口,并重寫了 initialize() 和 isValid() 兩個方法。initialize() 方法用于初始化驗證器,獲取枚舉類型的所有枚舉值;isValid() 方法用于實現(xiàn)驗證邏輯,判斷枚舉值是否在指定的枚舉類型中。
最后,在使用 @Validated 注解的 Controller 中,對請求參數(shù)使用自定義的 @ValidEnum 注解進行驗證
@RestController
@Validated
public class UserController {
@GetMapping("/user")
public void getUser(@RequestParam @ValidEnum(value = Gender.class) String gender) {
// 處理請求
}
}
@ValidEnum 注解用于驗證 gender 參數(shù)是否在 Gender 枚舉類型中。如果 gender 參數(shù)的值不在 Gender 枚舉類型中,則會拋出 ConstraintViolationException 異常,并帶有指定的錯誤消息。
需要注意的是,自定義的 Bean Validation 注解需要使用 @Constraint 注解進行標注,并指定對應(yīng)的驗證器類。
在驗證器類中,需要實現(xiàn) ConstraintValidator 接口,并實現(xiàn) initialize() 和 isValid() 方法。在使用自定義注解進行參數(shù)驗證時,需要在對應(yīng)的 Controller 中使用 @Validated 注解進行標注。
有趣的歷史

大家可以看到spring-boot-starter-validation 中依賴的包是 jakarta.validation-api,其命名空間屬于jakarta。jakarta.validation-api 實現(xiàn)的規(guī)范依舊是JSR380,熟悉的小伙伴可能知道其實以前用的是 javax.validation-api。可是為什么現(xiàn)在會是jakarta.validation-api 呢,而不是 javax.validation-api?這中間其實涉及到了太多的商業(yè)上的博弈。有興趣的大家可以自己去了解下,有時間單獨出一篇介紹。
以上就是springboot實現(xiàn)請求參數(shù)驗證的多種方法的詳細內(nèi)容,更多關(guān)于springboot校驗參數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解Java中使用externds關(guān)鍵字繼承類的用法
子類使用extends繼承父類是Java面向?qū)ο缶幊讨械幕A(chǔ)知識,這里我們就來詳解Java中使用externds關(guān)鍵字繼承類的用法,需要的朋友可以參考下2016-07-07
Java中List轉(zhuǎn)Map List實現(xiàn)的幾種姿勢
本文主要介紹了Java中List轉(zhuǎn)Map List實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
Java Map 在put值時value值不被覆蓋的解決辦法
這篇文章主要介紹了Java Map 在put值時value值不被覆蓋的解決辦法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-04-04
java?list和map切割分段的實現(xiàn)及多線程應(yīng)用案例
這篇文章主要為大家介紹了java?list和map切割分段的實現(xiàn)及多線程應(yīng)用案例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12

