比如操作人,操作机构,操作时间
用aop自定义切面,枚举是不同的操作(insert,select)对应的变化不一样,注解是自定义注解
1、自定义注解
package com.sky.annotation;
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();
}
2、枚举类
package com.sky.enumeration;
/**
* 数据库操作类型
*/
public enum OperationType {
/**
* 更新操作
*/
UPDATE,
/**
* 插入操作
*/
INSERT
}
自定义切面类 AutoFiAspect,统一拦截加入了 AutoFi 注解的方法,通过反射为公共字段赋值
3、切面类 AutoFiAspect
注意类的位置
package com.sky.aspect;
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;
/**
* 自定义切面,实现公共字段自动填充处理逻辑
*/
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
/**
* 切入点表示对哪些类的哪些方法进行拦截
* execution(* com.sky.mapper.*.*(..)第一个*表示返回值是所有,在com.sky.mapper的所有(*)类所有(*)方法,匹配所有的参数类型(..)
* 但是这个mapper不是里面的所有方法都要被拦截,只拦截insert和update
* && @annotation(com.sky.annotation.AutoFill) 还要满足该方法上加了AutoFill注解
*
*/
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
public void autoFillPointCut(){}
/**
* 前置通知,在通知中进行公共字段的赋值,注意是前置通知,sql都执行完了再通知就没有意义了
*/
@Before("autoFillPointCut()") //括号里面是33上面的方法名称
//joinPoint是一个连接点,是哪个方法被拦截到了以及拦截到的方法是什么样子的
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];//这里是获取实体对象,约定用AutoFill注解的第一个参数都是实体对象,例如void update(Orders orders)
//准备赋值的数据
LocalDateTime now = LocalDateTime.now();
Long currentId = BaseContext.getCurrentId();
//根据当前不同的操作类型,为对应的属性通过反射来赋值
if(operationType == OperationType.INSERT){
//为4个公共字段赋值
try {
//通过反射赋值,这里的实体类默认加了@Data,下面4行代码是获得set方法
Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);//setCreateTime方法是time类型的
Method setCreateUser = entity.getClass().getDeclaredMethod("setCreateUser", Long.class);
Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);
//通过反射为对象属性赋值
setCreateTime.invoke(entity,now);//entity的setCreateTime赋值为now
setCreateUser.invoke(entity,currentId);
setUpdateTime.invoke(entity,now);
setUpdateUser.invoke(entity,currentId);
} catch (Exception e) {
e.printStackTrace();
}
}else if(operationType == OperationType.UPDATE){
//为2个公共字段赋值
try {
Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);
//通过反射为对象属性赋值
setUpdateTime.invoke(entity,now);
setUpdateUser.invoke(entity,currentId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
在mapper上面加上相应的注解(每个mapper的insert和update都要加,有点麻烦?)
括号里面是枚举类