基于Spring-AOP写的切面和注解,解决一些跟业务逻辑无关的公共问题处理方法

2023-10-29

技术点: Spring  Aop  反射

背景:目前在做一个项目,做数据库设计的时候对一些表进行了埋点,比如跟我业务相关的每个表,都有create_time,create_user_id,create_user_name,update_time,update_user_id,update_user_name等字段

如果放在Dao处理,则我每一个表对应的每一个实体都需要setCreateUserId,setCreateUserName,setUpdateUserId,

setUpdateUserName 等等,代码咸的很臃肿,基于这样的背景,写了一个切面,处理这些公共的逻辑。

代码:

      aspect 包:

 

注解             

import java.lang.annotation.*;

/**
 * @author qiwenshuai
 * @note
 * @since 18-11-8 14:00 by jdk 1.8
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OTADaoRecord {
    OTARecordEnum type()  default OTARecordEnum.NONE;
}

枚举
/**
 * @author qiwenshuai
 * @note
 * @since 18-11-9 09:17 by jdk 1.8
 */
public enum OTARecordEnum {

    NONE("NONE",0),

    CREATE("CREATE",1),

    UPDATE("UPDATE",2),

    MAPCREATE("MAPCREATE",3),

    MAPUPDATE("MAPUPDATE",4),

    ;


    private String type;
    private Integer value;

    OTARecordEnum(String type,Integer value){
        this.type=type;
        this.value=value;
    }


    public String getType() {
        return type;
    }

    public Integer getValue() {
        return value;
    }

}

切面

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author qiwenshuai
 * @note 每次修改和新增都要增加 userId和userName 为了简便,写个注解只关注业务层。
 * @since 18-11-8 17:45 by jdk 1.8
 */
@Aspect
@Component
public class RecordAspect {

    private static final Logger logger = LoggerFactory.getLogger(RecordAspect.class);

    private static final String CREATE_USER_ID_METHOD = "setCreateUserId";
    private static final String CREATE_USER_NAME_METHOD = "setCreateUserName";
    private static final String CREATE_DATA_SOURCE_METHOD = "setDataSource";
    private static final String CREATE_MAP_USER_ID_METHOD = "createUserId";
    private static final String CREATE_MAP_USER_NAME_METHOD = "createUserName";
    private static final String CREATE_MAP_DATA_SOURCE_METHOD = "dataSource";
    private static final String UPDATE_MAP_USER_ID = "updateUserId";
    private static final String UPDATE_MAP_USER_NAME = "updateUserName";
    private static final String UPDATE_USER_ID_METHOD = "setUpdateUserId";
    private static final String UPDATE_USER_NAME_METHOD = "setUpdateUserName";

    protected final HttpServletRequest request;

    @Autowired
    public RecordAspect(HttpServletRequest request) {
        this.request = request;
    }

    //Controller层切点
    @Pointcut("@annotation(cn.futuremove.tsp.vehicle.aspect.OTADaoRecord)")
    public void OTADaoRecord() {
    }

    /**
     * 环绕AOP
     */
    @Around("OTADaoRecord()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        try {
            if (OTARecordEnum.UPDATE.equals(getControllerMethodDescription(pjp))) {
                setUpdateProperty(pjp);
            } else if (OTARecordEnum.CREATE.equals(getControllerMethodDescription(pjp))) {
                setCreateProperty(pjp);
            } else if (OTARecordEnum.MAPCREATE.equals(getControllerMethodDescription(pjp))) {
                setMapCreateProperty(pjp);
            } else if (OTARecordEnum.MAPUPDATE.equals(getControllerMethodDescription(pjp))) {
                setMapUpdateProperty(pjp);
            }
            return pjp.proceed();
        } catch (Exception e) {
            logger.error("切面设置值发生错误:{}", e);
            return null;
        }

    }


    /**
     * 反射获取type值的逻辑
     */
    private OTARecordEnum getControllerMethodDescription(ProceedingJoinPoint pjp) throws ClassNotFoundException {
        String targetName = pjp.getTarget().getClass().getName();
        String methodName = pjp.getSignature().getName();
        Object[] arguments = pjp.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        OTARecordEnum recordEnum = null;
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    recordEnum = method.getAnnotation(OTADaoRecord.class).type();
                    break;
                }
            }
        }
        return recordEnum;
    }


    private void setCreateProperty(ProceedingJoinPoint pjp) throws InvocationTargetException, IllegalAccessException {
        //create的逻辑
        Object[] arguments = pjp.getArgs();
        for (Object object : arguments) {
            Method[] methods = object.getClass().getMethods();
            createInvoke(methods, object);
        }
    }


    private void setUpdateProperty(ProceedingJoinPoint pjp) throws InvocationTargetException, IllegalAccessException {
        //create的逻辑
        Object[] arguments = pjp.getArgs();
        for (Object object : arguments) {
            Method[] methods = object.getClass().getMethods();
            updateInvoke(methods, object);
        }
    }


    private void setMapCreateProperty(ProceedingJoinPoint pjp) {
        Object[] arguments = pjp.getArgs();
        for (Object o : arguments) {
            if (o instanceof Map) {
                for (Object key : ((Map) o).keySet()) {
                    Map map = (Map)((Map<String,Object>) o).get(key);
                    map.put(CREATE_MAP_USER_ID_METHOD,"999");
                    map.put(CREATE_MAP_USER_NAME_METHOD,"create");
                    map.put(CREATE_MAP_DATA_SOURCE_METHOD,"1");
                }
            }
        }
    }

    private void setMapUpdateProperty(ProceedingJoinPoint pjp) {
        Object[] arguments = pjp.getArgs();
        for (Object o : arguments) {
            if (o instanceof Map) {
                for (Object key : ((Map) o).keySet()) {
                    Map map = (Map)((Map<String,Object>) o).get(key);
                    map.put(UPDATE_MAP_USER_ID,"999");
                    map.put(UPDATE_MAP_USER_NAME,"update");
                }
            }
        }

    }


    private void createInvoke(Method[] methods, Object object) throws InvocationTargetException, IllegalAccessException {
        for (Method method : methods) {
            if (method.getName().equals(CREATE_USER_ID_METHOD)) {
                //后期取值
                method.invoke(object, "99999");
            }
            if (method.getName().equals(CREATE_USER_NAME_METHOD)) {
                //后期取值
                method.invoke(object, "create");
            }
            if (method.getName().equals(CREATE_DATA_SOURCE_METHOD)) {
                //创建数据的时候,记录数据源
                method.invoke(object, "1");
            }
        }
    }

    private void updateInvoke(Method[] methods, Object object) throws InvocationTargetException, IllegalAccessException {
        for (Method method : methods) {
            if (method.getName().equals(UPDATE_USER_ID_METHOD)) {
                //后期取值
                method.invoke(object, "99999");
            }
            if (method.getName().equals(UPDATE_USER_NAME_METHOD)) {
                //后期取值
                method.invoke(object, "update");
            }
        }

    }
}

具体的Controller调用只需要在Controller层加上注解就可以了

例如:

@OTADaoRecord(type = OTARecordEnum.MAPUPDATE)
@OTADaoRecord(type = OTARecordEnum.CREATE)

等等。。。。。。。

 

要注意的是,使用声明式事务注解的时候,Controller层不要写 

@Transactional

基于Spring事务在Service层的传播性,要在Service处理所有的Dao逻辑,并且在Service层加上注解,并且不要加try-catch,否则Controller拦截不到Exception,无法回滚事务。

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于Spring-AOP写的切面和注解,解决一些跟业务逻辑无关的公共问题处理方法 的相关文章

随机推荐

  • xilinx ip 高斯滤波

    功能 1 单axi stream 接口输入 10bit raw输入 axis输出 10bit输出 使用5x5 的卷积进行滤波 2 使用xilinx hls 编写 3 配置寄存器有 pragma HLS INTERFACE s axilite
  • Spring学习笔记:AOP

    学习内容 AOP 文章目录 学习内容 AOP 一 什么是AOP 二 AOP中的相关概念 三 使用Spring实现AOP 1 使用原生Spring API接口 2 自定义类来实现AOP 3 使用注解实现 四 AOP中的五类通知 一 什么是AO
  • PCL 1.13.0——中文显示乱码解决办法

    目录 一 问题概述 二 解决方法 一 问题概述 PCL1 13 0中使用的是VTK9 2进行点云的可视化 在使用中发现PCL1 13 0中的setWindowName 进行中文名称显示的时候会出现乱码现象 如下所示 可视化投影结果 boos
  • 特殊矩阵的压缩存储(对称矩阵,三角矩阵和三对角矩阵)

    目录 1 对阵矩阵 2 三角矩阵 3 三对角矩阵 带状矩阵 均假设数组的下标从0开始 1 对阵矩阵 定义 若对一个n阶矩阵A中的任意一个元素 a 都有a a 1 i j n 则称其为对称矩阵 存储策略 只存储主对角线 下三角区 或主对角线
  • shardingsphere的坑。。。

    前面有说到defaultDataSource设置不生效 手动修改后 此项还勉强能用 如今又遇到一个奇葩的问题 本地调试时一切正常 丢到服务器后就一直报错 重点是 只是说空指针 就是不说具体哪里有毛病 报错信息如下 Creating a ne
  • 数据库连接用法

    1 内联接 典型的联接运算 使用像 或 lt gt 之类的比较运算符 包括相等联接和自然联接 内联接使用比较运算符根据每个表共有的列的值匹配两个表中的行 例如 检索 students和courses表中学生标识号相同的所有行 2 外联接 外
  • Java编程工具哪种好?

    Java强大的功能需要依托在软件工具上实现 所以Java编程开发需要用到编程工具 市面上有哪些Java编程工具呢 那种编程工具好呢 该怎么选择呢 接下来罗列了一系列的Java编程开发工具 一 idea 这是jetbrains公司的产品 也是
  • 从0实现基于Linux socket聊天室-多线程服务器模型-1

    前言 Socket在实际系统程序开发当中 应用非常广泛 也非常重要 实际应用中服务器经常需要支持多个客户端连接 实现高并发服务器模型显得尤为重要 高并发服务器从简单的循环服务器模型处理少量网络并发请求 演进到解决C10K C10M问题的高并
  • linux下gcc/g++编译器使用

    linux编译器gcc g 使用 1 gcc 编译器编译c语言程序 gcc 文件名 默认生成a out 可执行程序程序 我们执行a out由两种方法 相对路径 绝对路径 进行程序的翻译 1 预处理 进行宏替换 头文件展开 去注释 条件编译
  • kettle开发篇-流查询-Day25

    前言 昨天我们讲了数据库相关操作 数据库连接来实现两个库的跨库查询 对应复杂的跨库查询通过数据库连接整合到一块后 就像是在一个数据库里面操作 今天我们来学习流查询 流查询主要用于在查询前把数据加载到内存中 并且只能进行等值查询 一 流查询
  • 51单片机波特率计算c语言,51单片机波特率怎么算?51单片机波特率计算公式

    51单片机波特率怎么算 51单片机波特率计算公式 方式0 方式0的波特率固定为主振频率的1 12 方式2 方式2的波特率由PCON中的选择位SMOD来决定 可由下式表示 波特率 2的SMOD次方除以64再乘一个fosc 也就是当SMOD 1
  • Spring三大核心思想详解

    spring核心思想分三大类 控制反转 IOC 依赖注入 DI 和面向切面 AOP 控制反转 通俗讲 控制权由应用代码中转到了外部容器 控制权的转移 是所谓反转 也就是说 正常我们都是新建对象 才可以调用对象 现在不需要了 交给容器来管理
  • 数据结构与算法(29):KMP算法(核心思想分析)及其相关应用实例(与暴力字符串匹配代码实现)

    应用场景 字符串匹配问题 字符串匹配问题 有一个字符串 str1 陈骁聪 陈骁聪你陈骁 陈骁聪你陈骁聪你陈骁你好 和一个子串 str2 陈骁聪你陈骁你 现在要判断 str1 是否含有 str2 如果存在 就返回第一次出现的位置 如果没有 则
  • 如何引入elementUI

    elementUI的引入 完整引入 按需引入 完整引入 在 main js 中写入以下内容 import Vue from vue import ElementUI from element ui import element ui lib
  • vue移动端拖拽悬浮按钮

    vue移动端拖拽悬浮按钮 功能介绍 大致需求 整体思路 简单效果展示 具体实现 一 position fixed布局 二 touch事件绑定 三 页面引入 功能介绍 在移动端开发中 实现悬浮按钮在侧边显示 为不遮挡页面内容 允许手指拖拽换位
  • 发起HTTP请求--Curl

    curl 是常用的命令行工具 用来请求 Web 服务器 它的名字就是客户端 client 的 URL 工具的意思 它的功能非常强大 命令行参数多达几十种 如果熟练的话 完全可以取代 Postman 这一类的图形界面工具 我们可以使用cURL
  • CTFshow(web21-web28)

    web21 考点tomcat 认证爆破之custom iterator使用 https www cnblogs com 007NBqaq p 13220297 html 下载密码字典抓包 通过burpsuite暴力破解 Payload se
  • 原生JS实现ajax 发送post请求

    1 代码 原生JS实现ajax 发送post请求
  • fluxion 无法连接虚假AP热点,DHCP服务启动失败

    记录一个使用fluxion时 无法连接至虚假AP的DHCP问题 编辑 fluxion attacks Captive Portal attack sh gedit fluxion attacks Captive Portal attack
  • 基于Spring-AOP写的切面和注解,解决一些跟业务逻辑无关的公共问题处理方法

    技术点 Spring Aop 反射 背景 目前在做一个项目 做数据库设计的时候对一些表进行了埋点 比如跟我业务相关的每个表 都有create time create user id create user name update time