前言
最近為了工作也為了更加深入了解掌握java注解的使用,決定自定義注解來實現(xiàn)數(shù)據(jù)驗證。
api開發(fā)中經(jīng)常會遇到一些對請求數(shù)據(jù)進行驗證的情況,這時候如果使用注解就有兩個好處,一是驗證邏輯和業(yè)務邏輯分離,代碼清晰,二是驗證邏輯可以輕松復用,只需要在要驗證的地方加上注解就可以。
java提供了一些基本的驗證注解,比如@notnull、@size,但是更多情況下需要自定義驗證邏輯,這時候就可以自己實現(xiàn)一個驗證注解,方法很簡單,僅需要兩個東西:
- 一個自定義的注解,并且指定驗證器
- 一個驗證器的實現(xiàn)
自定義驗證注解
考慮有一個api,接收一個student對象,并希望對象里的age域的值是奇數(shù),這時候就可以創(chuàng)建以下注解:
1
2
3
4
5
6
7
8
|
@target (elementtype.field) @retention (retentionpolicy.runtime) @constraint (validatedby = agevalidator. class ) public @interface odd { string message() default "age must be odd" ; class <?>[] groups() default {}; class <? extends payload>[] payload() default {}; } |
其中:
- @target指明這個注解要作用在什么地方,可以是對象、域、構(gòu)造器等,因為要作用在age域上,因此這里選擇field
- @retention指明了注解的生命周期,可以有source(僅保存在源碼中,會被編譯器丟棄),class(在class文件中可用,會被vm丟棄)以及runtime(在運行期也被保留),這里選擇了生命周期最長的runtime
- @constraint是最關鍵的,它表示這個注解是一個驗證注解,并且指定了一個實現(xiàn)驗證邏輯的驗證器
- message()指明了驗證失敗后返回的消息,此方法為@constraint要求
- groups()和payload()也為@constraint要求,可默認為空,詳細用途可以查看@constraint文檔
創(chuàng)建驗證器
有了注解之后,就需要一個驗證器來實現(xiàn)驗證邏輯:
1
2
3
4
5
6
7
8
9
10
|
public class agevalidator implements constraintvalidator<odd,integer> { @override public void initialize(odd constraintannotation) { } @override public boolean isvalid(integer age, constraintvalidatorcontext constraintvalidatorcontext) { return age % 2 != 0 ; } } |
其中:
- 驗證器有兩個類型參數(shù),第一個是所屬的注解,第二個是注解作用地方的類型,這里因為作用在age上,因此這里用了integer
- initialize()可以在驗證開始前調(diào)用注解里的方法,從而獲取到一些注解里的參數(shù),這里用不到
- isvalid()就是判斷是否合法的地方
應用注解
注解和驗證器創(chuàng)建好之后,就可以使用注解了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public class student { @odd private int age; private string name; public string getname() { return name; } public void setname(string name) { this .name = name; } public int getage() { return age; } public void setage( int age) { this .age = age; } } |
1
2
3
4
5
6
7
|
@restcontroller public class studentresource { @postmapping ( "/student" ) public string addstudent( @valid @requestbody student student) { return "student created" ; } } |
在需要啟用驗證的地方加上@valid注解,這時候如果請求里的student年齡不是奇數(shù),就會得到一個400響應:
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
|
{ "timestamp" : "2018-08-15t17:01:44.598+0000" , "status" : 400 , "error" : "bad request" , "errors" : [ { "codes" : [ "odd.student.age" , "odd.age" , "odd.int" , "odd" ], "arguments" : [ { "codes" : [ "student.age" , "age" ], "arguments" : null , "defaultmessage" : "age" , "code" : "age" } ], "defaultmessage" : "age must be odd" , "objectname" : "student" , "field" : "age" , "rejectedvalue" : 12 , "bindingfailure" : false , "code" : "odd" } ], "message" : "validation failed for object='student'. error count: 1" , "path" : "/student" } |
也可以手動來處理錯誤,加上一個bindingresult來接收驗證結(jié)果即可:
1
2
3
4
5
6
7
8
9
10
|
@restcontroller public class studentresource { @postmapping ( "/student" ) public string addstudent( @valid @requestbody student student, bindingresult validateresult) { if (validateresult.haserrors()) { return validateresult.getallerrors().get( 0 ).getdefaultmessage(); } return "student created" ; } } |
這時候如果驗證出錯,便只會返回一個狀態(tài)為200,內(nèi)容為age must be odd的響應。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:https://www.cnblogs.com/xz816111/p/9484902.html