面向AOP切面编程 -- 应用篇

面向AOP切面编程 – 应用篇

前提:

自定义注解注意项

自定义注解中的参数:不是方法,而是参数。
这样写是因为自定义注解中的参数的命名要求,参数类型 + 参数名 + ();
如果只有一个参数 当使用注解的时候,可以将参数名省略
@AutoFill(value = OperationType.INSERT) --> @AutoFill(OperationType.INSERT)

/**
 * 用于标识需要进行公共字段自动填充的方法
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    OperationType value();//参数
}
@Mapper
public interface CategoryMapper {
    @AutoFill(OperationType.INSERT)
    void updateDate(Category category);
}
@Mapper
public interface CategoryMapper {
    @AutoFill(value = OperationType.INSERT)
    void updateDate(Category category);
}

创建自定义注解:

/**
 * 用于标识需要进行公共字段自动填充的方法
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    OperationType value();//参数
}

创建枚举类:

/**
 * 数据库操作类型
 */
public enum OperationType {

    /**
     * 更新操作
     */
    UPDATE,

    /**
     * 插入操作
     */
    INSERT

}

背景:

当使用sql语句进行插入、更新时,每当编写这两个sql语句的逻辑处理层都需要手动填充插入时间、更新时间、插入操作用户、更新操作用户字段。

解决:

创建自定义注解:用于标识哪些sql语句需要被拦截做统一的广播处理

准备工作,创建自定义注解,创建枚举类,创建切面(切入点和通知组成)

代码:

/**
 * 自定义切面类 实现公共字段自动填充处理逻辑
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    //切入点 +  通知 = 切面


    /**
     * *:返回值是所有的
     * com.sky.mapper:包
     * .*:所有的类
     * .*:所有的方法
     * (..):匹配所有的参数类型
     */
    //切入点
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut() {
    }

    /**
     * 前置通知(在执行sql语句之前进行通知操作),在通知中进行公共字段的赋值
     */
    //通知
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) {//连接点(JoinPoint joinPoint):获取当前被拦截的方法以及方法的参数
        log.info("字段开始自动填充");
        //1.判断被拦截到的方法是insert还是update
        //获得签名对象 但是该对象是接口,被拦截到的是方法,所以要向下转型(转成子接口).
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取方法上的注解对象
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);
        //获取数据库操作类型
        OperationType operationType = autoFill.value();

        //2.获取方法的参数 约定俗成 要想实现自动填充功能,方法第一个参数要是实体对象
        Object[] args = joinPoint.getArgs();

        if (args == null || args.length == 0) {
            return;
        }
        Object entity = args[0];
        //3.为实体对象准备数据
        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();
        //4.通过反射进行赋值
        if (operationType == OperationType.INSERT) {
            //getClass() 返回此 Object 的运行时该对象的类. 该方法返回一个Class对象, 可以通过该对象可以获取某个类的相关信息, 如构造方法 属性 方法 等.
            //getDeclaredMethod() 返回 一个Method对象,它反映此Class对象所表示的类或接口的指定已声明方法
            /**
             * 补充在 Java 中,getDeclaredMethod() 方法用于获取当前类中声明的指定名称和参数类型的方法。
             * 参数说明:
             * String name:这是一个字符串类型的参数,用于指定要获取的方法的名称。比如,如果您要获取名为 calculateSum 的方法,那么这里就应传入 "calculateSum" 。
             * 例如:假设您有一个方法叫 processData ,您就传入 "processData" 来获取该方法。
             * Class<?>... parameterTypes:这是一个可变参数,用于指定方法的参数类型。
             * 比如,如果要获取的方法接收两个参数,分别为 int 类型和 String 类型,那么可以这样写:Class<?>[] parameterTypes = {Integer.class, String.class} 。
             * 再比如,如果方法没有参数,那么这里就传入一个空的参数列表即可。
             */
            try {
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME,LocalDateTime.class;
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME,LocalDateTime.class;
                Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //为公共字段赋值 通过反射
                setCreateTime.invoke(entity, now);
                setUpdateTime.invoke(entity, now);
                setCreateUser.invoke(entity, currentId);
                setUpdateUser.invoke(entity, currentId);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else if (operationType == OperationType.UPDATE) {
            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) {
                throw new RuntimeException(e);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值