一、背景
我们用json对象作为接收参数的包装器,最后要转化为dto进行业务操作,操作之前要做非空校验,我们可以实现2个注解来实现这个通用的操作。@NotNullField @CheckNull
二、思路
1.实现@NotNullField注解,注解标记在dto字段名上面
@Target(ElementType.FIELD) // 目标为字段
@Retention(RetentionPolicy.RUNTIME) // 运行时可用
public @interface NotNullField {
String fieldName() default ""; // 可自定义字段名
String message() default "字段不能为空"; // 默认错误消息
}
2.实现@CheckNull注解,注解标记在调用方法上面,这个是要接受dto.class的
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckNull {
//要校验的dto
Class<?> value();
}
三、代码实现
1.@NotNullField,这个我实现了一个静态方法
/**
* 校验标注了非空字段的dto
* @param obj
* @throws NullParamsException
*/
public static void validateNotNull(Object obj) throws NullParamsException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(NotNullField.class)) {
field.setAccessible(true); // 允许访问私有字段
try {
Object value = field.get(obj);
if (value == null) {
NotNullField annotation = field.getAnnotation(NotNullField.class);
throw new NullParamsException(
String.format("验证错误: %s - %s", annotation.fieldName(), annotation.message())
);
}else{
//如果是集合类型递归调用
//感觉递归调用 是一个危险的方式 大数据量会导致栈内存溢出 先进行实验
//代码中如果有集合的方式必须 业务自己提取出来data自己去遍历校验
if(Collections.class.isAssignableFrom(field.getType())){
field.setAccessible(true); // 允许访问私有字段
Collection<?> collection = (Collection<?>) value;
Iterator<?> iterator = collection.iterator();
while (iterator.hasNext()) {
Object item = iterator.next();
// 处理集合中的每个对象
validateNotNull(item);
}
}
}
} catch (IllegalAccessException e) {
throw new RuntimeException("访问错误", e);
}
}
}
// 移动到父类 要支持继承
clazz = clazz.getSuperclass();
}
}
2.@CheckNull,这里的@Order 注解是标记注解起作用的顺序,因为我还写了其他校验注解
@Component
@Aspect
@Order(2)
public class CheckNullAspect {
@Autowired
private MyAutoConfig myAutoConfig;
/**
* 环绕处理
* 连接点
* 注解的全限定名称
* @return 结果
* @throws Throwable 异常
*/
@Pointcut(value = "@annotation(具体包)")
public void checkAround() throws Throwable {
}
@Before("checkAround()")
public void around(JoinPoint proceedingJoinPoint) throws Throwable {
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
//获取操作
CheckNull annotation = method.getAnnotation(CheckNull.class);
Class<?> dtoClass = annotation.value();
// 获取入参
Object[] objects = proceedingJoinPoint.getArgs();
if (Objects.nonNull(objects) && objects.length > 0) {
JSONObject jsonObject = (JSONObject) objects[0];
Object dto = jsonObject.toJavaObject(dtoClass);
CheckUtil.validateNotNull(dto);
}
}
}
四、后记
自定义注解实现在spring类型的项目里面超好用!
标签:dto,NotNullField,校验,field,字段,为空,Dto,注解,public From: https://www.cnblogs.com/lovefoolself/p/18515318