背景
这篇的公共字段填充主要是修改和插入一些数据的接口会用到,像一些实体类的创建时间、修改时间、创建人和修改人。
解决办法
自定义注解类AutoFill,标识需要公共字段填充的方法;
自定义切面类AutoFillAspect,统一拦截里加入AutoFill注解的方法,通过反射为其赋值;
在Mapper的方法上加上AutoFill注解;
实现
自定义注解代码实现:
import com.sky.enumeration.OperationType;
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 {
// 指定数据库操作类型,update insert
OperationType value();
}
其中:定义了一个名为 OperationType
的枚举(Enum),枚举中有两个常量:UPDATE
和 INSERT
。代码实现:
/**
* 数据库操作类型
*/
public enum OperationType {
/**
* 更新操作
*/
UPDATE,
/**
* 插入操作
*/
INSERT
}
切面类代码实现:
import com.sky.annotation.AutoFill;
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.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
/*
* 自定义切面 实现公共字段自动填充的逻辑
* */
@Aspect
@Slf4j
@Component
public class AutoFillAspect {
/*
* 切入点
* */
@Pointcut("execution(* com.sky.mapper.*.*(..)) && " +
"@annotation(com.sky.annotation.AutoFill)") //指定了拦截mapper包下的所有类所有方法 以及同时加入了AutoFill自定义注解的方法
public void autoFillPointCut(){}
/*
* 前置通知 在该通知中进行公共字段的赋值
* */
@Before("autoFillPointCut()")
public void autoFill(JoinPoint joinPoint) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { //传入一个参数 表示连接点
// 获取注解上面的方法的数据库类型是insert还是update
MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获取一个 MethodSignature 对象,它包含了当前执行的方法的签名信息,比如方法名、参数类型等
AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//从获得的signature对象中获取其方法 再获取名为AutoFill的注解
OperationType operationType=autoFill.value(); //将获取到的有添加自定义注解的方法进行操作类型的获取 insert还是update
// 获取要赋值的实体对象 即被拦截的方法的参数
Object[] args = joinPoint.getArgs();//获取参数
if(args==null || args.length==0){
// 参数为空 直接return
return;
}
// 不为空 获取参数列表中的第一个参数 例如 Employee employee 中的Employee
Object object=args[0];
// 准备赋值的数据
LocalDateTime now = LocalDateTime.now();
Long currentId = BaseContext.getCurrentId();
// 为对应的操作类型进行赋值
if(operationType==OperationType.INSERT){
// 插入操作 为四个公共字段赋值
Method setCreateTime=object.getClass()
.getDeclaredMethod("setCreateTime",LocalDateTime.class);//获取当前对象类的setCreateTime方法 并设置为其赋值一个 LocalDateTime 类型的参数
Method setCreateUser = object.getClass()
.getDeclaredMethod("setCreateUser", Long.class);//与上面同理 只不过user是long型数据
Method setUpdateTime=object.getClass()
.getDeclaredMethod("setUpdateTime",LocalDateTime.class);
Method setUpdateUser = object.getClass()
.getDeclaredMethod("setUpdateUser", Long.class);
// 通过反射为对象属性赋值
setCreateTime.invoke(object,now);
setCreateUser.invoke(object,currentId);
setUpdateTime.invoke(object,now);
setUpdateUser.invoke(object,currentId);
}else if(operationType==OperationType.UPDATE){
// 更新操作 为两个属性赋值即可
Method setUpdateTime=object.getClass()
.getDeclaredMethod("setUpdateTime",LocalDateTime.class);
Method setUpdateUser = object.getClass()
.getDeclaredMethod("setUpdateUser", Long.class);
setUpdateTime.invoke(object,now);
setUpdateUser.invoke(object,currentId);
}
}
}
随后,便可在需要的方法上面添加自定义注解来进行公共字段的填充: