公共字段自动填充功能开发
前言
本文主要利用AOP,反射,枚举等多种技术,通过苍穹外卖项目讲解如何进行公共字段自动填充,从而达到对所有表自动记录创建人、创建时间、更新人、更新日期等数据,而不需要在每个service层重复写代码,达到了降低代码重复度和便于维护的目的.
1. 需求分析
菜品表和分类表中都存在上述这四个公共的字段,导致我们的业务代码中出现了冗余的代码,不方便后期维护
实现思路:
2. 代码开发
- 自定义注解AutoFill
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
OperationType value();
}
设置Target为METHOD,Retention为RUNTIME,并且枚举类型为UPDATE和INSERT
- 自定义切面类
@Component
@Slf4j
@Aspect
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("开始进行公共字段自动填充......");
}
}
需要在类上面加上@Component注解和@Aspect注解以及Slf4j来记录日志
需要定义切入点为com.sky.mapper包下的任意类和任意方法,方法参数任意,返回值任意,并且只捕获加入了com.sky.annotation.AutoFill注解的方法
- 通过反射为公共字段赋值
@Before("autoFillPointcut()")
public void autoFill(JoinPoint joinPoint) throws NoSuchMethodException {
log.info("开始进行公共字段自动填充......");
//获取当前拦截方法的数据库操作类型
MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获取方法签名
AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获取方法上的AutoFill注解
OperationType operationType = autoFill.value();//获取操作类型
//获取当前被拦截的方法的参数,实体对象
Object[] args = joinPoint.getArgs();
if (args == null || args.length == 0){
return;
}
Object entity = args[0];
//获取当前时间和操作人id
LocalDateTime now = LocalDateTime.now();
Long id = BaseContext.getCurrentId();
if (operationType == OperationType.INSERT){
//设置四个属性
//为什么使用反射?因为以后操作的表不一定是员工表,类型也不一定是员工类型,所以不能直接把实体类转换成员工类型进行操作
try {
Method setCreatTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
Method setCreatUser = 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);
//通过反射对属性进行赋值
setCreatTime.invoke(entity,now);
setCreatUser.invoke(entity,id);
setUpdateTime.invoke(entity,now);
setUpdateUser.invoke(entity,id);
}catch (Exception e){
e.printStackTrace();
}
}else if (operationType == OperationType.UPDATE){
//为2个公共字段进行赋值
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,id);
}catch (Exception e){
e.printStackTrace();
}
}
}
- 为mapper层对应方法加上注解
- 菜品:
@AutoFill(value = OperationType.INSERT)
void insert(Category category);
@AutoFill(value = OperationType.UPDATE)
void update(Category category);
员工mapper同上
3. 功能测试
插入数据:
执行结果:
数据库中成功填充公共字段
更新操作同样成功填充公共字段
4. 代码提交
点击Git,点击提交并推送进行提交