欢迎来到“雪碧聊技术”CSDN博客!
在这里,您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者,还是具有一定经验的开发者,相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导,我将不断探索Java的深邃世界,分享最新的技术动态、实战经验以及项目心得。
让我们一同在Java的广阔天地中遨游,携手提升技术能力,共创美好未来!感谢您的关注与支持,期待在“雪碧聊技术”与您共同成长!
目录
1、定义一个注解AutoFill,用来标志mapper接口的哪些方法需要进行公共字段填充
4、之后对应的方法,会携带填充完的、更加完善的实体类,进入mapper.xml中进行sql操作。
一、什么叫公共字段?
举例
下面几张表,都包含了创建时间、修改时间、创建人ID、修改人ID。
此时这四个字段,就叫公共字段。
二、为什么要进行公共字段填充?
1、不这么做的缺点
如果不进行公共字段填充,就需要在service层,手动地给添加/修改的对象的这四个字段进行填充,会造成代码臃肿、重复,不是明智的选择。
而我们使用AOP切面编程,会在这几张表相关的所有insert、update操作语句执行之前,自动完成公共字段填充。
2、公共字段填充的实现思路
通过切入点表达式,捕获到所有需要进行公共字段填充的方法,给这些方法加一个前置通知:即,在进行insert、update操作之前,要先获取操作的实体类,给这个实体类的4个公共字段(创建时间、修改时间、创建人ID、修改人ID)进行填充。
三、具体是如何实现的?
1、定义一个注解AutoFill,用来标志mapper接口的哪些方法需要进行公共字段填充
2、给需要公共字段自动填充的方法,添加该注解
3、编写切面类AutoFillAspect
- 通过切入点表达式,来捕获到对应的连接点(即:需要被AOP切面类操作的方法)。
- 添加前置通知
- 约定这些方法的第一个形参,就是要insert/update操作的实体类
- 获取该实体类
- 准备要赋值的数据,如:当前时间、当前人员的ID(如管理员id)
- 根据注解上的操作类型,来执行不同的逻辑
- 如果是insert类型,就给该实体类加上创建时间、更新时间、创建人ID、更新人ID这四个字段。如果是update类型,就给该实体类加上更新时间、更新人ID这两个字段(因为之前该条数据已经有创建时间、创建人ID这两个字段了)。
/**
* 自定义切面,实现公共字段自动填充处理逻辑
*/
@Aspect //表明这是一个切面类
@Component //表明这也是一个Bean,需要交给spring容器来管理(IOC控制反转)
@Slf4j //方便进行日志记录(lombok)
public class AutoFillAspect {
/**
* 切入点(说白了就是,对哪些类的哪些方法进行拦截,做原有功能的增强(加通知))
*/
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
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();//获得该注解操作类型是update还是insert
//-:获取到当前被拦截的方法的参数
Object[] args = joinPoint.getArgs();
if(args == null || args.length == 0){
return;
}
//自己约定的规则(insert/update的对象,一定放在形参列表的第一个)这一点十分重要。
Object entity = args[0];
//-:准备赋值的数据:当前时间、当前用户的id
LocalDateTime now = LocalDateTime.now();
Long currentId = BaseContext.getCurrentId();
//-:根据当前不同的操作类型,为对应的属性通过反射来赋值
//如果方法是添加操作(第一种可能)
if(operationType == OperationType.INSERT){
//-:为4个公共字段赋值
try {
//-:通过反射,获取到对应的set方法(方法名+形参类型, 这样能避免方法重载问题)
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);
//-:通过反射,调用构造器,为该entity对象属性赋值,然后就可以携带进入Mapper.xml进行sql操作了
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){
//-:为2个公共字段赋值
try {
//-:通过反射,获取到对应的set方法
Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
//-:通过反射,调用set方法,为该entity对象的属性(公共字段)赋值,然后就可以携带进Mapper.xml进行sql操作了
setUpdateTime.invoke(entity, now);
setUpdateUser.invoke(entity, currentId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
4、之后对应的方法,会携带填充完的、更加完善的实体类,进入mapper.xml中进行sql操作。
结语
以上就是使用AOP切面编程,实现公共字段自动填充的步骤,想了解更多的Java开发知识,请关注本博主~~