出发点:开发中发现前端传来的枚举的index数值没有进行校验,传入不存在的index值也能传到后端
1、直接在后端业务代码中进行处理枚举的校验侵入性比较大,复用性不高
2、模仿lombok的@NotNull注解,直接在domin中进行注解,代码侵入性不高,复用性比较高,直接将message报给前端
——————————————————————————————————————————
|注解基本知识|
元注解(注解的注解)(copy自zhuanlan.zhihu.com/p/111762882)
@Target
- @Target元注解表示我们的注解作用的范围,可以是类,方法,方法参数变量等,同样也是通过枚举类ElementType表达作用类型
- @Target(ElementType.TYPE) 作用接口、类、枚举、注解
- @Target(ElementType.FIELD) 作用属性字段、枚举的常量
- @Target(ElementType.METHOD) 作用方法
- @Target(ElementType.PARAMETER) 作用方法参数
- @Target(ElementType.CONSTRUCTOR) 作用构造函数
- @Target(ElementType.LOCAL_VARIABLE)作用局部变量
- @Target(ElementType.ANNOTATION_TYPE)作用于注解(@Retention注解中就使用该属性)
- @Target(ElementType.PACKAGE) 作用于包
- @Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8加入)
- @Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class (jdk1.8加入)
@Retention
- @Retention表示注解存在的生命周期,是保留在源码(编译期)时期,还是字节码(类加载)或者运行期(JVM中运行)时期。在@Retention注解中使用枚举RetentionPolicy来表示注解保留时期
- @Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中不包含 (.java)
- @Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得(.class)
- @Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到(内存中的字节码)
- 自定义注解必须选择@Retention(RetentionPolicy.RUNTIME)
首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。
一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解,比如@Deprecated使用RUNTIME注解
如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;
如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,使用SOURCE 注解。
@Documented
- Document的意思是文档。它的作用是能够将注解中的元素包含到 Javadoc 中去。
@Constraint(validatedBy = EnumValidator.class)
指定实际校验的类
以下是代码实现
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {EnumValidator.class})
public @interface EnumValid {
String message() default "";
// 作用参考@Validated和@Valid的区别
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/**
* 目标枚举类
*/
Class<?> target() default Class.class;
/**
* 是否忽略空值
*/
boolean ignoreEmpty() default true;
}
//实现ConstraintValidator接口
public class EnumValidator implements ConstraintValidator<EnumValid, Integer> {
private EnumValid annotation;
@Override
public void initialize(EnumValid constraintAnnotation) {
annotation = constraintAnnotation;
}
@Override
public boolean isValid(Integer val, ConstraintValidatorContext constraintValidatorContext) {
//获取注解的target值
Class<?> target = annotation.target();
//获取注解的ignoreEmpty值
boolean ignoreEmpty = annotation.ignoreEmpty();
if ( target.isEnum() && (val != null || !ignoreEmpty) ){
//获取对应枚举类的枚举值域
Object[] enumValues = target.getEnumConstants();
//如果前端传来的值在枚举值域内则返回true
for( Object enumValue:enumValues ){
if( enumValue.toString().equals(String.valueOf(val)) ){
return true;
}
}
}else{
return true;
}
//前端传来的值不在枚举值域内则返回false
return false;
}
}
@EnumValid(target = ScreenProtectorPictureSizeTypeEnum.class,message = "图片尺寸类型状态值错误")
private Integer pictureSizeType;