AutoFill
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{
//数据库操作类型
OperationType value();
}
@Target(ElementType.METHOD)当前注解加在的位置(方法上)
@Retention(RetentionPolicy.RUNTIME)保留时间,生命周期
OperationType
public enum OperationType {
UPDATE,
INSERT
}
AutoFillAspect
//自定义切面,实习公共字段自动填充处理逻辑
@Aspect
@Component
@Slf4j
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("开始进行公共字段的自动填充...");
//
}
}
@annotation(com.sky.annotation.AutoFill)")
定义了一个切入点,指明了哪些方法会被拦截。这里表示所有在com.sky.mapper
包下的方法,并且这些方法需要有 AutoFill
注解。
@Before("autoFillPointCut()")前置通知
@AutoFill(value = OperationType.INSERT)
@AutoFill(value = OperationType.UPDATE)
测试发现已经拦截到方法了,接下来完善代码
AutoFillAspect
@Aspect//切面类
@Component
@Slf4j
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();//获取数据库操作类型
//获得到当前被拦截放到的参数,实体对象
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){
//为4个公共字段赋值
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,now);
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(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();
}
}
}
}
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);
AutoFill
注解。OperationType operationType = autoFill.value();
Object[] args = joinPoint.getArgs();
到这里功能完成,我们就可以把更新之类的方法公共字段注释起来
@Override
public void update(EmployeeDTO employeeDTO) {
Employee employee = new Employee();
BeanUtils.copyProperties(employeeDTO, employee);
//employee.setUpdateTime(LocalDateTime.now());
//employee.setCreateUser(BaseContext.getCurrentId());
employeeMapper.update(employee);
}
测试后程序正常运行
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,用于处理横切关注点(cross-cutting concerns)。横切关注点是指那些跨越多个模块或组件的公共行为或功能,例如日志记录、事务管理、安全控制等。在传统的面向对象编程中,这些横切关注点通常需要在各个业务逻辑中重复编写,这不仅增加了代码的复杂性,还可能导致代码的维护困难。
AOP 的核心思想是将这些横切关注点从业务逻辑中分离出来,封装成独立的模块,称为“切面”(Aspect)。这样,就可以在不修改业务逻辑的情况下添加或修改这些横切关注点的行为。
Spring 框架支持 AOP,并提供了一种声明式的方式来进行 AOP 编程。在 Spring 中,可以通过以下方式定义切面:
@Aspect
注解标记切面类。@Pointcut
注解定义切入点表达式。@Before
, @After
, @AfterReturning
, @Around
, @AfterThrowing
等注解来定义通知类型。在代码中,AutoFillAspect
类是一个切面类,它使用了 AOP 来实现自动填充的功能。下面逐项解释:
@Aspect
和 @Component
注解表明 AutoFillAspect
类是一个切面类,它将被 Spring 管理。@Pointcut
注解定义了一个名为 autoFillPointCut
的切入点表达式,该表达式匹配所有位于 com.sky.mapper
包下的方法,并且这些方法必须标注有 @AutoFill
注解。@Before
注解定义了一个前置通知 autoFill
,该通知在匹配的切入点方法执行之前触发。JoinPoint
对象 joinPoint
代表了切入点方法执行时的连接点,可以通过它获取方法签名、参数等信息。在 autoFill
方法中,通过 joinPoint.getArgs()
获取被拦截方法的参数,然后根据 @AutoFill
注解中的 value
属性确定操作类型,并使用反射机制来设置实体对象的公共字段(如创建时间、更新时间等)。
AOP 切面是 AOP 编程中的一个重要概念,它封装了横切关注点的逻辑,使得这些逻辑可以从主要业务逻辑中分离出来,便于管理和重用。在您的代码示例中,AutoFillAspect
类就是一个切面类,它负责自动填充实体对象的公共字段。