自定义数据校验注解
在后端数据校验时,我们通常使用 javax.validation.constraints 或@Pattern 正则注解来使用,但可能存在一种这样的情况,我们的业务场景很复杂,官方提供的校验注解可能无法为我们提供合适的功能,这时候我们可以考虑采用自定义我们的校验注解。
场景:我们数据库中商品的 showStatus 属性规定 0 为不可见,1 为可见,我们为防止接口被用户滥用传入非法值
一、自定义注解的规范
图中红色部分是我们自定义注解必须使用上的
1、其中第一部分
- @Target 表明该自定义注解可以运用在方法体、成员变量还是构造函数上
- @Retention 表明注解使用的范围:SOURCE/CLASS/RUNTIME,其中 SOURCE 和 CLASS 级别的注解在 VM 中不会保留,在经过 VM 解释后该注解会被移除,而 RUNTIME 表明在被 VM 运行期间仍然保留
- @Constraint 中的 validatedBy 就是我们编写的校验逻辑了——校验器
可以看到 validatedBy 的属性,要求我们校验逻辑必须实现 ConstraintValidator 接口,其中第一个泛型为我们自定义注解的接口,第二个为注解标注
2、第二部分:
- message
我们自定义注解校验不通过时的提示消息,我们模仿官方将校验注解错误信息放置在 resources/ValidationMessages.properties 下,其中 key 为图中的 reference(包路径+message),value 为错误信息
- groups
策略分组
- payload
对于接收者有用的数据
二、实践
1.编写自定义校验注解@interface
@Documented
@Constraint(validatedBy = {ListValueConstraintValidator.class}) // 填写我们的校验器
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListValue {
String message() default "{com.lookstarry.common.valid.ListValue.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int[] vals() default {};
}
resource 下新建 ValidationMessages.properties 文件定义错误信息
com.lookstarry.common.valid.ListValue.message=必须提交指定的值
2.校验器
这里我们不允许 showStatus 出现 0,1 之外的值,实现 ConstraintValidator,?>,其中第一个泛型为校验接口、第二个泛型为校验的类型(即校验注解添加在哪个本体上)
public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
Set<Integer> set = new HashSet<>();
// 初始化方法,获取@ListValue(vals={1,2})的规定值
@Override
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for(int val : vals)
set.add(val);
}
/**
* 判断是否校验成功,interger即待校验的值,检查是否在set中,返回true或false表示校验是否通过
* @param integer 需要校验的值
* @param constraintValidatorContext
* @return
*/
@Override
public boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) {
return set.contains(integer);
}
}
3.校验属性
@NotNull( groups={AddGroup.class, UpdateStatusGroup.class})
@ListValue(vals={0,1}, groups={AddGroup.class, UpdateStatusGroup.class})
private Integer showStatus;
4.测试
三、总结
1)编写自定义校验注解@interface
2)编写自定义校验器 ListValueConstraintValue
3)校验注解关联到自定义校验器 validatedBy={ListValueConstraintValue.class}
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 (CC BY-NC-ND 4.0) 进行许可。