背景
自定义注解实现字段有条件的判空,例如Student有三个字段name、age、sex;name、age不能为空,sex只有当age=18时不能为空(可能例子不是很符合实际场景,只为实现说明)
代码实现
1、新建自动以注解类
基本元注解含义请自行学习@Target、@Retention、@Documented、@Inherited。本例@ConditionalNotEmpty注解有三个参数message、conditionFiledName、contionString,含义分别为错误提示信息、判断依据的字段名称、判断条件(如本例中如果age=18,则sex不能为空)。可以自行设置参数默认值,如果参数没有默认值则在使用注解时必须要明确传递参数值
package com.atguigu.springcloud.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ConditionalNotEmpty {
//错误提示信息
String message();
//判断依据的字段名称
String conditionFiledName() default "";
//判断条件,如本例中 18
String contionString() default "";
}
2、新建Student类
建议使用lombok注解减少代码量,可以看到注解的参数message必须赋值,否则会报错,conditionFiledName、contionString在自定义注解中已经执行默认值为"",所有不明确赋值也不会报错。在sex字段使用注解的含义为如果age=18则sex不能为空
package com.atguigu.springcloud.annotation;
import lombok.Data;
@Data
public class Student {
@ConditionalNotEmpty(message = "name不能为空")
private String name;
@ConditionalNotEmpty(message = "age不能为空")
private String age;
@ConditionalNotEmpty(message = "sex不能为空",conditionFiledName = "age",contionString = "18")
private String sex;
public Student(String name, String age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
3、新建ConditionalNotEmptyExplain类
利用反射解析注解,详细注释如下代码。实际开发中可以直接调用也可以使用AOP去判空
package com.atguigu.springcloud.annotation;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
public class ConditionalNotEmptyExplain {
public static <T> void validate(T t) throws IllegalAccessException, NoSuchFieldException {
// 获取当前对象所有字段信息
Field[] declaredFields = t.getClass().getDeclaredFields();
for (Field field : declaredFields) {
// 判断字段是否被注解 ConditionalNotEmpty 解释
if (field.isAnnotationPresent(ConditionalNotEmpty.class)) {
// 功能是启用或禁用安全检查,设置为true
field.setAccessible(true);
// field.get(t)获取当前字段值,如果有值则判断下个字段
if (field.get(t) != null) {
continue;
}
// field.get(t)获取当前字段值,如果为空则继续判断是否需要条件判断
ConditionalNotEmpty annotation = field.getAnnotation(ConditionalNotEmpty.class);
// 获取message参数值
String message = annotation.message();
// 获取conditionFiledName参数值
String conditionFiledName = annotation.conditionFiledName();
// 获取contionString参数值
String contionString = annotation.contionString();
// 如果conditionFiledName和contionString不为空,则直接打印出message
if (StringUtils.isNotEmpty(conditionFiledName) && StringUtils.isNotEmpty(contionString)) {
// 根据依赖字段conditionFiledName(比如本例字段age),反射得到这个依赖字段的信息
Field conditionFiled = t.getClass().getDeclaredField(conditionFiledName);
conditionFiled.setAccessible(true);
// 获取当前依赖字段值(比如本例字段age)
Object conditionFiledValue = conditionFiled.get(t);
// 进行判断如果当前依赖字段值等于注解参数contionString值则满足条件(本例当前字段age值10等于注解参数contionString10,则打印)
if (conditionFiledValue != null && contionString.equals(conditionFiledValue)) {
if (field.get(t) == null) {
System.out.println("当"+conditionFiled.getName()+"为"+conditionFiledValue+"时"+message);
continue;
}
}
}else {
// 如果conditionFiledName和contionString为空,则直接打印出message
System.out.println(message);
}
}
}
}
}
4、测试结果
// 1、当name、age、sex都为空时
public class TestMain {
public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
Student student = new Student(null,null,null);
ConditionalNotEmptyExplain.validate(student);
}
}
控制台打印结果:
name不能为空
age不能为空
// 2、当age、sex为空时
public class TestMain {
public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
Student student = new Student("zhangsan",null,null);
ConditionalNotEmptyExplain.validate(student);
}
}
控制台打印结果:
age不能为空
// 3、当age=18、sex为空时
public class TestMain {
public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
Student student = new Student("zhangsan","18",null);
ConditionalNotEmptyExplain.validate(student);
}
}
控制台打印结果:
当age为18时sex不能为空
// 4、当age=19、sex为空时
public class TestMain {
public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
Student student = new Student("zhangsan","18",null);
ConditionalNotEmptyExplain.validate(student);
}
}
控制台打印结果:
没有打印结果