aop实现公共字段自动填充

aop实现公共字段自动填充

参考视频:黑马苍穹外卖项目

1. 问题

在数据库表中有创建时间、修改时间字段。

在service层,对数据库操作需要每次手动new一个LocalDateTime对象生成当前时间,比较繁琐。所以我们考虑使用aop来自动完成这些任务。

aop实现公共字段自动填充_第1张图片
aop实现公共字段自动填充_第2张图片

2. 实现步骤

2.1 声明注解

自定义一个注解,value用来说明连接点进行的数据库操作类型。通常为insert、update,我们将其定义为枚举类型,方便重复使用。

加上这个注解的方法,我们就会进行aop切入,进行功能扩充。

枚举类型说明数据库操作类型

/**
 * 数据库操作类型
 */
public enum OperationType {

    /**
     * 更新操作
     */
    UPDATE,

    /**
     * 插入操作
     */
    INSERT

}

定义注解加载service层的方法上

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 公共字段填充注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    OperationType value();
}

2.2 定义通知类

通知类使用aop、反射实现字段填充的具体功能

主要目的就是更改参数的某些成员变量值,这里是为了更新上面数据库中的四个字段。

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 实现公共字段自动填充
 */
@Component
@Aspect
@Slf4j
public class AutoFillAspect {

    /**
     * 切入点
     * 哪里需要加上功能
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut(){};

    /**
     * 前置通知,要实习哪些功能
     * @param joinPoint
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) {
        log.info("开始进行公共字段填充");

        // 获取当前拦截的方法进行的数据库操作类型(注解value值)
        MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //方法签名对象
        Method method = signature.getMethod();//获取方法
        AutoFill autoFill = method.getAnnotation(AutoFill.class);//获取注解
        OperationType value = autoFill.value(); //获取注解对值,也就是数据库操作类型

        // 获取拦截方法的参数
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            return;
        }

        Object entity = args[0];
        // 准备赋值的数据
        LocalDateTime now = LocalDateTime.now();
        Long id = BaseContext.getCurrentId();

        // 根据数据库操作类型,利用反射对参数进行赋值
        try {
            if (OperationType.INSERT.equals(value)) {
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                setCreateTime.invoke(entity, now);
                setUpdateTime.invoke(entity, now);
                setCreateUser.invoke(entity, id);
                setUpdateUser.invoke(entity, id);
            } else if (OperationType.UPDATE.equals(value)) {
                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 exception) {
            exception.printStackTrace();
        }

    }

}

2.3 加上注解

dao层中加入注解,一劳永逸

/**
 * 修改分类
 * @param category
 */
@AutoFill(OperationType.UPDATE)
void update(Category category);

你可能感兴趣的:(springboot,反射,java,springboot)