標籤:bind 使用 .class val ali nts erro integer 情況
API開發中經常會遇到一些對請求資料進行驗證的情況,這時候如果使用註解就有兩個好處,一是驗證邏輯和商務邏輯分離,代碼清晰,二是驗證邏輯可以輕鬆複用,只需要在要驗證的地方加上註解就可以。
Java提供了一些基本的驗證註解,比如@NotNull、@Size,但是更多情況下需要自訂驗證邏輯,這時候就可以自己實現一個驗證註解,方法很簡單,僅需要兩個東西:
自訂驗證註解
考慮有一個API,接收一個Student對象,並希望對象裡的age域的值是奇數,這時候就可以建立以下註解:
@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指明這個註解要作用在什麼地方,可以是對象、域、構造器等,因為要作用在age域上,因此這裡選擇FIELD
@Retention指明了註解的生命週期,可以有SOURCE(僅儲存在源碼中,會被編譯器丟棄),CLASS(在class檔案中可用,會被VM丟棄)以及RUNTIME(在運行期也被保留),這裡選擇了生命週期最長的RUNTIME
@Constraint是最關鍵的,它表示這個註解是一個驗證註解,並且指定了一個實現驗證邏輯的驗證器
message()指明了驗證失敗後返回的訊息,此方法為@Constraint要求
groups()和payload()也為@Constraint要求,可預設為空白,詳細用途可以查看@Constraint文檔
建立驗證器
有了註解之後,就需要一個驗證器來實現驗證邏輯:
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; }}
其中:
- 驗證器有兩個型別參數,第一個是所屬的註解,第二個是註解作用地方的類型,這裡因為作用在
age上,因此這裡用了Integer
initialize()可以在驗證開始前調用註解裡的方法,從而擷取到一些註解裡的參數,這裡用不到
isValid()就是判斷是否合法的地方
應用註解
註解和驗證器建立好之後,就可以使用註解了:
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; }}
@RestControllerpublic class StudentResource { @PostMapping("/student") public String addStudent(@Valid @RequestBody Student student) { return "Student Created"; }}
在需要啟用驗證的地方加上@Valid註解,這時候如果請求裡的Student年齡不是奇數,就會得到一個400響應:
{ "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來接收驗證結果即可:
@RestControllerpublic 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"; }}
這時候如果驗證出錯,便只會返回一個狀態為200,內容為Age Must Be Odd的響應。
JAVA裡自訂註解來進行資料驗證