公共字段自动填充

77 阅读2分钟

公共字段自动填充功能开发

前言

本文主要利用AOP,反射,枚举等多种技术,通过苍穹外卖项目讲解如何进行公共字段自动填充,从而达到对所有表自动记录创建人、创建时间、更新人、更新日期等数据,而不需要在每个service层重复写代码,达到了降低代码重复度和便于维护的目的.

1. 需求分析

image-20250729132025269

菜品表和分类表中都存在上述这四个公共的字段,导致我们的业务代码中出现了冗余的代码,不方便后期维护

实现思路:

image-20250729132439496

2. 代码开发

  • 自定义注解AutoFill
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    OperationType value();
}

设置Target为METHOD,Retention为RUNTIME,并且枚举类型为UPDATE和INSERT

  • 自定义切面类
@Component
@Slf4j
@Aspect
public class AutoFillAspect {

    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointcut(){}

    @Before("autoFillPointcut()")
    public void autoFill(JoinPoint joinPoint){
        log.info("开始进行公共字段自动填充......");
    }
}

需要在类上面加上@Component注解和@Aspect注解以及Slf4j来记录日志

需要定义切入点为com.sky.mapper包下的任意类和任意方法,方法参数任意,返回值任意,并且只捕获加入了com.sky.annotation.AutoFill注解的方法

  • 通过反射为公共字段赋值
 @Before("autoFillPointcut()")
    public void autoFill(JoinPoint joinPoint) throws NoSuchMethodException {
        log.info("开始进行公共字段自动填充......");
        //获取当前拦截方法的数据库操作类型
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获取方法签名
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获取方法上的AutoFill注解
        OperationType operationType = autoFill.value();//获取操作类型

        //获取当前被拦截的方法的参数,实体对象
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0){
            return;
        }

        Object entity = args[0];

        //获取当前时间和操作人id
        LocalDateTime now = LocalDateTime.now();
        Long id = BaseContext.getCurrentId();

        if (operationType == OperationType.INSERT){
            //设置四个属性
            //为什么使用反射?因为以后操作的表不一定是员工表,类型也不一定是员工类型,所以不能直接把实体类转换成员工类型进行操作
            try {
                Method setCreatTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreatUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //通过反射对属性进行赋值
                setCreatTime.invoke(entity,now);
                setCreatUser.invoke(entity,id);
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,id);
            }catch (Exception e){
                e.printStackTrace();
            }
        }else if (operationType == OperationType.UPDATE){
            //为2个公共字段进行赋值
            try {
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //通过反射对属性进行赋值
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,id);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
  • 为mapper层对应方法加上注解
    • 菜品:
    @AutoFill(value = OperationType.INSERT)
    void insert(Category category);

    @AutoFill(value = OperationType.UPDATE)
    void update(Category category);

员工mapper同上

3. 功能测试

插入数据:

image-20250729154203142

执行结果:

image-20250729154322723

数据库中成功填充公共字段

更新操作同样成功填充公共字段

4. 代码提交

点击Git,点击提交并推送进行提交