公共字段自动填充

160 阅读2分钟

一些表的公共字段例如

create_time,create_user,update_time,update_user

可以通过自定义注解AutoFill来统一实现

技术点:枚举 注解 AOP 反射

1.准备管理类与枚举

// 创建操作类型枚举
public enum OperationType{
	UPDATE,
	INSERT;
}

// 创建一个常量工具类来管理公共字段
public class AutoFillContstant{
    public static final String SET_CREATE_TIME = "setCreateTime";
    public static final String SET_UPDATE_TIME = "setUpdateTime";
    public static final String SET_CREATE_USER = "setCreateUser";
    public static final String SET_UPDATE_USER = "setUpdateUser";
}

2. 创建一个自定义注解 AutoFill

用于表示需要进行公共字段自动填充的方法

@Target(ElementType.METHOD) // 只能加在方法上面
@Retention(RetentionPolicy.RUNTIME) // 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
public @interface AutoFill{
	// 指定数据库操作类型
	OperationType value();
}

3.自定义一个切面类 AutoFillAspect

// 自定义切面类,实现公共字段自动填充
@Aspect
// 交给ioc容器
@Component
@Slf4j
public class AutoFileAspect{
	// 定义切入点
	// *任意返回值 com.sky.mapper包下的所有接口 下的 以及加了com.sky.annotaiton.AutoFill这个注解的方法
	// Pointcut:切入点key封装  使用的时候直接 autoFillPointCut()就行
	@Pointcut("execution(* com.sky.mapper.*.*(..)) && 
	@annotation(com.sky.annotaiton.AutoFill)")
	public void autoFillPointCut(){
	}
	
	// 使用前置通知‘
	@Before("autoFillPointCut()")
	public void autoFill(JoinPoint joinPoint){
        // 获取当前被拦截方法的签名
        Signature signature = (MethodSignature) joinPoint.getSignature();
		// 获得当前方法的注解,因为可能存在多个注解,所以需要传入注解的类型
		signature.getMethod().getAnnotation(AutoFill.class);
		// 获得数据库操作类型 INSERT or UPDATE
		OperationType operationType = autoFill.value();
		
		
		// 获取当前被拦截的方法的参数
		Object[] args = joinPoint.getArgs();
		// 防御性编程,防止空指针报错
		if(args == null || args.length == 0){
			return;
		}
		Object entry = args[0];
		
		// 准备赋值的数据
		LocalDateTime now = LocalDateTime.now();
		Long currentId = BaseContext.getCurrentId();
		
		// 根据sql操作类型,为对应的属性通过反射来赋值
		if(operationType == OperationType.INSERT){
			// 查询,需要为四个属性赋值
			
			try{
				
				// 获取方法
				Method setCreateTime = entry.getClass().getDeclareMethod(AutoFillConstant.SET_CREATE_TIME,LocalDateTime.class);
				
				
				Method setCreateUser = entry.getClass().getDeclareMethod(AutoFillConstant.SET_CREATE_USER,Long.class);
				
				Method setUpdateTime = entry.getClass().getDeclareMethod(AutoFillConstant.SET_CREATE_TIME,LocalDateTime.class);
				
				Method setUpdateUser = entry.getClass().getDeclareMethod(AutoFillConstant.SET_UPDATE_USER,Long.class);
				
				// 调用反射方法
				setCreateTime.invoke(entry,now);
				setCreateUser.invoke(entry,currentId);
				setUpdateTime.invoke(entry,now);
				setUpdateUser.invoke(entry,currentId);
			}catch(Exception e){
			
			}
			
		}else if(operationType == OperationType.UPDATE){
			// 更新,需要为两个属性赋值
			try{
				Method setUpdateTime = entry.getClass().getDeclareMethod(AutoFillConstant.SET_CREATE_TIME,LocalDateTime.class);
				
				Method setUpdateUser = entry.getClass().getDeclareMethod(AutoFillConstant.SET_UPDATE_USER,Long.class);
				
				setUpdateTime.invoke(entry,now);
				setUpdateUser.invoke(entry,currentId);
			}catch(Exception e){
				
			}
		}
		
		
	}
}

3. Mapper方法中加上AutoFill注解

@AutoFill(value = OperationType.INSERT)
void insert(Employee employee);

@AutoFill(value = OperationType.UPDATE)
void update(Employee employee);