JAVA中通過(guò)自定義注解進(jìn)行數(shù)據(jù)驗(yàn)證的方法
前言
最近為了工作也為了更加深入了解掌握java注解的使用,決定自定義注解來(lái)實(shí)現(xiàn)數(shù)據(jù)驗(yàn)證。
API開(kāi)發(fā)中經(jīng)常會(huì)遇到一些對(duì)請(qǐng)求數(shù)據(jù)進(jìn)行驗(yàn)證的情況,這時(shí)候如果使用注解就有兩個(gè)好處,一是驗(yàn)證邏輯和業(yè)務(wù)邏輯分離,代碼清晰,二是驗(yàn)證邏輯可以輕松復(fù)用,只需要在要驗(yàn)證的地方加上注解就可以。
Java提供了一些基本的驗(yàn)證注解,比如@NotNull、@Size,但是更多情況下需要自定義驗(yàn)證邏輯,這時(shí)候就可以自己實(shí)現(xiàn)一個(gè)驗(yàn)證注解,方法很簡(jiǎn)單,僅需要兩個(gè)東西:
- 一個(gè)自定義的注解,并且指定驗(yàn)證器
- 一個(gè)驗(yàn)證器的實(shí)現(xiàn)
自定義驗(yàn)證注解
考慮有一個(gè)API,接收一個(gè)Student對(duì)象,并希望對(duì)象里的age域的值是奇數(shù),這時(shí)候就可以創(chuàng)建以下注解:
@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è)注解要作用在什么地方,可以是對(duì)象、域、構(gòu)造器等,因?yàn)橐饔迷赼ge域上,因此這里選擇FIELD
- @Retention指明了注解的生命周期,可以有SOURCE(僅保存在源碼中,會(huì)被編譯器丟棄),CLASS(在class文件中可用,會(huì)被VM丟棄)以及RUNTIME(在運(yùn)行期也被保留),這里選擇了生命周期最長(zhǎng)的RUNTIME
- @Constraint是最關(guān)鍵的,它表示這個(gè)注解是一個(gè)驗(yàn)證注解,并且指定了一個(gè)實(shí)現(xiàn)驗(yàn)證邏輯的驗(yàn)證器
- message()指明了驗(yàn)證失敗后返回的消息,此方法為@Constraint要求
- groups()和payload()也為@Constraint要求,可默認(rèn)為空,詳細(xì)用途可以查看@Constraint文檔
創(chuàng)建驗(yàn)證器
有了注解之后,就需要一個(gè)驗(yàn)證器來(lái)實(shí)現(xiàn)驗(yàn)證邏輯:
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; } }
其中:
- 驗(yàn)證器有兩個(gè)類(lèi)型參數(shù),第一個(gè)是所屬的注解,第二個(gè)是注解作用地方的類(lèi)型,這里因?yàn)樽饔迷赼ge上,因此這里用了Integer
- initialize()可以在驗(yàn)證開(kāi)始前調(diào)用注解里的方法,從而獲取到一些注解里的參數(shù),這里用不到
- isValid()就是判斷是否合法的地方
應(yīng)用注解
注解和驗(yàn)證器創(chuàng)建好之后,就可以使用注解了:
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; } }
@RestController public class StudentResource { @PostMapping("/student") public String addStudent(@Valid @RequestBody Student student) { return "Student Created"; } }
在需要啟用驗(yàn)證的地方加上@Valid注解,這時(shí)候如果請(qǐng)求里的Student年齡不是奇數(shù),就會(huì)得到一個(gè)400響應(yīng):
{ "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" }
也可以手動(dòng)來(lái)處理錯(cuò)誤,加上一個(gè)BindingResult來(lái)接收驗(yàn)證結(jié)果即可:
@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"; } }
這時(shí)候如果驗(yàn)證出錯(cuò),便只會(huì)返回一個(gè)狀態(tài)為200,內(nèi)容為Age Must Be Odd的響應(yīng)。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
springBoot快速訪(fǎng)問(wèn)工程目錄下的靜態(tài)資源
springboot工程,是沒(méi)有webapp文件夾的,靜態(tài)文件放在src/main/resources/static文件夾下即可,模板文件放在src/main/resources/templates下,本文給大家介紹springBoot快速訪(fǎng)問(wèn)工程目錄下的靜態(tài)資源的相關(guān)知識(shí),一起看看吧2021-06-06一文帶你了解Spring中Bean名稱(chēng)加載機(jī)制
這篇文章主要給大家介紹了Spring Framework如何從使用注解定義的Bean元數(shù)據(jù)中獲取到Bean的名稱(chēng),文中通過(guò)代碼示例給大家介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2024-01-01spring boot下mybatis配置雙數(shù)據(jù)源的實(shí)例
這篇文章主要介紹了spring boot下mybatis配置雙數(shù)據(jù)源的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09如何基于Springboot完成新增員工功能并設(shè)置全局異常處理器
最近工作中遇到了做一個(gè)管理員工信息的功能,下面這篇文章主要給大家介紹了關(guān)于如何基于Springboot完成新增員工功能并設(shè)置全局異常處理器的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-11-11使用springboot對(duì)外部靜態(tài)資源文件的處理操作
這篇文章主要介紹了使用springboot對(duì)外部靜態(tài)資源文件的處理操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08java使用Logback配置輸出日志內(nèi)容到文件示例代碼
這篇文章主要介紹了java?Logback輸出日志內(nèi)容到文件,要將logger.info的信息輸出到文件,您可以使用Logback配置,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09SpringBoot2 task scheduler 定時(shí)任務(wù)調(diào)度器四種方式
這篇文章主要介紹了SpringBoot2 task scheduler 定時(shí)任務(wù)調(diào)度器四種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03