一、背景
我们用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 {//要校验的dtoClass<?> 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 {@Autowiredprivate 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类型的项目里面超好用!