Spring Boot - 自定义注解来记录访问路径以及访问信息,并将记录存储到MySQL

news2024/11/15 21:55:29

1、准备阶段

application.properties;yml 可通过yaml<互转>properties

spring.datasource.url=jdbc:mysql://localhost:3306/study_annotate
spring.datasource.username=root
spring.datasource.password=123321
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

依赖(以 jpa 为例,简化代码方便举例):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>

2、自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD) // 因为路径在方法上所以作用目标为 METHOD
@Retention(RetentionPolicy.RUNTIME) // 运行时:通过反射在运行时读取注解信息
public @interface AccessLog {
    String value() default "";
}

3、先来定义一个实体类

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDateTime;

@Entity
@Data
public class AccessLogEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String logMessage;
    private String ipAddress;
    private LocalDateTime timestamp;


    public AccessLogEntity() {
        this.timestamp = LocalDateTime.now();
    }

    public AccessLogEntity(String logMessage, String ipAddress) {
        this();
        this.logMessage = logMessage;
        this.ipAddress = ipAddress;
    }

}

4、接着dao

import com.lfsun.demolfsunstudyannotate.entity.AccessLogEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AccessLogRepository extends JpaRepository<AccessLogEntity, Long> {
    // 这里可以定义一些自定义的查询方法,根据需要进行扩展
}


5、然后service

import com.lfsun.demolfsunstudyannotate.dao.AccessLogRepository;
import com.lfsun.demolfsunstudyannotate.entity.AccessLogEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AccessLogService {

    @Autowired
    private AccessLogRepository accessLogRepository;

    public void saveLog(String logMessage, String ipAddress) {
        // 在这里实现将日志信息保存到MySQL数据库的逻辑
        AccessLogEntity logEntity = new AccessLogEntity(logMessage, ipAddress);
        accessLogRepository.save(logEntity);
    }
}

6、该切面了

import com.lfsun.demolfsunstudyannotate.annotate.AccessLog;
import com.lfsun.demolfsunstudyannotate.service.AccessLogService;
import com.lfsun.demolfsunstudyannotate.util.IpUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
public class AccessLogAspect {

    @Autowired
    private AccessLogService accessLogService;

    @Before("@annotation(accessLog)")
    public void logAccess(JoinPoint joinPoint, AccessLog accessLog) {
        String methodName = joinPoint.getSignature().toShortString();
        String logMessage = accessLog.value().isEmpty() ? methodName : accessLog.value();
        String ipAddress = IpUtil.getClientIpAddress();

        // 在这里将日志信息记录到MySQL数据库
        accessLogService.saveLog(logMessage, ipAddress);
    }

}

7、controller

import com.lfsun.demolfsunstudyannotate.annotate.AccessLog;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
public class HelloController {

    @AccessLog("/hello")
    @GetMapping("/hello")
    public String hello() {
        return "hello lfsun!";
    }
}

如果观察仔细的话可以看到:点下就回到刚刚定义的切面了!
在这里插入图片描述

8、补个IpUtil ,获取ip的工具类

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

@Slf4j
public class IpUtil {

    private static final String X_FORWARDED_FOR_HEADER = "X-Forwarded-For";
    private static final String PROXY_CLIENT_IP_HEADER = "Proxy-Client-IP";
    private static final String WL_PROXY_CLIENT_IP_HEADER = "WL-Proxy-Client-IP";

    /**
     * 获取客户端真实IP地址,考虑了代理服务器的情况。
     *
     * @param request HttpServletRequest对象
     * @return 客户端真实IP地址
     */
    public static String getClientIpAddress(HttpServletRequest request) {
        String xForwardedForHeader = request.getHeader(X_FORWARDED_FOR_HEADER);
        if (xForwardedForHeader != null && !xForwardedForHeader.isEmpty()) {
            // 如果有多个IP地址,取第一个
            return xForwardedForHeader.split(",")[0].trim();
        } else if (request.getHeader(PROXY_CLIENT_IP_HEADER) != null) {
            return request.getHeader(PROXY_CLIENT_IP_HEADER);
        } else if (request.getHeader(WL_PROXY_CLIENT_IP_HEADER) != null) {
            return request.getHeader(WL_PROXY_CLIENT_IP_HEADER);
        } else {
            // 如果以上都不存在,直接获取RemoteAddr
            String remoteAddr = request.getRemoteAddr();
            log.warn("使用 remoteAddr 无法确定客户端 IP 地址: {}", remoteAddr);
            return remoteAddr;
        }
    }

    /**
     * 获取客户端真实IP地址,使用Spring的RequestContextHolder。
     *
     * @return 客户端真实IP地址
     */
    public static String getClientIpAddress() {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
            return getClientIpAddress(request);
        } catch (NullPointerException e) {
            log.error("无法从 RequestContextHolder 获取 HttpServletRequest.", e);
            return "unknown";
        }
    }

}

项目启动并测试

1、从本地浏览器访问查看日志

在这里插入图片描述

2、从内网穿透的url访问查看日志

在这里插入图片描述

3、从内网穿透的url然后再开着梯子访问查看日志

在这里插入图片描述

吐槽一下 这是断网了吗 ~ ^ ~

在这里插入图片描述

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

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

相关文章

python趣味编程-5分钟实现一个贪吃蛇游戏(含源码、步骤讲解)

Python 贪吃蛇游戏代码是用 Python 语言编写的。在这个贪吃蛇游戏中,Python 代码是增强您在创建和设计如何使用 Python 创建贪吃蛇游戏方面的技能和才能的方法。 Python Tkinter中的贪吃蛇游戏是一个简单干净的 GUI,可轻松玩游戏。游戏设计非常简单,用户不会觉得使用和理解…

听GPT 讲Rust源代码--src/bootstrap

图片来自 使用rust的image库进行图片压缩[1] File: rust/src/bootstrap/build.rs 在Rust源代码中&#xff0c;rust/src/bootstrap/build.rs这个文件是一个构建脚本。构建脚本是一个在编译Rust编译器本身时运行的程序&#xff0c;它用于初始化和配置Rust编译器的构建过程。build…

编写函数实现简单的插值进入有序数组问题

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 老骥伏枥&#xff0c;志在千里&…

【Spring】SpringBoot的扩展点之ApplicationContextInitializer

简介 其实spring启动步骤中最早可以进行扩展的是实现ApplicationContextInitializer接口。来看看这个接口的注释。 package org.springframework.context;/*** Callback interface for initializing a Spring {link ConfigurableApplicationContext}* prior to being {linkpl…

Ubuntu——卸载、安装CUDA

【注】WSL的Ubuntu是不用安装CUDA的&#xff0c;因为它使用的是Windows的显卡驱动&#xff0c;所以如果WSL的CUDA出了问题&#xff0c;重新安装WSL即可&#xff01; 1、卸载 安装完CUDA后&#xff0c;会提示如果要卸载CUDA可以使用下列方法。 首先终端进入cuda-uninstaller所…

crmchat安装搭建教程文档 bug问题调试

一、安装PHP插件&#xff1a;fileinfo、redis、swoole4。 二、删除PHP对应版本中的 proc_open禁用函数。 一、设置网站运行目录public&#xff0c; 二、设置PHP版本选择纯静态。 三、可选项如有需求则开启SSL,配置SSL证书&#xff0c;开启强制https域名。 四、添加反向代理。 …

时间序列与 Statsmodels:预测所需的基本概念(1)

后文&#xff1a;时间序列与 statsmodels&#xff1a;预测所需的基本概念&#xff08;2&#xff09;-CSDN博客 一、说明 本博客解释了理解时间序列的基本概念&#xff1a;趋势、季节性、白噪声、平稳性&#xff0c;并使用自回归、差分和移动平均参数进行预测示例。这是理解任何…

计算机网络(持续更新…)

文章目录 一、概述1. 计网概述⭐ 发展史⭐ 基本概念⭐ 分类⭐ 数据交换方式&#x1f970; 小练 2. 分层体系结构⭐ OSI 参考模型⭐TCP/IP 参考模型&#x1f970; 小练 二、物理层1. 物理层概述⭐ 四个特性 2. 通信基础⭐ 重点概念⭐ 极限数据传输率⭐ 信道复用技术&#x1f389…

nodejs微信小程序 +python+PHP+图书销售管理系统的设计与实现-网上书店-图书商城-计算机毕业设计

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

Redis-高性能原理剖析

redis安装 下载地址&#xff1a;http://redis.io/download 安装步骤&#xff1a; # 安装gcc yum install gcc# 把下载好的redis-5.0.3.tar.gz放在/usr/local文件夹下&#xff0c;并解压 wget http://download.redis.io/releases/redis-5.0.3.tar.gz tar -zxvf redis-5.0.3.tar…

Java八股文(急速版)

Redis八股文 我看你在做项目的时候都使用到redis&#xff0c;你在最近的项目中哪些场景下使用redis呢? 缓存和分布式锁都有使用到。 问&#xff1a;说说在缓存方面使用 1.在我最写的物流项目中就使用redis作为缓存&#xff0c;当然在业务中还是比较复杂的。 2.在物流信息…

归并排序知识总结

归并排序思维导图&#xff1a; 知识点&#xff1a;如果原序列中两个数的值是相同的&#xff0c;它们在排完序后&#xff0c;它们的位置不发生变化&#xff0c;那么这个排序是稳定的。快速排序是不稳定的&#xff0c;归并排序是稳定的。 快排变成稳定的>使快排排序数组中的每…

Java格式化类Format

文章目录 Format介绍Format方法- format&#xff08;格式化&#xff09;- parseObject&#xff08;解析&#xff09; 格式化分类日期时间格式化1. DateFormat常用方法getInstancegetDateInstancegetTimeInstancegetDateTimeInstance 方法入参styleLocale 2. SimpleDateFormat常…

Redis入门与应用

目录 Redis的技术全景 两大维度 三大主线 Redis的版本选择与安装 Redis的linux安装 Redis的启动 默认配置 带参数启动 配置文件启动 操作 停止 Redis全局命令 键名的生产实践 Redis常用数据结构 字符串&#xff08;String&#xff09; 操作命令 set 设置值 g…

科技云报道:全球勒索攻击创历史新高,如何建立网络安全的防线?

科技云报道原创。 最简单的方式&#xff0c;往往是最有效的&#xff0c;勒索软件攻击就属于这类。 近两年&#xff0c;随着人类社会加速向数字世界进化&#xff0c;勒索软件攻击成为网络安全最为严重的威胁之一。今年以来&#xff0c;勒索软件攻击在全球范围内呈现快速上升态…

Day36力扣打卡

打卡记录 T 秒后青蛙的位置&#xff08;DFS&#xff09; 链接 class Solution:def frogPosition(self, n: int, edges: List[List[int]], t: int, target: int) -> float:g [[] for _ in range(n 1)]for x, y in edges:g[x].append(y)g[y].append(x)g[1].append(0)ans …

11.16~11.19绘制图表,导入EXCEL中数据,进行拟合

这个错误通常是由于传递给curve_fit函数的数据类型不正确引起的。根据你提供的代码和错误信息&#xff0c;有几个可能的原因&#xff1a; 数据类型错误&#xff1a;请确保ce_data、lg_data和product_data是NumPy数组或类似的可迭代对象&#xff0c;且其元素的数据类型为浮点数。…

系列二、Lock接口

一、多线程编程模板 线程 操作 资源类 高内聚 低耦合 二、实现步骤 1、创建资源类 2、资源类里创建同步方法、同步代码块 三、12306卖票程序 3.1、synchronized实现 3.1.1、Ticket /*** Author : 一叶浮萍归大海* Date: 2023/11/20 8:54* …

城市智慧路灯智能照明管理系统简介

城市路灯存在着开关灯控制方式单、亮灯时间不准确、巡查困难、故障处理不及时、亮灯率无法把控等问题&#xff0c;从而导致路灯系统能耗高&#xff0c;维护成本高。传统的路灯控制系统已无法满足智慧城市管理的需要&#xff0c;智能路灯照明控制系统从而得到广泛应用。 叁仟智…

基于安卓android微信小程序的好物分享系统

运行环境 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&a…