AOP应用之系统操作日志

news2024/11/23 12:05:36

本文演示下如何使用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();
}

实例验证

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Apache Doris】周FAQ集锦:第 7 期

【Apache Doris】周FAQ集锦&#xff1a;第 7 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目&#xff01; 在这个栏目中&#xff0c;每周将筛选社区反馈的热门问题和话题&#xff0c;重点回答并进行深入探讨。旨在为广大用户和…

YYU-5/80-260mm型钢筋残余变形测试仪 电子引伸计

YYU-5/80-260mm型钢筋接头专用引伸计&#xff0c;是按照《JGJ 107 2010 钢筋技术连接技术规程》的技术要求设计的&#xff0c;专门用于测试钢筋接头残余变形的双向平均引伸计&#xff0c;其标距可以根据钢筋直径要求进行调整。 完全符合《JGJ 107 2010 钢筋技术连接技术规程》…

Vulnhub--OS-HACKNOS-2.1

渗透复现 目标站点为wordpress&#xff0c;通过wpscan进行漏洞扫描发现漏洞插件 通过漏洞插件存在的目录穿越漏洞成功读取/etc/passwd文件中flag用户的密码 SSH登录flag用户后在备份文件中找到rohit用户的密码 切换rohit用户&#xff0c;rohit用户能够以root权限执行任何文…

靠3个字寻求机会,情商不够,别勉强自己

之前我分享了一篇文章寻求一个自由职业的前端伙伴&#xff0c;吸引了好几位朋友来咨询合作&#xff0c;中间出现了不少插曲&#xff0c;好在结果是令人满意的。 作为一名初次创业者&#xff0c;我承认很多地方做的不是那么到位&#xff0c;比如招聘合作伙伴&#xff0c;理想的状…

监控 Prometheus源码安装实战和动态更新 Centos7

安装go环境 下载go安装包 #创建文件夹 mkdir /usr/local/software #进入文件夹 cd /usr/local/software #下载安装包 wget https://dl.google.com/go/go1.17.6.linux-amd64.tar.gz配置go环境变量 #解压 tar -zxvf go1.17.6.linux-amd64.tar.gz#配置环境变量 echo "exp…

AudioSep:从音频中分离出特定声音(人声、笑声、噪音、乐器等)本地一键整合包下载

AudioSep是一种 AI 模型&#xff0c;可以使用自然语言查询进行声音分离。这一创新性的模型由Audio-AGI开发&#xff0c;使用户能够通过简单的语言描述来分离各种声音源。 比如在嘈杂的人流车流中说话的录音中&#xff0c;可以分别提取干净的人声说话声音和嘈杂的人流车流噪声。…

集合注意事项

目录 我们为什么要用到集合中的迭代器 List实现类的循环遍历 Set集合 HashSet TreeSet Map Hashmap Treemap Hashtable map的遍历方式 Collections的一些静态方法 我们为什么要用到集合中的迭代器 List实现类的循环遍历 如图我们对arraylist中加入了三个相同的“a”…

汽车OTA--Flash RWW属性为什么这么重要

目录 1. OTA与RWW 1.1 FOTA需求解读 1.2 什么是RWW 2.主流OTA方案 2.1 单Bank升级 2.2 基于硬件A\B SWAP的FOTA方案 2.3 基于软件实现的FOTA方案 3.小结 1. OTA与RWW 1.1 FOTA需求解读 CP AUTOSAR R19-11首次提出了FOTA的概念&#xff0c;针对FOTA Target ECU提出了多…

适耳贴合的气传导耳机,带来智能生活体验,塞那Z50耳夹耳机上手

现在大家几乎每天都会用到各种AI产品&#xff0c;蓝牙耳机也是我们必不可少的装备&#xff0c;最近我发现一款很好用的分体式气传导蓝牙耳机&#xff0c;它还带有一个具备AI功能的APP端&#xff0c;大大方便了我们日常的使用。这款sanag塞那Z50耳夹耳机我用过一段时间以后&…

以太坊==使用IDE remix.ethereum搭配metamask发布合约到测试网

IDE地址 Remix - Ethereum IDE 编写代码 部署&#xff0c;选择metamask 查看 部署成功后&#xff0c;可以看到详情地址&#xff0c;查看详情&#xff0c;所以发布合约就是一个TX https://sepolia.etherscan.io/tx/0xe62a0b03ec9f55702cd06f36447fd3c50450a948d59d03c381d97…

postman测试接口使用

背景&#xff1a; 隔了一段时间没有用postman&#xff0c;有些忘记了&#xff0c;谨以此文来记录postman的使用&#xff0c;如有忘记就可以快速回忆 使用&#xff1a; 点击这个号&#xff0c;是创建接口页面 这里的复选框可供我们选择接口的rest方式 请求路径&#xff1a; …

Google trend搜索关键词

Google trend地址&#xff1a;https://trends.google.com/trends/?geoUS&hlzh-CN 1、具体的操作步骤如下&#xff1a; 2、Google trend搜索页面如下&#xff1a;

【金】?Y? python网页前端streamlit

1、如何从 Google Colab Notebook 启动 streamit参考-How to Launch Streamlit App from Google Colab Notebook !streamlit run web.py & npx localtunnel --port 8501 & curl ipv4.icanhazip.com

spire.Pdf 将pdf转成image

一、nuget安装 <ItemGroup><PackageReference Include"Spire.PDF" Version"10.6.7" /></ItemGroup> 二、直接上代码 using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System; using System.IO;namespace …

1962springboot VUE社区服务平台系统开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot VUE社区服务平台系统是一套完善的完整信息管理类型系统&#xff0c;结合springboot框架和VUE完成本系统&#xff0c;对理解vue java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和…

微型操作系统内核源码详解系列五(四):cm3下svc启动任务

系列一&#xff1a;微型操作系统内核源码详解系列一&#xff1a;rtos内核源码概论篇&#xff08;以freertos为例&#xff09;-CSDN博客 系列二&#xff1a;微型操作系统内核源码详解系列二&#xff1a;数据结构和对象篇&#xff08;以freertos为例&#xff09;-CSDN博客 系列…

ctfshow 2023 愚人杯 web

easy_signin 观察url&#xff0c;发现base64 &#xff0c;进行解码&#xff0c;原来可以访问文件路径&#xff0c;那我们访问一下index.php ?imgaW5kZXgucGhw查看源代码发现还是base64 解码得到flag 被遗忘的反序列化 <?php# 当前目录中有一个txt文件哦 error_reporti…

SpringBoot测试实践

测试按照粒度可分为3层&#xff1a; 单元测试&#xff1a;单元测试&#xff08;Unit Testing&#xff09;又称为模块测试 &#xff0c;是针对程序模块&#xff08;软件设计的最小单位&#xff09;来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中…

SQlyog连接到主机时报错:错误号码2058Plugin sha256 password could not be loaded

1.问题重述 MySQL版本&#xff1a;8.4.0 SQlyog连接到主机时报错&#xff1a;错误号码2058Plugin sha256 password could not be loaded&#xff0c;如下图 经过查阅资料得知出现这个问题是因为 mysl8之前的加密规则是 mysql_native_password &#xff0c;而在mysql8之后&…

Python神经影像数据的处理和分析库之nipy使用详解

概要 神经影像学(Neuroimaging)是神经科学中一个重要的分支,主要研究通过影像技术获取和分析大脑结构和功能的信息。nipy(Neuroimaging in Python)是一个强大的 Python 库,专门用于神经影像数据的处理和分析。nipy 提供了一系列工具和方法,帮助研究人员高效地处理神经影…