自定义注解实现记录日志功能(注解支持SpEL表达式)

一、首先创建个接口类Log


import java.lang.annotation.*;

/**
 * @description: 自定义操作日志记录注解
 * @author xizc
 *
 */
@Target({ ElementType.PARAMETER, ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Log {
    /**
     * 日志类别
     */
    public LogType logType();

    /**
     * 操作类别
     */
    public BusinessType businessType();

    /**
     * 关联Id
     */
    public String businessId();

    /**
     * 内容
     */
    public String content();

}

二、编写切面类


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 
 * @description: 操作日志记录处理
 * @author xizc
 */
@Aspect
@Component
public class LogAspect {
    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

    /**
     * 获取被拦截方法参数名列表(使用Spring支持类库)
     */
    LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
    ExpressionParser parser = new SpelExpressionParser();

    /**
     * 处理请求前执行
     * @param joinPoint 切点
     */
    @Before(value = "@annotation(methodLog)")
    public void boBefore(JoinPoint joinPoint, Log methodLog) {
        handleLog(joinPoint, methodLog, null, null);
    }

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "@annotation(methodLog)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Log methodLog, Object jsonResult) {
        handleLog(joinPoint, methodLog, null, jsonResult);
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "@annotation(methodLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log methodLog, Exception e) {
        handleLog(joinPoint, methodLog, e, null);
    }

    protected void handleLog(final JoinPoint joinPoint, Log methodLog, final Exception e, Object jsonResult) {
        try {
            Object[] args = joinPoint.getArgs();
            Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
            String[] params = discoverer.getParameterNames(method);
            EvaluationContext context = new StandardEvaluationContext();
            for (int len = 0; len < params.length; len++) {
                context.setVariable(params[len], args[len]);
            }

            //解析businessId注解值中的SpEL表达式
            String businessIdSpel = methodLog.businessId();
            Expression businessIdExpression = parser.parseExpression(businessIdSpel);
            String businessId = businessIdExpression.getValue(context, String.class);
            System.out.println("businessId:"+ businessId);

            //解析content注解值中的SpEL表达式
            String contentSpel = methodLog.content();
            Expression contentExpression = parser.parseExpression(contentSpel);
            String content = contentExpression.getValue(context, String.class);
            System.out.println("content:"+ content);
            
            //到此已经解析并获取到注解里面的信息,下面可以根据自己的业务相应的逻辑

        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }
}

根据自己情况来删减切入点。

SpEL表达式可以获取入参对象里面的属性,例如传入User对象user里面的username,那么SpEL表达式就是 #user.username 。

三、测试

在controller里面写个方法

 /**
     * 测试log注解
     *
     * @param ids
     * @param msg
     */
    @GetMapping("/test5")
    @Log(logType = LogType.EQUIP, businessType = BusinessType.EXPORT, businessId = "#ids", content = "'测试拼接参数'+#msg")
    public void test5(Long[] ids, String msg) {

    }

然后请求接口:

打印结果如下:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/362470.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JUnit

前言&#xff1a;自动化就是selenium脚本来实现的&#xff0c;JUnit是java的单元测试工具&#xff0c;只不过我们在实现自动化的时候需要借助一下JUnit库里面提供的一些方法。 1、Test Test &#xff1a;表示方法是测试方法&#xff0c;执行当前这个类的时候&#xff0c;会自动…

Unity之做一个最简单的FPS游戏demo

目录 &#x1f60b;FPS游戏Demo &#x1f4a4;1.新建FPS模板项目 ⚒️2.装备枪 &#x1f4a3;3.设置射击功能 &#x1f4fa;4.制造一个子弹预制体 &#x1f3ae;5.发射子弹 说起来小编学Unity差不多一个月了&#xff0c;都是利用上班摸鱼时间学的&#xff08;doge.jpg&…

java+springboot校园体育场地预约预订使用系统vue+ssm

研究内容和研究方法 1.研究内容 网站主要包括管理员和用户两个部分&#xff0c;用户可以登录与注册自己的基本信息、查询哪些场地可以使用、提前预约场地、取消预约的场地、使用完场地后进行缴费。管理员可以审批用户的注册信息、对用户信息进行增删改查、查询场地的使用情况、…

【C++干货基地】C++引用与指针的区别:深入理解两者特性及选择正确应用场景

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位铁汁们好啊&#xff0c;我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发&#xff0c;不知道各位的…

秋招面试—JS篇

2024 JavaScript面试题 1.new 操作符的工作原理 ①.创建一个新的空对象 ②.将这个对象的原型设置为函数的 prototype 对象 ③.让函数的this指向该对象&#xff0c;为函数添加属性和方法 ④.最后返回这个对象 2.什么是DOM&#xff0c;什么是BOM? DOM&#xff1a;文档对象…

AI日报:谷歌的“双子时代”:将第二代人工智能嵌入其所做的一切

谷歌强大的大型多模式模式Gemini正在进军搜索、广告、云、Bard等领域。Bard的付费订阅即将到来吗&#xff1f; 文章目录 一览Bard订阅即将到来&#xff1f;一代人工智能进入谷歌广告YouTube正在崛起收入上升但股价下跌 一览 谷歌首席执行官、母公司Alphabet的桑达尔皮查伊表示&…

Kotlin 协程:用源码来理解 ‘viewModelScope‘

Kotlin 协程&#xff1a;用源码来理解 ‘viewModelScope’ Kotlin 协程是 Kotlin 语言的一大特色&#xff0c;它让异步编程变得更简单。在 Android 开发中&#xff0c;我们经常需要在后台线程执行耗时操作&#xff0c;例如网络请求或数据库查询&#xff0c;然后在主线程更新 UI…

VBoxManage 命令行使用

VBoxManage&#xff1a; 序号命令作用1VBoxManage list vms# 查看当前所有虚拟机2VBoxManage list runningvms # 查看当前正在运行的虚拟机3VBoxManage startvm 虚拟机名 --type gui # 启动虚拟机4VBoxManage startvm 虚拟机名 --type headless# 无前端图形界面方式启动虚拟机…

Elasticsearch:构建自定义分析器指南

在本博客中&#xff0c;我们将介绍不同的内置字符过滤器、分词器和分词过滤器&#xff0c;以及如何创建适合我们需求的自定义分析器。更多关于分析器的知识&#xff0c;请详细阅读文章&#xff1a; 开始使用 Elasticsearch &#xff08;3&#xff09; Elasticsearch: analyzer…

Debezium发布历史101

原文地址&#xff1a; https://debezium.io/blog/2021/01/07/debezium-1-4-final-released/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. Debezium 1.4.0.Final 发布 2021 年 1 月 7 日 作者&#xff1a; 克里…

C#中的WebApi响应Accept头,自动返回xml或者json

Global.asax.cs中的Application_Start方法添加 GlobalConfiguration.Configuration.Formatters.Clear(); GlobalConfiguration.Configuration.Formatters.Add(new XmlMediaTypeFormatter()); GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter())…

工作七年,对消息推送使用的一些经验和总结

前言&#xff1a;不管是APP还是WEB端都离不开消息推送&#xff0c;尤其是APP端&#xff0c;push消息&#xff0c;小信箱消息&#xff1b;WEB端的代办消息等。因在项目中多次使用消息推送且也是很多项目必不可少的组成部分&#xff0c;故此总结下供自己参考。 一、什么是消息推…

Vue.js 中子组件向父组件传值的方法

Vue.js 是一款流行的 JavaScript 前端框架&#xff0c;它提供了一套完整的工具和 API&#xff0c;使得开发者可以更加高效地构建交互式的 Web 应用程序。其中&#xff0c;组件化是 Vue.js 的一个核心概念&#xff0c;通过组件化可以将一个复杂的应用程序拆分成多个独立的部分&a…

3D应用开发平台HOOPS Platforms优化制造流程和数字化转型

Tech Soft 3D公司的HOOPS Platform &#xff08;包括HOOPS Native Platform 和HOOPS Web Platform&#xff09;&#xff0c;是一种用于开发顶级3D软件的集成技术。具有高性能3D图形&#xff0c;准确&#xff0c;快速的CAD数据转换&#xff0c;3D数据发布以及与流行的建模内核的…

iOS_Xcode_LLDB调试常用命令

文章目录 结构常用命令&#xff1a;1、流程控制&#xff1a;2、常用命令3、进程信息&#xff1a;4、寄存器&#xff1a;register5、镜像&#xff1a;image6、内存&#xff1a;memory7、符号断点&#xff1a;breakpoint8、内存断点&#xff1a;watchpoint9、Tips&#xff1a; 结…

音视频数字化(音频数字化)

在音视频领域,人们始终追求无限还原现场效果,因此音频越逼真越好,视频越清晰越好。之所以我们需要将音视频信号由模拟转为数字,目的是在录制、存储、编辑、复制、回放等环节的不失真,尽量保持原有细节,不因以上操作,导致音画的质量下降。 为此,视频系统分辨率越来越高,…

【iOS ARKit】手动配置环境探头

在上节中我们已经了解了环境探头以及如何使用自动环境探头&#xff0c;这节一起了解如何使用手动配置环境探头。 在使用自动环境反射时&#xff0c;开发人员无须进行有关环境反射的任何操作&#xff0c;只需要设置自动环境反射即可&#xff0c;其余工作完全由 RealityKit 自动完…

ArcGIS Pro字段编号相关代码

字段属于SHP文件的重要组成部分&#xff0c;在某些时候需要对字段进行编号&#xff0c;这里为大家介绍一下字段编号相关的代码&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的POI数据&#xff0c;除了POI数据&#xff0c;常见的GIS数据都可…

全面掌握Django的web框架Django Rest_Framework(一)

文章目录 Django Rest_Framework1. DRF介绍2.DRF特点3.环境安装与配置&#xff08;1&#xff09;DRF需要以下依赖&#xff08;2&#xff09;创建django项目 4.序列化器的使用&#xff08;1&#xff09;创建序列化器 5. 反序列化器使用 Django Rest_Framework 1. DRF介绍 Djan…

springboot141夕阳红公寓管理系统的设计与实现

基于Spring Boot的夕阳红公寓管理系统的设计与实现 摘 要 如今社会上各行各业&#xff0c;都在用属于自己专用的软件来进行工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。互联网的发展&#xff0c;离不开一些新的技术&#xff0c;而新技术的…