AOP应用之系统操作日志

本文演示下如何使用AOP,去实现系统操作日志功能。

实现步骤

  1. 引入AOP包
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-aop</artifactId>
     <version>2.6.6</version>
 </dependency>
  1. 定义数据模型
package com.angel.ocean.domain.entity;

import lombok.Data;
import java.util.Date;

@Data
public class Syslog {
    /**
     * 主键
     **/
    private Long id;
    /**
     * ip 地址
     **/
    private String ip;
    /**
     * 类名
     **/
    private String className;
    /**
     * 方法名称
     **/
    private String methodName;
    /**
     * 传参
     **/
    private String params;
    /**
     * 执行结果, true-成功,false-失败
     **/
    private boolean status;
    /**
     * 响应信息
     **/
    private String response;
    /**
     * 业务类型
     **/
    private String remark;
    /**
     * 触发时间
     **/
    private Date createTime;
    /**
     * 操作用户
     **/
    private String createBy;
}
  1. 定义系统日志注解SyslogAnno
package com.angel.ocean.annotation;

import java.lang.annotation.*;

/**
 * 定义系统日志注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SyslogAnno {

    String value() default "";

}
  1. 定义切面SyslogAspect
package com.angel.ocean.aspect;

import com.alibaba.fastjson2.JSON;
import com.angel.ocean.annotation.SyslogAnno;
import com.angel.ocean.domain.entity.Syslog;
import com.angel.ocean.runner.SyslogHandlerTask;
import com.angel.ocean.util.LogDataUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 1. 日志切面
 */
@Slf4j
@Aspect
@Component
public class SyslogAspect {

    @Pointcut("@annotation(com.angel.ocean.annotation.SyslogAnno)")
    public void logPointCut() {
    }

    @AfterReturning(value = "logPointCut()", returning = "result")
    public void normalLog(JoinPoint point, Object result) {
        try {
            Syslog syslog = getSysLog(point);
            syslog.setStatus(true);
            syslog.setResponse(JSON.toJSONString(result));
            SyslogHandlerTask.LOG_QUEUE.offer(syslog);
        } catch (Exception e) {
            log.error("SyslogAspect.normalLog() error. ", e);
        }
    }

    @AfterThrowing(value = "logPointCut()", throwing = "throwable")
    public void exceptionLog(JoinPoint point, Throwable throwable) {
        try {
            Syslog syslog = getSysLog(point);
            syslog.setStatus(false);
            syslog.setResponse(throwable.getMessage());
            SyslogHandlerTask.LOG_QUEUE.offer(syslog);
        } catch (Exception e) {
            log.error("SyslogAspect.exceptionLog() error. ", e);
        }
    }

    private Syslog getSysLog(JoinPoint joinPoint) {

        Syslog sysLog = new Syslog();

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        SyslogAnno sysLogAnno = method.getAnnotation(SyslogAnno.class);
        if (sysLogAnno != null) {
            sysLog.setRemark(sysLogAnno.value());
        }

        // 请求的 类名、方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setClassName(className);
        sysLog.setMethodName(methodName);

        // 请求的参数
        Object[] args = joinPoint.getArgs();
        try {
            List<String> list = new ArrayList<>();
            for (Object o : args) {
                list.add(JSON.toJSONString(o));
            }
            sysLog.setParams(list.toString());
        } catch (Exception e) {
            log.error("SyslogAspect.saveLog() error.", e);
        }

        sysLog.setIp(LogDataUtil.getIP());
        sysLog.setCreateBy(LogDataUtil.getUserId());
        sysLog.setCreateTime(new Date());

        return sysLog;
    }
}

工具类

package com.angel.ocean.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;

@Slf4j
public class LogDataUtil {

    private LogDataUtil() {}

    /**
     *  获取用户IP地址
     */
    public static String getIP() {
        String ip = "";
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            ip = request.getRemoteAddr();
        } catch (Exception e) {
            log.error("GetIPException", e);
        }
        return ip;
    }

    /**
     * 获取用户ID
     */
    public static String getUserId() {
        String userId = "";
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            userId = request.getHeader("userId");
        } catch (Exception e) {
            log.error("GetUserIdException", e);
        }
        return userId;
    }
}
  1. 定义日志数据处理SyslogHandlerTask
package com.angel.ocean.runner;

import cn.hutool.core.collection.CollUtil;
import com.angel.ocean.domain.entity.Syslog;
import com.angel.ocean.service.SyslogService;
import com.google.common.collect.Queues;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class SyslogHandlerTask implements CommandLineRunner {

    @Resource
    private SyslogService syslogService;

    /**
     * 操作日志队列
     */
    public static final BlockingQueue<Syslog> LOG_QUEUE = new LinkedBlockingQueue<>();

    @Override
    public void run(String... strings) throws Exception {
        new Thread(() -> {
            List<Syslog> SyslogList = new ArrayList<>();
            while (true) {
                try {
                    Queues.drain(LOG_QUEUE, SyslogList, 100, 500, TimeUnit.MILLISECONDS);
                    if (CollUtil.isNotEmpty(SyslogList)) {
                        syslogService.batchInsert(SyslogList);
                        SyslogList.clear();
                    } else {
                        Thread.sleep(500);
                    }
                } catch (Exception e) {
                    log.error("SyslogHandlerTask error={}", e.getMessage(), e);
                }
            }
        }, "Syslog_Props_Mysql").start();
    }
}
  1. 打包成系统操作日志SDK (ocean-log)

如何使用

继承系统操作日志SDK

<dependency>
    <groupId>com.angel.ocean</groupId>
    <artifactId>ocean-log</artifactId>
    <version>1.0.0</version>
</dependency>

在Api的添加/修改/删除等方法上,添加SyslogAnno注解

@ApiModelProperty(value = "保存角色信息表")
@PostMapping("save")
@SyslogAnno("添加角色")
public ApiResult<?> save(@RequestBody SysRoleDTO dto) {
    service.save(dto);
    return ApiResult.success();
}

实例验证

接口调用
在这里插入图片描述系统操作日志数据
在这里插入图片描述

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

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

相关文章

AI大眼萌探索 AI 新世界:Ollama 使用指南【1】

在人工智能的浪潮中&#xff0c;Ollama 的出现无疑为 Windows 用户带来了一场革命。这款工具平台以其开创性的功能&#xff0c;简化了 AI 模型的开发与应用&#xff0c;让每一位爱好者都能轻松驾驭 AI 的强大力量。大家好&#xff0c;我是AI大眼萌&#xff0c;今天我们将带大家…

颠覆多跳事实验证!Causal Walk 前门调整技术引领去偏新纪元

Causal Walk: Debiasing Multi-Hop Fact Verifcation with Front-Door Adjustment 论文地址: Causal Walk: Debiasing Multi-Hop Fact Verification with Front-Door Adjustment| Proceedings of the AAAI Conference on Artificial Intelligencehttps://ojs.aaai.org/index.p…

基于Vue-cli脚手架搭建项目使用ElementUI组件

项目结构 node_modules 项目依赖的外部组件文件放在此处,例如vue public index.html是对外提供的唯一的html文件 src assets 存放静态文件 例如图片 css js等文件 components 里面存放的是组件 App.vue是组件 main.js是项目配置文件 package.json存放的是项目依赖的…

C# Onnx Yolov5 水果识别,人员识别,物品识别 人工智能

目录 先上效果 来电废话&#xff0c;但实用 网络成功案例实践易失败的原因 万物检测涉及技术 下载合集 关键代码 全部代码 实操vs2022安装关键 YOLO V5核心库编译 编写自己识别软件 更新相关依赖 标注字库文件 测试效果 名词解释YOLO 名词解释ONNX 源码 直播教…

基于Java的火车订票管理系统【附源码】

火车订票管理登录 摘要&#xff1a;随着我国铁路交通的不断发展&#xff0c;简单的窗口售票模式已经不能满足方便人们出行的目的。采用先进的网络技术开发出方便快捷的火车票订票系统是现代客运业务发展的必然需求。本次设计的火车票订票系统通过访问主页&#xff0c;可以实现…

Linux PXE高效批量装机

部署PXE远程安装服务 在大规模的 Linux 应用环境中&#xff0c;如 Web 群集、分布式计算等&#xff0c;服务器往往并不配备光驱设备&#xff0c;在这种情况下&#xff0c;如何为数十乃至上百台服务器裸机快速安装系统呢?传统的USB光驱、移动硬盘等安装方法显然已经难以满足需…

VC++支持断点续下或续传的功能

VC使用多线程和Socket实现断点续下 一、断点续下的基本原理&#xff1a; 1.断点续传的理解可以分为两部分&#xff1a;一部分是断点&#xff0c;一部分是续传。断点的由来是在下载过程中&#xff0c;将一个下载文件分成了多个部分&#xff0c;同时进行多个部分一起的下载&…

Python武器库开发-武器库篇之ThinkPHP 5.0.23-RCE 漏洞复现(六十四)

Python武器库开发-武器库篇之ThinkPHP 5.0.23-RCE 漏洞复现&#xff08;六十四&#xff09; 漏洞环境搭建 这里我们使用Kali虚拟机安装docker并搭建vulhub靶场来进行ThinkPHP漏洞环境的安装&#xff0c;我们进入 ThinkPHP漏洞环境&#xff0c;可以 cd ThinkPHP&#xff0c;然…

每日一题——Python代码实现PAT乙级1048 数字加密(举一反三+思想解读+逐步优化)五千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 初次尝试 再次尝试 代码点评 代码结构 时间复杂度 空间复杂度 优化建议 我要更强…

【Linux】IP协议、以太网帧格式

目录 网络层IP协议协议头格式网段划分分类划分法特殊的 IP 地址IP 地址的数量限制私有 IP 地址和公有 IP 地址路由路由表生成算法 数据链路层以太网以太网帧格式认识 MAC 地址ARP协议ARP数据报格式 ARP 协议的工作流程ARP欺骗 DNShosts 文件域名的层级关系域名服务器分类域名解…

day3-xss漏洞(米斯特web渗透测试)

day3-xss漏洞&#xff08;米斯特web渗透测试&#xff09; XSSXss种类三种反射型1.反射型xss2.存储型xss3.DOM型xss XSS Xss有一部分是前端的有一部分不是前端的&#xff0c;我们来看一下&#xff0c;昨天的HTML注入修复方法应灵活使用。 HTML注入是注入一段HTML&#xff0c;那…

mysql中in参数过多该如何优化

优化方式概述 未优化前 SELECT * FROM rb_product rb where sku in(1022044,1009786)方案2示例 public static void main(String[] args) {//往list里面设置3000个值List<String> list new ArrayList<>();for (int i 0; i < 3000; i) {list.add(""…

8.DELL R730服务器对RAID5进行扩容

如果服务器的空间不足了&#xff0c;如何进行扩容&#xff1f;我基本上按照如何重新配置虚拟磁盘或添加其他硬盘来进行操作。我的机器上已经有三块硬盘了&#xff0c;组了Raid5&#xff0c;现在再添加一块硬盘。 先把要添加的硬盘插入服务器&#xff0c;无论是在IDRAC还是管理…

Phi-3 模型手机部署教程(微软发布的可与GPT-3.5媲美的小模型)

前面几篇博文&#xff0c;老牛同学和大家一起在个人电脑部署了Qwen2、GLM4、Llama3、ChatTTS和Stable Diffusion等 LLM 大模型&#xff0c;也通过 API 和 WebUI 的方式完成了体验。 但是这些大模型因为部署在个人电脑本地&#xff0c;不能够随时携带。如果能在手机上部署大模型…

python判断语句

目录 布尔类型和比较运算符if语句的基本格式if else 语句if elif else 语句判断语句的嵌套 布尔类型和比较运算符 1、布尔类型 bool布尔类型只有两个结果&#xff1a;真或假 布尔类型的字面量&#xff1a; True 表示真&#xff08;是、肯定&#xff09; False 表示假&#x…

Python+Pytest+Yaml+Request+Allure框架源代码之(一)common公共方法封装

common模块&#xff1a; get_path.py&#xff1a;获取路径方法 # -*- coding: UTF-8 -*- import os# 项目根目录 BASE_DIR os.path.dirname(os.path.dirname(os.path.abspath(__file__)))# 配置文件目录 CONFIG_DIR os.path.join(BASE_DIR,config)# 测试用例文件目录 TESTCA…

【数据结构导论】自考笔试题:伪代码练习题汇总 1

目录 一、开源项目推荐 二、线性表的基本运算在单链表上的实现 &#xff08;1&#xff09;初始化 &#xff08;2&#xff09;插入 p 指向的新结点的操作 &#xff08;3&#xff09;删除 *p 节点 三、循环链表 &#xff08;1&#xff09;在单链表中 &#xff08;2&…

双指针问题2

文章目录 1. 有效三角形的个数&#xff08;611&#xff09;2. 查找总价格为目标值的两个商品&#xff08;LCR179&#xff09;3. 三数之和&#xff08;15&#xff09;4. 四数之和&#xff08;18&#xff09; 1. 有效三角形的个数&#xff08;611&#xff09; 题目描述&#xff…

Stable Diffusion初体验——基于机器学习通过神经网络的强大AI平台

文章目录 前言最新热门活动&#xff01;&#xff01;平台介绍 一.创建应用 Stable Diffusion WebUI初始化上传模型&#xff0c;VAE&#xff0c;lora 介绍sd模型&#xff0c;vae&#xff0c;lora模型进入应用文生图工作区调参区图生图 结语小程序活动——6.20火热上线&#x1f5…

消息队列MQ相关面试题

消息队列MQ相关面试题 1 RabbitMQ 1.1 你们项目中哪里用到了RabbitMQ ? 难易程度&#xff1a;☆☆☆ 出现频率&#xff1a;☆☆☆☆ 我们项目中很多地方都使用了RabbitMQ , RabbitMQ 是我们项目中服务通信的主要方式之一 , 我们项目中服务通信主要有二种方式实现 : 通过Fei…