如题:使用 @Range 注解来检查 Java Bean的字段,如果字段类型是 String,就检查 String 的长度,如果字段是 int,就检查 int 的范围。
1、定义注解Range
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 下面定义注解,必须设置@Target 和 @Retetion
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) // 可以把注解参数变为数组 @Target({ElementType.FIELD,ElementType.METHOD})
public @interface Range {
int min() default Integer.MIN_VALUE; // 最小值,默认为最小整数值
int max() default Integer.MAX_VALUE; // 最大值,默认为最大整数值
}
# 元注解,一些可以修饰其他注解的注解,称为元注解(meta annotation)。
常用的元注解有
- @Target 可以定义 Annotation 能够被应用于源码的哪些位置
- 类或接口:ElementType.TYPE;
- 字段:ElementType.FIELD;
- 方法:ElementType.METHOD;
- 构造方法:ElementType.CONSTRUCTOR;
- 方法参数:ElementType.PARAMETER。
- @Retention 定义了 Annotation 的声明周期
- 仅编译期:RetentionPolicy.SOURCE;
- 仅class文件:RetentionPolicy.CLASS;
- 运行期:RetentionPolicy.RUNTIME。
如果@Retention 不存在,则该注解默认为Class,但是通常我们定义的注意都是RUNTIME,所以请务必加上这个注解。
- @Repeatable 可以定义 Annotation 是否可重复
定义多个注解之后,我们可以这样使用
@Report(type=1, level="debug")
@Report(type=2, level="warning")
public class Hello {}
- @Inherited 定义子类是否可继承父类定义的 Annotation,@Inherited 仅针对@Target(ElementType.TYPE)类型的 annotation 有效,并且仅针对 class 的继承,对 interface 的继承无效。
2、定义Java Bean
public class MyBen {
public static void main(String[] args) throws IllegalAccessException {
MyBen my = new MyBen();
my.setName("chennan");
System.out.println(my.getName());
my.setAge(3);
RangeValidator.validate(my);
/*
* RangeValidator.validate(my); 这个就是我们生成的拦截器或者校验工具,将实例对象my传入拦截器中
* 拦截器会获取实例对象my的字段方法,如果字段方法有@Range注解,则触发校验
* */
}
@Range(min = 5,max = 10)
public int age;
@Range(min=5,max = 20)
public String name;
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3、定义拦截器RangeValidator
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Stack;
public class RangeValidator {
// 拦截器,用于校验长度。
public static void validate(Object obj) throws IllegalAccessException {
Class<?> cls = obj.getClass();
Field[] fields = cls.getDeclaredFields(); // 获取要检查类的字段
System.out.println(Arrays.toString(fields));
for (Field field:fields){ // 遍历每一个字段,获取注解,再判断类型,然后再对比
if (field.isAnnotationPresent(Range.class)){
field.setAccessible(true);
Range rangeAnnotation = field.getAnnotation(Range.class);
/*
* getAnnotation 方法获取指定注解类型的注解。
* 通过这个方法,可以在运行时检查类、方法或字段上是否存在特定类型的注解,并获取注解的属性值。
* 这对于实现反射和元数据处理非常有用。
* */
Object value = field.get(obj);
/*
* 1、先获取了class,然后利用反射获取class的所有字段信息。
* 2、循环拿到每一个字段,然后用get方法,传入实例对象,来获取实例对象对应字段的值
* */
if (value != null){
if (value instanceof Integer){
int intValue = (int) value;
if (intValue < rangeAnnotation.min() || intValue > rangeAnnotation.max()){
throw new IllegalArgumentException("Field "+ field.getName() + " is out of range. 哈哈int"+ rangeAnnotation.min() + " " + rangeAnnotation.max());
}else if (value instanceof String){
String strValue = (String) value;
if(strValue.length() < rangeAnnotation.min() || strValue.length() > rangeAnnotation.max()){
throw new IllegalArgumentException("Field "+ field.getName() + " is out of range. 哈哈str"+ rangeAnnotation.min() + " " + rangeAnnotation.max());
}
}
}
}
}
}
}
}