当我们在进行写项目的时候,往往会遇到实现某一个接口的时候会遇到反复使用某些方法的时候,会进行代码复用,举个例子:比如我们实现update修改操作的时候,我们需要更新 修改时间update_time和update_user 当我们实现插入insert操作的时候,我们需要更新update_user create_user和 create_userid 等操作。每次写这些的时候会造成代码冗余,如何解决呢?
一:自定义注解AutoFill,用于标识需要进行公共字段自动填充的方法。
我们需要自定义一个注解。
/**
* 自定义注解,用于表示某个方法需要进行功能字段填充处理
*/
@Target(ElementType.METHOD)//指明注解只能加在方法上面
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
//数据库操作类型; Update Insert
OperationType value();
}
OperationType是一个枚举类,里面定义了我们需要进行操作的类型名称。
public enum OperationType {
/**
* 更新操作
*/
UPDATE,
/**
* 插入操作
*/
INSERT
}
二:自定义切面类AutoFillAspect,同意拦截加入了AutoFill注解的方法,通过反射为公共红字段赋值
**
* 自定义切面类,实现公共字段自动填充处理逻辑
*/
@Aspect //切面类的注解
@Component //交给spring容器管理
@Slf4j
public class AutoFillAspect {
/**
* 切入点
*/
@Pointcut("execution(* com.sky.mapper.*.*(..))&& @annotation(com.sky.annotation.AutoFill)")//该包下所有方法,并且加入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,currentId);
setUpdateTime.invoke(entity,now);
setUpdateUser.invoke(entity,currentId);
} catch (Exception e) {
throw new RuntimeException(e);
}
}else if (operationType==OperationType.UPDATE){
//为2个公共字段赋值
try { //获取到某个实体类的 这四个方法
// Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);
// Method setCreateUser = entity.getClass().getDeclaredMethod("setCreateUser", 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) {
throw new RuntimeException(e);
}
}
}
}
@Pointcut 这个注解的意思是切入点,意思是后面路径的类的方法都会进行处理。、
因为在用update和insert方法时,才会更新创建人和创建时间,更新时间等,所以我们要用前置通知。@Before注解。
注意:我们在定义方法时候,如果有多个参数的时候第一个参数必须是实体类!
如果大家在引入@Aspect 注解爆红的时候,引入AOP的依赖就好了,下面是AOP的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
三:在Mapper的方法上加入AutoFill注解
最后一步是在我们定义的Mapper的方法上加入AutoFill注解 例如:
@AutoFill(value = OperationType.UPDATE)
void update(Employee employee);
value值后面跟的是该方法的数据库操作类型。(是更新操作还是新增操作)
四:技术点
我们使用的技术点有:枚举、注解、AOP、反射。
如果有不懂的或者有不足的欢迎在评论区或者私信留言,一定会第一时间回复、以后会多多更新的!!感谢大佬们的观看和关注!!