SpringBoot使用 AOP 实现自定义日志记录并保存在Mysql

本文主要介绍在 Spring Boot 中使用 AOP 实现自定义日志记录并保存在 Mysql 的方法。先阐述记录日志的重要性及传统方式的弊端,提出新方式,即通过创建自定义注解、切面类等,将重要日志存到数据库,还给出了创建日志表、注解类、切面类及在代码中使用的具体步骤和存储结果。

记录日志的重要性

记录日志在开发中起着至关重要的作用。它不仅可以提高系统的可靠性、安全性和性能,还可以为故障排查、业务分析和合规要求提供支持。在Spring Boot中,我们通常使用日志框架如Logback、Log4j等进行日志记录。这些框架提供了灵活的配置选项和丰富的日志级别和输出格式,使得日志记录变得方便且易于管理。

传统记录日志的弊端

然而,传统的日志记录方式通常是将日志记录在text文本中,并且会定期删除。这种方式存在一些局限性,比如无法轻松地获取很久之前的日志、进行日志数据的统计和分析整理、实现数据的关联和追踪等功能。此外,对于一些重要的日志,我们可能希望具备更高的安全性和隐私性,或者需要对日志数据进行备份和恢复,甚至希望能够实现日志数据的共享。这就需要我们思考一种新的记录日志的方式。
在实际开发中,我们通常需要更多的功能来满足日志记录的需求:

  • 查询历史日志:我们可能需要获取很久之前的日志数据,以便进行历史记录的查看和分析。
  • 统计和分析日志数据:对日志数据进行统计和整理,以便进行业务分析和系统性能优化。
  • 数据关联和追踪:需要将日志数据与其他数据进行关联,以实现对系统操作和业务流程的追踪和监控。
  • 提高日志的安全性和隐私性:确保敏感信息不被泄露,对日志数据进行安全加密和权限控制。
  • 日志数据备份和恢复:对重要的日志数据进行定期备份,以便在系统故障或数据丢失时进行快速恢复。
  • 数据共享:需要能够方便地与其他系统或团队共享和交换日志数据,以实现更全面的系统监控和分析。

以上这些功能是我们在日志记录过程中经常会遇到的需求,对于如何实现这些功能,我们需要综合考虑技术、业务和安全等方面的因素,以便为系统的可靠性、安全性和性能提供更全面的支持。

使用AOP将日志存储到Mysql中

一种解决方案是使用AOP(面向切面编程)结合自定义注解来实现日志存储。AOP允许我们在程序执行的特定点织入代码,而自定义注解则可用于标记需要记录日志的方法。通过这种方式,我们可以实现灵活且精准的日志记录,并在需要时将重要的日志存储到数据库中。
为了实现这一目标,我们可以按照以下步骤进行:
首先,创建一个自定义注解,用来标记需要记录日志的方法。该注解可以包含一些额外的信息,如操作描述等,以便于更详细地记录日志。
其次,创建一个切面类,该类包含切入点和通知。在切面类中,我们可以定义通知,在方法执行前后、抛出异常时等特定时刻进行日志记录。在通知中,我们可以获取方法的参数、返回值等信息,并将这些信息记录到数据库中。
在需要记录日志的方法上添加自定义注解。通过在方法上添加自定义注解,我们可以指示AOP在执行该方法时进行日志记录,并将日志存储到数据库中。
通过以上步骤,我们就可以实现对日志存储的优化和扩展。这种基于AOP和自定义注解的日志记录方式具有很多优点,包括灵活性高、精细化的记录方式、易于管理和扩展等。同时,通过将重要的日志存储到数据库中,我们可以轻松地获取历史日志、进行统计分析、实现数据关联和追踪等功能。

SpringBoot 整合 AOP

Spring Boot 整合Aop

我们需要实现的目的

    1. 自定义日志记录,包括记录系统接口的日志以及保存到数据库。 (@Log 注解标注需要记录日志的方法或类)
    1. 创建注解 @Log 来指定需要记录的模块、功能等信息,以便进行日志记录。
  • 30 创建切面类 LogAspect,用于记录请求信息、当前用户信息、错误信息等,并将这些信息保存到数据库中

步骤

1、创建一个all_data_log自定义日志表

主要定义了操作日志的一些基本的信息,用来对我们AOP自定义的日志进行存储。

CREATE TABLE `all_data_log` (
  `user_id` int DEFAULT NULL COMMENT '用户名',
  `url` varchar(512) DEFAULT NULL COMMENT '接口',
  `ip` varchar(100) DEFAULT NULL COMMENT 'ip地址',
  `param` text COMMENT '接口参数',
  `time` datetime DEFAULT NULL COMMENT '时间',
  `method` varchar(100) DEFAULT NULL COMMENT '方法',
  `project` varchar(100) DEFAULT NULL COMMENT '项目'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='自定义日志表';

2、创建一个注解类 Log

创建一个注解类 Log,定义在类和方法上的注解。注解中可以包括模块、功能、操作人类别、是否保存请求和响应参数等信息。

/**
 * 自定义操作日志记录注解
 */
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{
    /**
     * 模块 
     */
    public String title() default "";

    /**
     * 功能
     */
    public BusinessType businessType() default BusinessType.OTHER;

    /**
     * 操作人类别
     */
    public OperatorType operatorType() default OperatorType.MANAGE;

    /**
     * 是否保存请求的参数
     */
    public boolean isSaveRequestData() default true;

    /**
     * 是否保存响应的参数
     */
    public boolean isSaveResponseData() default true;
}
3. 创建一个切面类

创建一个切面类 LogAspect,用于记录系统接口的日志,并根据需要将日志信息保存到数据库中。在切面类中,可以根据注解中的信息记录请求的URL、方法、IP地址、参数、当前用户信息、错误信息等,并将这些信息保存到数据库中。

@Component
@Aspect
public class LogAspect {


    @Autowired
    private RedisCache redisCache;

    @Autowired
    private LogAspect logAspect;

    @Value("${token.header}")
    private String header;

    /**
     * 定义一个开关 可以随时关闭这个切面
     */
    @Value("${aspect.switch}")
    private Boolean aBoolean;


    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
    public void doBefore(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
        handle(joinPoint, jsonResult, null);
    }

    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
        handle(joinPoint, null, e);
    }

    private void handle(JoinPoint joinPoint, Object jsonResult, Exception e) {
        try {
            if (aBoolean) {
                ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = attributes.getRequest();

                HashMap<String, Object> map = new HashMap<>();
                // 获取请求的URL
                map.put("url", request.getRequestURL().toString());

                // 获取请求的方法
                map.put("method", request.getMethod());

                // 获取请求的IP地址
                map.put("ip", request.getRemoteAddr());

                // 获取请求的参数
                Object[] args = joinPoint.getArgs();
                String params = "";
                try {
                    if (args != null && args.length > 0) {
                        for (Object arg : args) {
                            if (arg instanceof MultipartFile[]) {
                                params = "files";
                            }
                        }
                        if (!params.equals("files")) {
                            params = JSON.toJSONString(args[0]);
                        }
                    }
                } catch (Exception e1) {
                    params = "参数解析失败";
                }
                map.put("params", params);

                // 获取当前的用户
                String token = request.getHeader(header);
                String userId = "";
                if (ObjectUtils.isNotEmpty(token)) {
                    LoginUser loginUser = SecurityUtils.getLoginUser();
                    if (ObjectUtils.isNotEmpty(loginUser)) {
                        userId = loginUser.getUserId().toString();
                    }
                }
                map.put("userId", userId);

                //记录错误信息
                if (e != null) {
                    map.put("errorMsg", StringUtils.substring(e.getMessage(), 0, 2000));
                }

                //当前时间
                map.put("time", DateUtils.getTime());

                // 是否需要保存result,参数和值
                if (StringUtils.isNotNull(jsonResult)) {
                    map.put("result", StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
                }

                // 异步 保存数据库
                AsyncManager.me().execute(AsyncFactory.recordOper(map));
            }
        } catch (Exception exp) {
            exp.printStackTrace();
        }
    }
}
4. 如何在代码中使用

在需要记录日志的方法上使用 @Log 注解,指定相应的模块、功能等信息,以便进行日志记录。

/**
 * 新增商品
 */
@Log(title = "新增商品", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody YdCommAttr ydCommAttr)
{
    return toAjax(ydCommAttrService.insertYdCommAttr(ydCommAttr));
}

5. 存储的结果

可以看到我们的切面完美的记录了我们想要记录的接口中的日志数据,以便于我们日后通过关系型数据库Musql去统计和分析这些数据。
在这里插入图片描述

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

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

相关文章

对golang的io型进程进行off-cpu分析

背景&#xff1a; 对于不能占满所有cpu核数的进程&#xff0c;进行on-cpu的分析是没有意义的&#xff0c;因为可能程序大部分时间都处在阻塞状态。 实验例子程序&#xff1a; 以centos8和golang1.23.3为例&#xff0c;测试下面的程序&#xff1a; pprof_netio.go package m…

CTF入门:以Hackademic-RTB1靶场为例初识夺旗

一、网络扫描 靶机ip地址为192.168.12.24 使用nmap工具进行端口扫描 nmap -sT 192.168.12.24 二、信息收集 1、80端口探索 靶机开放了80和22端口&#xff0c;使用浏览器访问靶机的80端口&#xff0c;界面如下&#xff1a; 点击target发现有跳转&#xff0c;并且url发生相应变…

腾讯云智能结构化OCR:以多模态大模型技术为核心,推动跨行业高效精准的文档处理与数据提取新时代

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大三学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

SD ComfyUI工作流 根据图像生成线稿草图

文章目录 线稿草图生成SD模型Node节点工作流程工作流下载效果展示线稿草图生成 该工作流的设计目标是将输入的图像转换为高质量的线稿风格输出。其主要流程基于 Stable Diffusion 技术,结合文本和图像条件,精确生成符合预期的线条艺术图像。工作流的核心是通过模型的条件设置…

Zabbix6.0升级为6.4

为了体验一些新的功能&#xff0c;比如 Webhook 和问题抑制等&#xff0c;升级个小版本。 一、环境信息 1. 版本要求 一定要事先查看官方文档&#xff0c;确认组件要求的版本&#xff0c;否则版本过高或者过低都会出现问题。 2. 升级前后信息 环境升级前升级后操作系统CentOS…

网络安全概论——身份认证

一、身份证明 身份证明可分为以下两大类 身份验证——“你是否是你所声称的你&#xff1f;”身份识别——“我是否知道你是谁&#xff1f;” 身份证明系统设计的三要素&#xff1a; 安全设备的系统强度用户的可接受性系统的成本 实现身份证明的基本途径 所知&#xff1a;个…

LabVIEW中的“Synchronize with Other Application Instances“

在LabVIEW中&#xff0c;“Synchronize with Other Application Instances”是一个常见的提示或错误&#xff0c;通常出现在尝试并行运行多个LabVIEW实例时&#xff0c;特别是当你打开多个VI或项目时。这个问题可能影响程序的执行流程&#xff0c;导致不同实例之间的数据同步或…

OpenGL ES 01 渲染一个四边形

项目架构 着色器封装 vertex #version 300 es // 接收顶点数据 layout (location 0) in vec3 aPos; // 位置变量的属性位置值为0 layout (location 1) in vec4 aColors; // 位置变量的属性位置值为1 out vec4 vertexColor; // 为片段着色器指定一个颜色输出void main() {gl…

Maven 生命周期

文章目录 Maven 生命周期- Clean 生命周期- Build 生命周期- Site 生命周期 Maven 生命周期 Maven 有以下三个标准的生命周期&#xff1a; Clean 生命周期&#xff1a; clean&#xff1a;删除目标目录中的编译输出文件。这通常是在构建之前执行的&#xff0c;以确保项目从一个…

力学笃行(二)Qt 示例程序运行

Qt 示例程序运行 1. Qt 示例程序简介1.1 编译报错问题: qt: error: cannot open C:\Users\我的电脑\AppData\Local\Temp\main.obj.34588.15.jom for write 2. Qt 示例程序主要分类2.1 Widgets 示例2.2 Qt Quick 示例2.3 3D 示例2.4 多媒体示例2.5 网络示例2.6 数据库示例2.7 图…

机器学习基础算法 (二)-逻辑回归

python 环境的配置参考 从零开始&#xff1a;Python 环境搭建与工具配置 逻辑回归是一种用于解决二分类问题的机器学习算法&#xff0c;它可以预测输入数据属于某个类别的概率。本文将详细介绍逻辑回归的原理、Python 实现、模型评估和调优&#xff0c;并结合垃圾邮件分类案例进…

《机器学习》支持向量机

目录 结构风险&#xff08;Structural Risk&#xff09;和经验风险&#xff08;Empirical Risk&#xff09; 经验风险&#xff08;Empirical Risk&#xff09;&#xff1a; 结构风险&#xff08;Structural Risk&#xff09;&#xff1a; L0范数&#xff1a; L0范数是指向…

Converseen:全能免费批量图像处理专家

还在为繁琐的图像处理任务而烦恼吗&#xff1f;Converseen 是一款功能卓越且完全免费的批量图像处理软件&#xff0c;它以其卓越的易用性、惊人的处理速度和强大的实用性赢得了用户的广泛赞誉。无论您是专业摄影师、设计师&#xff0c;还是仅仅需要处理大量图片&#xff0c;Con…

Linux下基于最新稳定版ESP-IDF5.3.2开发esp32s3入门任务间的通讯-信号量【入门三】

继续上一篇任务创建 【Linux下基于最新稳定版ESP-IDF5.3.2开发esp32s3入门任务创建【入门二】-CSDN博客】 今天要实现再创建一个任务。【二值和互斥都进行测试】 ①、通过任务A发送一个信号量&#xff0c;另一个任务得到信号量后再发送helloworld。 ②、两个任务通过互斥信…

windows安装Elasticsearch及增删改查操作

1.首先去官网下载Elasticsearch 下载地址 我这里选择的是7.17.18 选择windows版本 下载完成后解压是这样的 下载完成后点击elasticsearch.bat启动elasticsearch服务 输入http://localhost:9200看到如下信息说明启动成功。 还有记得修改elasticsearch.yml文件&#xff0c;…

虚拟机VMware的安装问题ip错误,虚拟网卡

要么没有虚拟网卡、有网卡远程连不上等 一般出现在win11 家庭版 1、是否IP错误 ip addr 2、 重置虚拟网卡 3、查看是否有虚拟网卡 4、如果以上检查都解决不了问题 如果你之前有vmware 后来卸载了&#xff0c;又重新安装&#xff0c;一般都会有问题 卸载重装vmware: 第一…

户籍管理系统的设计与实现【源码+文档+部署讲解】

目 录 摘 要 Abstract 1 系统大概 1.1 系统背景 1.2 研究意义 1.3 本文结构 1.4 开发平台简介 1.4.1 Java语言的特点 1.4.2 J2EE概述 1.4.3 B/S结构概述 1.4.4 MySQL 1.4.5 Tomcat 1.4.6 JSP.NET 1.4.7 开发流程 1.4.8 Eclipse简介 1.4.9 of…

【Rust自学】5.1. 定义并实例化struct

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 5.1.1. 什么是struct struct的中文意思为结构体&#xff0c;它是一种自定义的数据类型&#xff0c;它允许程序为相关联的值命名和打包&am…

【自动驾驶】单目摄像头实现自动驾驶3D目标检测

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;传知代码 欢迎大家点赞收藏评论&#x1f60a; 目录 概述算法介绍演示效果图像推理视频推理 核心代码算法处理过程使用方式环境搭建下载权重文件pytorch 推理&#xff08;自动选择CPU或GPU&#x…

Python+OpenCV系列:AI看图识人、识车、识万物

在人工智能风靡全球的今天&#xff0c;用 Python 和 OpenCV 结合机器学习实现物体识别&#xff0c;不仅是酷炫技能&#xff0c;更是掌握未来的敲门砖。本篇博文手把手教你如何通过摄像头或图片输入&#xff0c;识别人、动物、车辆及其他物品&#xff0c;让你的程序瞬间具备 AI …