SpringBoot项目开发中公共字段的处理

老衲曾是一枝花 / 2024-07-08 / 原文

序言

在SpringBoot项目开发中,会存在许多重复的公共字段,例如:

字段名
create_time 创建时间
update_time 更新时间
create_user 创建操作人
update_user 更新操作人

对于以上四个字段,需要大量的重复代码来实现,比较繁琐、冗余。


一、利用注解+AOP+反射处理公共字段

1.1核心思路

以上四个字段只会出现在更新(update)和插入(insert)操作之上,我们可以创建一个注解,然后在创建一个aop切面,利用aop来捕获注解,再使用反射,将四个字段进行赋值。

1.2代码实现

  • 创建注解
//自定义注解
@Target(ElementType.Method)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill{
    //数据库操作类型
    OperationType value();
}
  • 创建一个枚举,提高代码的可读性和可维护性
public enum OperationType {
	UPDATE,
    INSERT
}
  • 创建一个AOP切面,捕捉注解
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    //切入点
    @Pointcut("excution(* com.yourpackage,*.*(,,)) && @annotation(com.yourpackage.AutoFill)")
    public void autoFillPointCut(){}
}
  • 创建通知,通知中使用反射实现功能
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    //切入点
    @Pointcut("excution(* com.yourpackage,*.*(,,)) && @annotation(com.yourpackage.AutoFill)")
    public void autoFillPointCut(){}
    //前置通知
	@Before("autoFillPointCut()")
    public void autoFill(JointPoint jointpoint){
        try{
            //日志记录
            log.info("开启公共字段自动填充");
            //利用反射获取注解
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);
            OperationType value = autoFill.value();
            //利用反射获取方法上的参数
            Object[] args = joinPoint.getArgs();
            //判断,如果mapper方法上不存在Insert或者Update枚举,或者读取不到参数,则直接结束
            if(value == null || arg){
                return;
            }
            // 获取第一个参数作为实体对象
            Object entity = args[0];
            // 设置创建时间和更新时间
            LocalDateTime now = LocalDateTime.now();
            setFieldIfExists(entity, "createTime", now);
            setFieldIfExists(entity, "updateTime", now);
         	
            // 设置创建用户和更新用户
            Long userId = getUserId(); // 获取当前用户ID的方法,未给出具体的值,自定义
            setFieldIfExists(entity, "createUser", userId);
            setFieldIfExists(entity, "updateUser", userId);
        } catch(Exception e){
            log.error("自动填充失败:{}",e.getMessage());
            e.printStackTrace();
        }
        
        //设置实体字段
        public void setFieldIfExists(Object entity, String filedName, Object vaule) throw NoSuchFieldException, IllegalAccessException {
            try{
                 Filed field = entity.getClass().getDeclaredField(fileName);
            	//避免安全扫描出现警告,覆盖访问控制
           		ReflectionUtils.makeAccessible(field);
            	field.set(entity, value)
            } catch (NoSuchFiledException e){
                log.warn("字段{}不存在,无法设置值",filedName);
            }
        
        } 
        
    }
}