Springboot使用Aop保存接口请求日志到mysql

news2024/11/18 9:27:20

1、添加aop依赖

        <!-- aop日志 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2、新建接口保存数据库的实体类RequestLog.java

package com.example.springboot.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;

/**
 * <p>
 * 请求日志
 * </p>
 *
 * @author Sca_jie
 * @since 2023-09-28
 */
@Getter
@Setter
@TableName("request_log")
public class RequestLog implements Serializable {

    private static final long serialVersionUID = 1L;

    // 主键-自增
    @TableId(value = "number", type = IdType.AUTO)
    private Integer number;

    // 用户账号
    private String id;

    // 携带token
    private String token;

    // 接口路径
    private String url;
    
    // 请求类型
    private String method;

    // 携带参数
    private String params;

    // ip地址
    private String ip;

    // 结果
    private String result;

    // 接口发起时间
    private LocalDateTime startDate;

    // 接口结束时间
    private LocalDateTime endDate;

    // 响应耗时
    private String responseTime;
}

3、新建一个注解RequestLogAnnotation.java

package com.example.springboot.annotation;

import java.lang.annotation.*;

/**
 * 请求记录日志注解
 */
@Target({ElementType.TYPE, ElementType.METHOD}) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented
public @interface RequestLogAnnotation {
    String value() default "";
}

4、(核心)新建aop面切类RequestLogAspect.java拦截请求并保存日志

package com.example.springboot.common;

import cn.hutool.core.net.NetUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.example.springboot.annotation.RequestLogAnnotation;
import com.example.springboot.entity.RequestLog;
import com.example.springboot.mapper.RequestLogMapper;
import com.example.springboot.utils.CookieUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 日志记录
 *
 */
@Aspect
@Component
public class RequestLogAspect {

    @Autowired(required = false)
    RequestLogMapper requestLogMapper;

    @Pointcut("@annotation(com.example.springboot.annotation.RequestLogAnnotation)")
    public void logPointCut() {

    }

    // 请求的开始处理时间(不同类型)
    Long startTime = null;
    LocalDateTime startDate;

    @Before("logPointCut()")
    public void beforeRequest() {
        startTime = System.currentTimeMillis();
        startDate = LocalDateTime.now();
    }

    @AfterReturning(value = "logPointCut()", returning = "result")
    public void saveLog(JoinPoint joinPoint, Object result) {

        // 获取请求头
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        HttpServletResponse response = requestAttributes.getResponse();

        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        //获取切入点所在的方法
        Method method = signature.getMethod();

        // 初始化日志表的实体类
        RequestLog requestLog = new RequestLog();

        //获取操作
        RequestLogAnnotation requestLogAnnotation = method.getAnnotation(RequestLogAnnotation.class);

//        // 获取@SystemLogAnnotation(value = "用户登录")中的注解value
//        if (systemLogAnnotation != null) {
//            String value = systemLogAnnotation.value();
//            requestLog.setSName(value);
//        }

        // 获取cookies
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            // 获取token
            for(Cookie cookie : cookies){
                if(cookie.getName().equals("token")){
                    requestLog.setToken(cookie.getValue());
                }
            }

            // 获取id
            String id = CookieUtil.getid(cookies);
            if (id != "" | id != null) {
                requestLog.setId(id);
            }
        }

        // 区分get和post获取参数
        String params = "{}";
        if (request.getMethod().equals("GET")) {
            params = JSONObject.toJSONString(request.getParameterMap());
        } else if (request.getMethod().equals("POST")) {
            params = JSONUtil.toJsonStr(joinPoint.getArgs());
        }

        // 用户Ip
        requestLog.setIp(NetUtil.getLocalhostStr());
        // 接口请求类型
        requestLog.setMethod(request.getMethod());
        // 请求参数(区分get和post)
        requestLog.setParams(params);
        // 请求接口路径
        requestLog.setUrl(request.getRequestURI().toString());
        // 返回结果
        requestLog.setResult(JSONObject.toJSONString(result));
        // 请求开始时间
        requestLog.setStartDate(startDate);
        // 请求结束时间
        requestLog.setEndDate(LocalDateTime.now());
        // 请求共计时间(ms)
        requestLog.setResponseTime(String.valueOf(System.currentTimeMillis() - startTime));

        // 保存日志到mysql
        requestLogMapper.insert(requestLog);
    }
}

5、在对应接口添加注解@RequestLogAnnotation

    @RequestLogAnnotation(value = "获取上传记录")
    @GetMapping("/getlist")
    public Result getlist (@RequestParam(required = false) String id) {
        if (id == null) {
            return Result.success(404, "参数缺失");
        } else {
            List<UploadLog> page = uploadLogService.getlist(id);
            return Result.success(200, page.toString());
        }

    }

效果如下

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

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

相关文章

volatile关键字使用总结

先说结论 1. volatile关键字可以让编译器层面减少优化&#xff0c;每次使用时必须从内存中取数据&#xff0c;而不是从cpu缓存或寄存器中获取 2. volatile关键字不能完全禁止指令重排&#xff0c;准确地说是两个volatile修饰的变量之间的命令不会进行指令重排 3. 使用volati…

BLE协议栈1-物理层PHY

从应届生开始做ble开发也差不读四个月的时间了&#xff0c;一直在在做上层的应用&#xff0c;对蓝牙协议栈没有过多的时间去了解&#xff0c;对整体的大方向概念一直是模糊的状态&#xff0c;在开发时也因此遇到了许多问题&#xff0c;趁有空去收集了一下资料来完成了本次专栏&…

毕业设计选题之Android基于移动端的线上订餐app外卖点餐安卓系统源码 调试 开题 lw

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

【gcc】RtpTransportControllerSend学习笔记

本文是对大神 webrtc源码分析(8)-拥塞控制(上)-码率预估 的学习笔记。看了啥也没记住,所以跟着看代码先。CongestionControlHandler 在底层网络可用的时候,会触发RtpTransportControllerSend::OnNetworkAvailability()回调,这里会尝试创建CongestionControlHandler创建后即刻…

在VS Code中优雅地编辑csv文件

文章目录 Rainbow csv转表格CSV to Tablecsv2tableCSV to Markdown Table Edit csv 下面这些插件对csv/tsv/psv都有着不错的支持&#xff0c;这几种格式的主要区别是分隔符不同。 功能入口/使用方法Rainbow csv按列赋色右键菜单CSV to Table转为ASCII表格指令CSV to Markdown …

混合网状防火墙的兴起如何彻底改变网络安全

数字环境在不断发展&#xff0c;随之而来的是日益复杂的网络威胁。 从复杂、持续的攻击到对非传统设备的秘密尝试&#xff0c;网络犯罪分子不断完善他们的策略。 除了这些日益严峻的挑战之外&#xff0c;各组织还在努力应对物联网 (IoT)&#xff0c;尽管大量联网设备收集和传…

Leetcode 1492.n的第k个因子

给你两个正整数 n 和 k 。 如果正整数 i 满足 n % i 0 &#xff0c;那么我们就说正整数 i 是整数 n 的因子。 考虑整数 n 的所有因子&#xff0c;将它们 升序排列 。请你返回第 k 个因子。如果 n 的因子数少于 k &#xff0c;请你返回 -1 。 示例 1&#xff1a; 输入&#…

使用华为eNSP组网试验⑸-访问控制

今天练习使用华为sNSP模拟网络设备上的访问控制&#xff0c;这样的操作我经常在华为的S7706、S5720、S5735或者H3C的S5500、S5130、S7706上进行&#xff0c;在网络设备上根据情况应用访问控制的策略是一个网管必须熟练的操作&#xff0c;只是在真机上操作一般比较谨慎&#xff…

FFmpeg 基础模块:AVIO、AVDictionary 与 AVOption

目录 AVIO AVDictionary 与 AVOption 小结 思考 我们了解了 AVFormat 中的 API 接口的功能&#xff0c;从实际操作经验看&#xff0c;这些接口是可以满足大多数音视频的 mux 与 demux&#xff0c;或者说 remux 场景的。但是除此之外&#xff0c;在日常使用 API 开发应用的时…

cpp primer笔记090-动态内存

shared_ptr和unique_ptr都支持的操作&#xff0c;加上shared_ptr独有的操作 每个shared_ptr都有一个关联的计数器&#xff0c;通常称其为引用计数&#xff0c;当调用了shared_ptr的构造函数时就会递增&#xff0c;当调用析构函数时就会递减&#xff0c;一旦一个shared_ptr的计…

【2023年11月第四版教材】第19章《配置与变更管理》(合集篇)

第19章《配置与变更管理》&#xff08;合集篇&#xff09; 1 章节内容2 配置管理3 变更管理4 项目文档管理 1 章节内容 【本章分值预测】本章内容90%和第三版教材内容一样的&#xff0c;少部分有一些变化&#xff0c;特别是变更涉及的人员及职责&#xff0c;预计选择题考3分&a…

Python如何实现数据驱动的接口自动化测试

大家在接口测试的过程中&#xff0c;很多时候会用到对CSV的读取操作&#xff0c;本文主要说明Python3对CSV的写入和读取。下面话不多说了&#xff0c;来一起看看详细的介绍吧。 1、需求 某API&#xff0c;GET方法&#xff0c;token,mobile,email三个参数 token为必填项mobil…

Connect to 127.0.0.1:1080 [/127.0.0.1] failed: Connection refused: connect

报错信息 A problem occurred configuring root project CourseSelection. > Could not resolve all artifacts for configuration :classpath.> Could not resolve com.android.tools.build:gradle:3.6.1.Required by:project :> Could not resolve com.android.tool…

力扣第101题 c++ 递归 迭代 双方法 +注释 ~

题目 101. 对称二叉树 简单 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false提示&a…

点读笔背后的神秘力量,究竟是如何实现即时识别的?

点读笔是一种智能学习工具&#xff0c;通过与印刷物或电子设备配合使用&#xff0c;将文字、图片或声音转化为可听、可读、可学习的内容。它的核心功能是识别并解析特定标识&#xff08;如二维码、条形码&#xff09;或区域内的信息&#xff0c;并提供相应的语音、文字或图像反…

docker swarm安装指导

SWARM部署DOCKER集群 1. 简介............................................................................................................................ 3 2. 部署准备.........................................................................................…

15040-2021 工作测光标准灯泡 学习记录

声明 本文是学习GB-T 15040-2021 工作测光标准灯泡.pdf而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件规定了工作测光标准灯(下文在不会引起误解时简称为"标准灯”或“灯")的分类、 一般要求、 技术要求和试验方法&#xff…

详解链表oJ<反转链表,链表的中间节点及链表的回文>

hello&#xff0c;大家好&#xff0c;这里是Dark FlameMaster,今天和大家分享的是有关数据结构链表的几道题目&#xff0c;链表的中间节点&#xff0c;反转链表及判断链表是否为回文结构&#xff0c;放在一起讲解会印象更加深刻。 文章目录 一&#xff0c;链表的中间节点二&…

C#,数值计算——数据建模FGauss的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { public class FGauss : MultiFuncd { public void funk(double x, double[] a, ref double y, double[] dyda) { int na a.Length; y 0.0; for (int …

吃鸡达人专享!提高战斗力,分享干货,查询装备皮肤,保护账号安全!

大家好&#xff01;作为专业吃鸡行家&#xff0c;我将为您带来一些热门话题和实用内容&#xff0c;帮助您提升游戏战斗力&#xff0c;分享顶级游戏作战干货&#xff0c;并提供便捷的作图工具和查询服务。让我们一起享受吃鸡的乐趣&#xff01; 首先&#xff0c;我要推荐一款绝地…