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

自定义元注解将方法上的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){
    
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
可以使用 Java 的反射机制和自定义注解来实现该功能,以下是一个示例代码: 首先,定义一个自定义注解 `DefaultValue`,用于标识需要设置默认值的属性: ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface DefaultValue { String value() default ""; } ``` 然后,在需要设置默认值的属性上加上 `@DefaultValue` 注解: ```java public class User { private String name; @DefaultValue("18") private int age; // 省略 getter 和 setter 方法 } ``` 最后,在后端接收对象的代码中,使用反射机制遍历对象的所有属性,如果某个属性被标记为 `@DefaultValue`,且其值为 `null`,则设置其默认值: ```java public void processUser(User user) throws IllegalAccessException { Class<?> clazz = user.getClass(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(DefaultValue.class)) { field.setAccessible(true); Object value = field.get(user); if (value == null) { DefaultValue defaultValue = field.getAnnotation(DefaultValue.class); String defaultValueStr = defaultValue.value(); Class<?> fieldType = field.getType(); if (fieldType == int.class || fieldType == Integer.class) { field.set(user, Integer.parseInt(defaultValueStr)); } else if (fieldType == long.class || fieldType == Long.class) { field.set(user, Long.parseLong(defaultValueStr)); } else if (fieldType == float.class || fieldType == Float.class) { field.set(user, Float.parseFloat(defaultValueStr)); } else if (fieldType == double.class || fieldType == Double.class) { field.set(user, Double.parseDouble(defaultValueStr)); } else if (fieldType == boolean.class || fieldType == Boolean.class) { field.set(user, Boolean.parseBoolean(defaultValueStr)); } else { field.set(user, defaultValueStr); } } } } } ``` 以上代码中,我们使用 `field.isAnnotationPresent(DefaultValue.class)` 判断某个属性是否被标记为 `@DefaultValue`,然后使用 `field.setAccessible(true)` 将其设置为可访问,最后使用 `field.get(user)` 获取其值,如果值为 `null`,则使用反射设置该属性的默认值。 需要注意的是,我们需要判断该属性的类型,然后根据类型将默认值换成相应的类型。以上代码只实现了对基本数据类型字符串类型的支持,如果需要支持其他类型,可以在代码中添加相应的处理逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值