自定义元注解将方法上的String类型字段 NULL 转为 ““
程序员文章站
2022-04-15 17:45:05
自定义元注解讲方法上的String类型字段 NULL 转为 “”元注解@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface StringEmptyFilter { String[] values() default {};//方法上的字段名称}AOP处理类import lombok.extern.slf4j.Slf4j;import org.aspect...
自定义元注解将方法上的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