JAVA里自定义注解来进行数据验证 2019-09-24

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<OddInteger> { @Override public void initialize(Odd constraintAnnotation) { } @Override public boolean isValid(Integer age ConstraintValidatorContext constraintValidatorContext) { return age % 2 != 0 }}

其中:

验证器有两个类型参数,第一个是所属的注解,第二个是注解作用地方的类型,这里因为作用在age上,因此这里用了Integerinitialize()可以在验证开始前调用注解里的方法,从而获取到一些注解里的参数,这里用不到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的响应。

Copyright © 2019 百乐宫网站 All Rights Reserved
王茜
地址:山东省烟台市幸福中路209号
全国统一热线:15131939126