自定义元注解将方法上的String类型字段 NULL 转为 “”

为什么博主会想到写这么一个元注解呢,因为博主在实际开发中,使用的是Springboot JPA,在Repository中写HQL或者SQL的时候总会有一些条件查询,String也是必然会用到的类型,但如果数据库没有对String类型的默认值做处理,那么DB的默认值则会是NULL,对于NULL的处理有几种方式。

对于值为NULL的String字段的处理方式

  • 在Controller层的DTO中给默认值
public class UserDTO{ 
	private String userName = "";
	private String email = "";
	private String address = "";
}
  • 在Service层一个个String类型的字段判空
public List<User> findUserBySearch(String userName,String email,String address){ 
        userName = StringUtils.isEmpty(userName)?"":userName;
        email = StringUtils.isEmpty(email)?"":email;
        address = StringUtils.isEmpty(address)?"":address;
        return UserRepository.findUserBySearch(userName,email,address);
    }
  • 在Repository层为每一个需要Like且可能为NULL的字段加上额外的条件
@Query(value = "select u from User u where (userName like %?1% or '' like %?1%) and (email like %?1% or '' like %?1%) and (address like %?1% or '' like %?1%) ")
List<User> findBySearch(String userName,String email,String address)

以上所想到的办法都让代码显示很不美观,对于博主这样有这种有代码洁癖还喜欢“偷懒”的人是一定不能忍的,所以博主想到用元注解来代替这一系列无脑且重复的操作
以下代码基于JDK1.8

元注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StringEmptyFilter { 
    String[] values() default { };//方法上的字段名称
}

AOP处理类

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
@Component
@Aspect
@Slf4j
public class StringEmptyFilterAspect { 
    @Around("@annotation(StringEmptyFilter)")
    public Object stringEmptyFilterHandler(ProceedingJoinPoint point) throws Throwable { 
        Object[] args = point.getArgs();//入参
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Method method = methodSignature.getMethod();//AOP代理方法
        Method targetMethod = point.getTarget().getClass().getMethod(method.getName(), method.getParameterTypes());//真实方法
        StringEmptyFilter annotation = targetMethod.getAnnotation(StringEmptyFilter.class);//当前方法的注解
        Class<?>[] parameterTypes = targetMethod.getParameterTypes();//获取方法入参字段类型
// new LocalVariableTableParameterNameDiscoverer().getParameterNames(targetMethod);//获取方法入参真实变量名①
        ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
        String[] parameterNames = pnd.getParameterNames(targetMethod);//获取方法入参真实变量名②
        if (annotation == null) { 
            //如果没有@StringEmptyFilter注解 不做处理
            return point.proceed(args);
        }
        if (annotation.values().length != 0) { 
            //如果指定了需要过滤的字符串字段,则只过滤指定的字符串字段
            String[] values = annotation.values();
            Arrays.stream(values).forEach(strField -> { 
                for (int i = 0; i < parameterNames.length; i++) { 
                    if (Objects.equals(parameterNames[i], strField) && parameterTypes[i] == String.class) { 
                        args[i] = StringUtils.isEmpty(args[i]) ? "" : args[i];
                        break;
                    }
                }
            });
            return point.proceed(args);
        } else { 
            //如果没指定需要过滤的字符串字段,则过滤所有String类型的字段
            for (int i = 0; i < parameterTypes.length; i++) { 
                if (parameterTypes[i] == String.class) { 
                    args[i] = StringUtils.isEmpty(args[i]) ? "" : args[i];
                }
            }
            return point.proceed(args);
        }
    }
}

Demo

//场景1:直接使用注解 默认将方法上所有的String的NULL转为""
@StringEmptyFilter
public void doSomething(String userName,String eamil,Integer age,Date birth){ 
    
}
//场景2:指定字段转化(指定字段不存在||指定字段类型不为String则跳过不做处理)
@StringEmptyFilter(values = { "userName"})
public void doSomething(String userName,String eamil,Integer age,Date birth){ 
    
}

本文地址:https://blog.csdn.net/qq_37957369/article/details/110820538