这个注解的使用是从苍穹外卖里面学习的,有兴趣的可以去看看,在这里做个笔记用于后面使用的时候可以快速的进行使用。
首先看看如何进行使用吧
可以看到下面的代码方法上面都是用的 @AutoFill(OperationType.INSERT) 或者@AutoFill(OperationType.UPDATE)
对数据进行新增和更新的时候就可以使用AOP的前置通知对数据进行自动添加时间的功能。
具体看后面的实现。
package com.sky.mapper;
/**
* @auther fang
* @date 2023/11/13 22:37
*/
@Mapper
public interface DishMapper {
/**
* 新增菜品
* @param dish
*/
@AutoFill(OperationType.INSERT)
void save(Dish dish);
/**
* 更新
* @param dish
*/
@AutoFill(OperationType.UPDATE)
void update(Dish dish);
// 其它方法都忽略
}
具体实现如下:
@Retention(RetentionPolicy.RUNTIME) :运行时
@Target(ElementType.METHOD):注解只能放在方法的上面
上面两个是元注解
package com.sky.annotation;
import com.sky.enumeration.OperationType;
import java.lang.annotation.*;
/**
* 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
* @author Fang
* @date 2023/11/14 21:20
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AutoFill {
/**
* 数据库操作类型:UPDATE,INSTALL
* @return
*/
OperationType value();
}
然后注解里面有一个属性值是OperationType是一个枚举类型如下:
package com.sky.enumeration;
/**
* 数据库操作类型
*/
public enum OperationType {
/**
* 更新操作
*/
UPDATE,
/**
* 插入操作
*/
INSERT
}
自定义切面,实现公共字段自动填充处理逻辑
首先定义一个切入点
execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)
切入点让它去匹配com.sky.mapper包下的所有类的任意入参的所有方法,并且方法上面写了上面的自定义注解@AutoFill
然后对这个切入点匹配的方法进行前置通知
@Before(value = "autoFillPointCut()")
在方法执行的时候都会进行前置通知,这里就是AOP切面编程,这一块一直都是比较难的,以后有时间的话还是可以学学spring的源码对IOC和AOP学习一些,首先要对IOC了解之后才有可能对AOP进行学习。
前置通知会从 JoinPoint连接点 获取到相应的数据,具体的操作还是看下面的代码
package com.sky.aspect;
import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
/**
* 自定义切面,实现公共字段自动填充处理逻辑
* @auther fangjt
* @date 2023/11/14 21:32
*/
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
/**
* 切入点
*/
@Pointcut(value = "execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
public void autoFillPointCut() {}
/**
* 前置通知,在通知中进行公共字段的赋值
* @param joinPoint
*/
@Before(value = "autoFillPointCut()")
public void autoFill(JoinPoint joinPoint) {
log.info("开始进行公共字段自动填充...");
// 获取到方法的入参
Object[] args = joinPoint.getArgs();
if (args == null || args.length == 0) {
return;
}
Object entity = args[0];
// 获取到方法上面的注解
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
AutoFill annotation = method.getAnnotation(AutoFill.class);
// 获取到注解里面的参数
OperationType operationType = annotation.value();
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,currentId);
setUpdateTime.invoke(entity,now);
setUpdateUser.invoke(entity,currentId);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException 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 (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}