苍穹外卖--公共字段

91 阅读2分钟

公共字段自动填充

问题分析

代码冗余、不便于后期维护

image.png

实现思路

自定义注解 AutoFill,用于标识需要进行公共字段自动填充的方法
自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值
在 Mapper 的方法上加入 AutoFill 注解

image.png 技术点:枚举、注解、AOP、反射

/**
 * 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
 * @author 赵鹏雨
 * @version 1.0
 */
@Target(ElementType.METHOD)//可修饰在方法之上
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    //数据库操作类型     UPDATE,INSERT
    OperationType value();
}

如果注解类型T上不存在@Target元注解,则类型T的注解可以写为除类型参数声明之外的任何声明的修饰符。
如果存在@Target元注解,编译器将强制执行ElementType枚举常量指示的使用限制

  • 它指明了它所修饰的注解使用的范围 如果自定义的注解为含有@Target元注解修饰,那么默认可以是在(除类型参数之外的)任何项之上使用,若有@Target元注解修饰那么根据Value(ElementType枚举常量)的指定的目标进行规定。
  • /** 方法声明 */ METHOD,

指示要保留带注解类型的注解多长时间。如果注释类型声明中不存在保留注释,则保留策略默认为RetentionPolicy.CLASS 。 仅当元注释类型直接用于注释时,保留元注释才有效。如果将元注释类型用作另一个注释类型中的成员类型,则它没有效果。

  • @Retention用来约束注解的生命周期,分别有三个值,源码级别(source)、类文件级别(class)或者运行时级别(runtime)可以通过指定@Retention中的值来实现(值为RetentionPolicy枚举常量)。
/**
 * 自定义切面,实现公共字段自动填充处理逻辑
 * @author 赵鹏雨
 * @version 1.0
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    /**
     * 切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") //(* com.sky.mapper.*.*(..))
    public void autoFillPointCut() {
    }

    /**
     * 前置通知,在通知中进行公共字段赋值
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) {
        log.info("开始进行公共字段自动填充...");

        //获取当前被拦截的方法上的数据库操作类型
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法对象签名
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象
        OperationType operationType = autoFill.value();//数据库操作类型

        //获取到当前被拦截的方法参--实体对象
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            return;
        }
        Object entity = args[0];
        //准备复制数据
        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();

        //根据当前不同的操作类型,为对应的属性通过反射来赋值
        if (operationType == OperationType.INSERT) {
            //为四个公共字段赋值
            try {
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = 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);

                //通过反射为对象赋值
                setCreateTime.invoke(entity,now);
                setCreateUser.invoke(entity,currentId);
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                e.printStackTrace();
            }

        } else if (operationType == OperationType.UPDATE) {
            //为两个公共字段赋值
            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,currentId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
}