前言
我們這里使用hibernate-validator作為對象參數驗證器,所以在正式介紹SpringBoot參數驗證之前,需要先簡單了解一下hibernate-validator的使用。
hibernate-validator基本使用
引入依賴
1
2
3
4
5
6
7
8
9
|
< dependency > < groupId >org.hibernate</ groupId > < artifactId >hibernate-validator</ artifactId > < version >6.0.17.Final</ version > </ dependency > < dependency > < groupId >javax.validation</ groupId > < artifactId >validation-api</ artifactId > </ dependency > |
編寫需要驗證對象
驗證要求 person對象的用戶名不能為空,年齡在1-150歲之間。
1
2
3
4
5
6
7
8
9
10
|
@Data public class Person { @NotBlank (message = "username must not be null" ) private String username; @Min (value = 1 , message = "age must be >= 1" ) @Max (value = 150 , message = "age must be < 150" ) private Integer age; } |
驗證對象屬性是否符合要求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/** * 對象驗證器 */ public Validator validator() { ValidatorFactory validatorFactory = Validation .byProvider(HibernateValidator. class ) .configure() // 驗證屬性時,如果有一個驗證不通過就返回,不需要驗證所有屬性 .addProperty( "hibernate.validator.fail_fast" , "true" ) .buildValidatorFactory(); return validatorFactory.getValidator(); } @Test public void test() throws Exception { Person person = new Person(); Set<ConstraintViolation<Person>> validate = validator().validate(person); validate.forEach(errorParam -> { System.out.println(errorParam.getMessage()); }); } |
- 我們只需要驗證的對象實例即可完成對象驗證,如果驗證成功,那么返回一個空的集合,如果驗證失敗,會返回具體的驗證失敗的屬性信息。
- 我們輸出驗證失敗的錯誤信息如下:
1
|
username must not be null |
驗證規則
validator提供了大量的驗證注解供我們使用,主要以下幾類:
空/非空驗證
- @Null 元素必須為空
- @NotNull 元素不能為空,空字符串""是非空
以下所有驗證規則都在元素非空的時候才會進行驗證,如果傳入的元素為空,驗證都會通過。
bool
- @AssertTrue 元素必須為true
- @AssertFalse 元素必須為false
時間
- @Future 元素必須是未來的某個時間。
- @FutureOrPresent 元素必須是未來或者現在的某個時間。
- @Past 元素必須是過去的某個時間。
- @PastOrPresent 元素必須是過去或者現在的某個時間。
數學
數字類型可以是BigDecimal、BigInteger、CharSequence 、byte 、 short 、 int 、 long以及它們各自的包裝器類型
- @Digits 元素必須是該數字類型下可以被接受的數值范圍內。
- @Negative 元素必須是負數
- @NegativeOrZero 元素必須小于等于0
- @Positive 元素必須大于0
- @PositiveOrZero 元素必須大于等于0
- @Max,@Min 元素的大小必須符合指定大小
字符串
- @Email 郵箱格式驗證
- @NotBlack 驗證字符串非空,空字符串""也屬于空
- @Pattern 字符串正則驗證
模板正則
validator提供了字符串模板正則的注解,這里提供一份常用的正則表達式,大家可以直接作為常量工具類放到項目里使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
public interface ValidatorPattern { /** * 正則表達式:驗證用戶名 * 1.長度在5-17 * 2.由大寫小寫字母構成 */ String REGEX_USERNAME = "^[a-zA-Z]\w{5,17}$" ; /** * 正則表達式:驗證密碼 * 密碼只能為 6 - 12位數字,字母及常用符號組成。 */ String REGEX_PASSWORD = "^(?=.*[a-zA-Z])(?=.*[0-9])[A-Za-z0-9._~!@#$^&*]{6,12}$" ; /** * 正則表達式:驗證手機號 */ String REGEX_MOBILE = "^[1][34578]\d{9}$" ; /** * 正則表達式:驗證郵箱 */ String REGEX_EMAIL = "^.+@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\.)+[a-zA-Z]{2,}$" ; /** * 正則表達式:驗證漢字 */ String REGEX_CHINESE = "^[\u4e00-\u9fa5],*$" ; /** * 正則表達式:驗證身份證 */ String REGEX_ID_CARD = "(^\d{18}$)|(^\d{15}$)" ; /** * 正則表達式:驗證URL */ String REGEX_URL = "http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?" ; /** * 正則表達式:驗證IP地址 */ String REGEX_IP_ADDR = "(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)" ; /** * 車牌號正則 */ String LICENSE_NO = "^[京津滬渝冀豫云遼黑湘皖魯新蘇浙贛鄂桂甘晉蒙陜吉閩貴粵青藏川寧瓊使領A-Z][A-Z][A-Z0-9]{4,5}[A-Z0-9掛學警港澳]$" ; /** * 姓名校驗 * 1~15位 * 姓名支持空格和中文的點 */ String NAME = "[\u4e00-\u9fa5\u00b7\sA-Za-z]{1,15}$" ; /** * 表情正則 */ String EMOJI = "[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]" ; /** * 數字正則 */ String NUMBER = "^[0-9]*$" ; /** * n位的數字 */ String N_NUMS = "^\d{n}$" ; } |
SpringBoot整合hibernate-validator
引入依賴
這個不再贅述,直接拷貝上文的依賴信息
配置hibernate-validator驗證器對象
在配置類中加入hibernate-validator驗證器對象
1
2
3
4
5
6
7
8
9
10
11
|
@Bean @Primary public Validator validator() { ValidatorFactory validatorFactory = Validation .byProvider(HibernateValidator. class ) .configure() .addProperty( "hibernate.validator.fail_fast" , "true" ) .buildValidatorFactory(); return validatorFactory.getValidator(); } |
借助SpringMVC統一異常處理處理參數校驗結果
配置好后,Spring會自動幫助我們進行參數驗證,如果參數驗證不通過,會拋出BindException異常,我們剛剛手動驗證時的Set<ConstraintViolation<Person>>通過該異常獲取。
我們這可以通過借助SpringMVC統一異常處理的能力處理這個異常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@Slf4j @RestControllerAdvice public class BaseExceptionHandler { /** * spring validation 自動校驗的參數異常 * * @param e BindException * @return R<Void> */ @ResponseStatus (org.springframework.http.HttpStatus.PAYMENT_REQUIRED) @ExceptionHandler (BindException. class ) public R<Void> handler(BindException e) { String defaultMsg = e.getBindingResult().getAllErrors() .stream() .map(ObjectError::getDefaultMessage) .collect(Collectors.joining( ":" )); log.warn(defaultMsg); return R.of(IRespCode.PARAMETERS_ANOMALIES.getCode(), e.getMessage()); } } |
使用參數校驗
我們只需要在校驗參數的方法傳參上標注@Valid或者@Validated都行
1
2
3
4
5
|
@PostMapping ( "register" ) public R<Void> register( @Valid @RequestBody Person person) { // todo return R.ok(); } |
分組校驗
那么@Valid和@Validated有什么區別呢?
Validated比Valid多了一個屬性,這個屬性用于分組校驗使用
1
2
3
4
5
|
public @interface Valid { } public @interface Validated { Class<?>[] value() default {}; } |
啥叫分組校驗?
就是一個實體類中的屬性,在不同的方法傳參中,方法的對屬性的要求不同。
比如說,Person類中有三個屬性,一個是用戶名稱,一個是郵箱,一個是年齡。
在注冊用戶接口中,用戶名稱,郵箱和年齡都不能為空,但是在更改用戶的信息接口中,用戶的年齡和郵箱都可以為空,但是用戶名稱不能為空。
這時候,我們就可以按照對屬性校驗的要求進行分組。
新建一個RegisterGroup分組,該分組只是一個空的接口,僅僅用于標記該校驗要求
1
2
|
public interface RegisterGroup { } |
對校驗要求進行分組
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Data public class Person { @NotBlank (message = "username must not be null" ) private String username; @Min (value = 1 , message = "age must be >= 1" ) @Max (value = 150 , message = "age must be < 150" ) @NotNull (message = "age must not be null" , groups = RegisterGroup. class ) private Integer age; @Email (message = "email format error" ) @NotBlank (message = "email must not be null" ,groups = RegisterGroup. class ) private String email; } |
方法調用時,加入分組要求
1
2
3
4
5
|
@PostMapping ( "register" ) public R<Void> register( @Validated (value = RegisterGroup. class ) @RequestBody Person person) { // todo return R.ok(); } |
這種方式其實不推薦使用,我在標題的時候,也已經標記為“過時”,因為,我們完全可以為這兩個不同的接口創建兩個不同的實體類,而不是使用分組對校驗要求進行隔離,因為實際生產環境中,分組可能有非常多個,這會為我們的程序的可讀性埋下隱患,后期開發人員難以維護,而且對于自動生成API文檔也不友好。大家對于分組只需要了解即可,不建議在項目開發中使用。
總結
到此這篇關于SpringBoot參數校驗的文章就介紹到這了,更多相關SpringBoot參數校驗內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://juejin.cn/post/6999607085998538759