公共字段自动填充
问题分析
代码冗余、不便于后期维护
实现思路
自定义注解 AutoFill,用于标识需要进行公共字段自动填充的方法
自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值
在 Mapper 的方法上加入 AutoFill 注解
技术点:枚举、注解、AOP、反射
/**
* 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
* @author 赵鹏雨
* @version 1.0
*/
@Target(ElementType.METHOD)//可修饰在方法之上
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
//数据库操作类型 UPDATE,INSERT
OperationType value();
}
如果注解类型T上不存在@Target元注解,则类型T的注解可以写为除类型参数声明之外的任何声明的修饰符。
如果存在@Target元注解,编译器将强制执行ElementType枚举常量指示的使用限制
- 它指明了它所修饰的注解使用的范围 如果自定义的注解为含有@Target元注解修饰,那么默认可以是在(除类型参数之外的)任何项之上使用,若有@Target元注解修饰那么根据Value(ElementType枚举常量)的指定的目标进行规定。
- /** 方法声明 */ METHOD,
指示要保留带注解类型的注解多长时间。如果注释类型声明中不存在保留注释,则保留策略默认为RetentionPolicy.CLASS 。 仅当元注释类型直接用于注释时,保留元注释才有效。如果将元注释类型用作另一个注释类型中的成员类型,则它没有效果。
- 即
@Retention用来约束注解的生命周期,分别有三个值,源码级别(source)、类文件级别(class)或者运行时级别(runtime)可以通过指定@Retention中的值来实现(值为RetentionPolicy枚举常量)。
/**
* 自定义切面,实现公共字段自动填充处理逻辑
* @author 赵鹏雨
* @version 1.0
*/
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
/**
* 切入点
*/
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") //(* com.sky.mapper.*.*(..))
public void autoFillPointCut() {
}
/**
* 前置通知,在通知中进行公共字段赋值
*/
@Before("autoFillPointCut()")
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];
//准备复制数据
LocalDateTime now = LocalDateTime.now();
Long currentId = BaseContext.getCurrentId();
//根据当前不同的操作类型,为对应的属性通过反射来赋值
if (operationType == OperationType.INSERT) {
//为四个公共字段赋值
try {
Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
//通过反射为对象赋值
setCreateTime.invoke(entity,now);
setCreateUser.invoke(entity,currentId);
setUpdateTime.invoke(entity,now);
setUpdateUser.invoke(entity,currentId);
} catch (Exception e) {
e.printStackTrace();
}
} else if (operationType == OperationType.UPDATE) {
//为两个公共字段赋值
try {
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,currentId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}