AOP如何实现公共字段自动填充

在数据库表的设计中主键id,创建时间create_time,更新时间update_time都是必须的字段,根据实际的需求可能还需要用到创建用户名create_username,和更新用户名update_username这两个字段。

其中的create_time、update_time、create_username、update_username都是属于是表的公共字段,如果每次在进行插入或者更新操作时都要手动赋值是很繁琐的。

通过AOP实现公共字段自动填充,只需给mapper层中的对应方法加上注解即可。

依赖



    org.springframework.boot
    spring-boot-starter-aop

OperateType枚举

枚举数据库操作类型

/**
 * @Description: 数据库操作类型
 * @Author: 翰戈.summer
 * @Date: 2023/11/17
 * @Param:
 * @Return:
 */
public enum OperateType {

    //插入操作
    INSERT,

    //更新操作
    UPDATE

}

AutoFill注解

AutoFill注解,用于标识需要进行公共字段自动填充的方法。

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

/**
 * @Description: 注解,用于标识需要进行公共字段自动填充的方法
 * @Author: 翰戈.summer
 * @Date: 2023/11/18
 * @Param:
 * @Return:
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {

    /**
     * 数据库操作类型,INSERT插入操作,UPDATE更新操作
     */
    OperateType value();

}

AutoFillAspect切面类

切入点一定要写对,这里用到的是前置通知,拦截mapper层接口的方法,获取方法参数进行公共字段填充。

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;

/**
 * @Description: 切面类,实现公共字段自动填充
 * @Author: 翰戈.summer
 * @Date: 2023/11/19
 * @Param:
 * @Return:
 */
@Aspect
@Component
public class AutoFillAspect {

    /**
     * @Description: 切入点
     * @Author: 翰戈.summer
     * @Date: 2023/11/19
     * @Param:
     * @Return: void
     */
    @Pointcut("execution(* com.demo.mapper.*.*(..)) && @annotation(com.demo.annotation.AutoFill)")
    public void autoFillPointcut() {
    }

    /**
     * @Description: 前置通知,进行公共字段自动填充
     * @Author: 翰戈.summer
     * @Date: 2023/11/19
     * @Param: JoinPoint
     * @Return: void
     */
    @Before("autoFillPointcut()")
    public void autoFill(JoinPoint joinPoint) {

        //获取方法签名对象
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        //获取注解对象
        AutoFill autoFill = methodSignature.getMethod().getAnnotation(AutoFill.class);
        //获取数据库操作类型
        OperateType operateType = autoFill.value();

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

        Object entity = args[0];

        //获取填充数据
        String username = BaseContext.getContext();// 当前用户名
        LocalDateTime now = LocalDateTime.now();// 当前时间

        //为插入操作填充数据
        if (operateType == OperateType.INSERT) {
            try {
                Method setCreateUsername = entity.getClass()
                        .getDeclaredMethod("setCreateUsername", String.class);
                Method setUpdateUsername = entity.getClass()
                        .getDeclaredMethod("setUpdateUsername", String.class);
                Method setCreateTime = entity.getClass()
                        .getDeclaredMethod("setCreateTime", LocalDateTime.class);
                Method setUpdateTime = entity.getClass()
                        .getDeclaredMethod("setUpdateTime", LocalDateTime.class);

                setCreateUsername.invoke(entity, username);
                setUpdateUsername.invoke(entity, username);
                setCreateTime.invoke(entity, now);
                setUpdateTime.invoke(entity, now);
            } catch (Exception ex) {
                throw new RuntimeException();
            }
        }

        //为更新操作填充数据
        if (operateType == OperateType.UPDATE) {
            try {
                Method setUpdateUsername = entity.getClass()
                        .getDeclaredMethod("setUpdateUsername", String.class);
                Method setUpdateTime = entity.getClass()
                        .getDeclaredMethod("setUpdateTime", LocalDateTime.class);

                setUpdateUsername.invoke(entity, username);
                setUpdateTime.invoke(entity, now);
            } catch (Exception ex) {
                throw new RuntimeException();
            }
        }
    }
}

BaseContext上下文

线程局部变量,用于存放用户名,便于在AutoFillAspect切面类中获取。

/**
 * @Description: 线程局部变量
 * @Author: 翰戈.summer
 * @Date: 2023/11/17
 * @Param:
 * @Return:
 */
public class BaseContext {
    
    public static ThreadLocal threadLocal = new ThreadLocal<>();

    public static void setContext(String context) {
        threadLocal.set(context);
    }

    public static String getContext() {
        return threadLocal.get();
    }

    public static void removeContext() {
        threadLocal.remove();
    }
}

你可能感兴趣的:(其他内容,spring,boot,java,后端,mysql)