SpringBoot3与AOP完美结合:轻松追踪用户操作,实现精准日志记录

程序员必备宝典icon-default.png?t=N7T8https://tmxkj.top/#/

1.pom文件

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.78</version></dependency>

2.Annotation 注解

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

3.Entity实体类和Dao


import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;import java.io.Serial;
import java.io.Serializable;
import java.util.Date;@Data
@TableName(value = "sys_log",autoResultMap = true)
public class Log implements Serializable {@Serialprivate static final long serialVersionUID = 1L;@TableId(type = IdType.AUTO)/*** id*/private Integer id;/*** 用户ip*/private String requestIp;/*** 用户id*/private String userId;/*** 用户名称*/private String userName;/*** 请求地址*/private String requestUrl;/*** 请求接口名称*/private String requestName;/*** 请求格式*/private String requestMethod;/*** 请求头信息*/private String requestHeader;/*** 请求查询参数*/private String requestQuery;/*** 请求体参数*/private String requestParam;/*** 请求耗时(秒)*/private Integer requestCost;/*** 请求状态*/private String requestCode = "200";/*** 请求位置*/private String requestPosition;/*** 响应状态*/private String responseCode ="200";/*** 响应结果*/private String responseResult;/*** 报错信息*/private String reportErrors;/*** 创建时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private Date createTime;/*** 结束时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private Date endTime;}
CREATE TABLE `tmxtestsql`.`Untitled`  (`id` int NOT NULL AUTO_INCREMENT,`request_ip` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户ip',`user_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户id',`user_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户名称',`request_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '请求地址',`request_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '请求接口名称',`request_method` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '请求格式',`request_header` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '请求头信息',`request_query` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '请求查询参数',`request_param` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '请求体参数',`request_cost` int NULL DEFAULT NULL COMMENT '请求耗时(秒)',`request_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '请求状态',`request_position` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '请求位置',`response_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '响应状态',`response_result` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '响应结果',`report_errors` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '报错信息',`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',`end_time` datetime NULL DEFAULT NULL COMMENT '结束时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

 Dao数据层

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.portalwebsiteservice.demos.web.Entity.Log;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface LogDao extends BaseMapper<Log> {
}

 4.Util工具类(获取ip地址)

/*** 获取IP真实地址* 备注:在本地运行是获取不到真实地址,需要部署到服务上才能获取得到*/
public class IpUtils {public static String getIpAddr(HttpServletRequest request) {String ipAddress = null;try {ipAddress = request.getHeader("x-forwarded-for");if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("WL-Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddr();if (ipAddress.equals("127.0.0.1")) {// 根据网卡取本机配置的IPInetAddress inet = null;try {inet = InetAddress.getLocalHost();} catch (UnknownHostException e) {e.printStackTrace();}ipAddress = inet.getHostAddress();}}// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()// = 15if (ipAddress.indexOf(",") > 0) {ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));}}} catch (Exception e) {ipAddress="";}return ipAddress;}}

5.Aspect切面类(业务流程)


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.portalwebsiteservice.demos.web.Annotation.RequestLog;
import com.portalwebsiteservice.demos.web.Dao.LogDao;
//import com.portalwebsiteservice.demos.web.Dto.JwtInfo;
import com.portalwebsiteservice.demos.web.Dto.Result;
import com.portalwebsiteservice.demos.web.Entity.Log;
//import com.portalwebsiteservice.demos.web.Service.JwtRedistService;
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.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;import static com.alibaba.fastjson.JSON.toJSONString;
import static com.portalwebsiteservice.demos.web.Util.IpUtils.getIpAddr;@Aspect
@Component
public class LoggingAspect {@Resourceprivate LogDao logDao;// @Resource// private JwtRedistService jwtRedistService;/*** execution是给指定区域,切入点(目前已去掉)* annotation是让特定类使用注解,切入点*/@Pointcut("@annotation(com.portalwebsiteservice.demos.web.Annotation.RequestLog)")public void logPointCut() {}Date startDate;@Before("logPointCut()")public void beforeRequest() {startDate = new Date();}/*** 日志存入*/@AfterReturning(value = "logPointCut()", returning = "result")public void saveLog(JoinPoint joinPoint, Result result) {try {// 获取请求头ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = null;//创建实体类实例Log log = new Log();if (requestAttributes != null) {//获取到响应数据HttpServletResponse response = requestAttributes.getResponse();//获取请求头信息request = requestAttributes.getRequest();//从切面织入点处通过反射机制获取织入点处的方法MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获取切入点所在的方法Method method = signature.getMethod();//------------------------以下方法是设置实体类参数----------------------------//// 获取@SystemLog(value = "用户登录")中的注解valueRequestLog requestLogName = method.getAnnotation(RequestLog.class);if (requestLogName != null) {String value = requestLogName.value();log.setRequestName(value);}//获取用户IpString clientIp = getIpAddr(request);log.setRequestIp(clientIp);//设置请求路径log.setRequestUrl(request.getRequestURI());//请求格式log.setRequestMethod(request.getMethod());//设置请求状态if (response != null) {log.setRequestCode(String.valueOf(response.getStatus()));}//设置请求头信息Map<String, String> map = new HashMap<>();Enumeration<String> headerNames = request.getHeaderNames();while (headerNames.hasMoreElements()) {String key = headerNames.nextElement();String value = request.getHeader(key);map.put(key, value);}log.setRequestHeader(toJSONString(map));//获取请求tokenString Authorization = request.getHeader("Authorization");//获取用户信息(这步骤是我的业务逻辑,你根据自己情况获取用户信息)if (Authorization != null) {// JwtInfo jwtInfo =jwtRedistService.getUserInfo(Authorization);//  if (jwtInfo.getPass()){//    log.setUserId(jwtInfo.getUserId());//   log.setUserName(jwtInfo.getUser().getUserName());// }}//设置查询参数log.setRequestQuery(request.getQueryString());//设置请求参数if (request.getMethod().equals("POST")) {Object[] list = joinPoint.getArgs();if (list != null && list.length > 0) {String params = toJSONString(list[0]);log.setRequestParam(params);}}//设置响应结果log.setResponseResult(String.valueOf(result));//设置响应状态log.setResponseCode(String.valueOf(result.getCode()));//设置创建时间log.setCreateTime(startDate);Date nowTime = new Date();//设置结束时间log.setEndTime(nowTime);//设置请求时长long durationInMillis = nowTime.getTime() - startDate.getTime();long durationInSeconds = (TimeUnit.MILLISECONDS.toSeconds(durationInMillis))+1L;log.setRequestCost((int) durationInSeconds);//插入数据logDao.insert(log);}}catch (Exception e) {e.fillInStackTrace();}}/*** 定时任务清除数据*/@Scheduled(cron = "0 0 2 * * ?")public void executeTask() {// 获取当前时间并减去3个月LocalDateTime threeMonthsAgo = LocalDateTime.now().minus(3, ChronoUnit.MONTHS);LambdaQueryWrapper<Log> lqw = new LambdaQueryWrapper<>();lqw.lt(Log::getCreateTime, threeMonthsAgo);List<Log> logList = logDao.selectList(lqw);if (logList != null && logList.size() > 0) {logDao.deleteBatchIds(logList);}}

备注:如果你使用了定时任务,记得在启动类添加@EnableScheduling注解

 6.使用(调用接口即可)

 运行结果:

{"RECORDS": [{"id": 22,"request_ip": "183.136.77777.78","user_id": null,"user_name": null,"request_url": "/api-net/phone-info","request_name": "获取手机号信息接口","request_method": "GET","request_header": "{\"remote-host\":\"\",\"referer\":\"http://api.aa1.cn\",\"cdn-loop\":\"cloudflare\",\"cf-ipcountry\":\"CN\",\"cf-ray\":\"8bac2457bd9093fa-LHR\",\"x-forwarded-proto\":\"https\",\"accept-language\":\"en-US,en;q=0.9\",\"x-forwarded-for\":\"183.136.132.78, 172.70.160.221\",\"x-host\":\"yubin-fuwu.top:80\",\"accept\":\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\",\"x-real-ip\":\"172.70.160.221\",\"cf-visitor\":\"{\\\"scheme\\\":\\\"https\\\"}\",\"host\":\"yubin-fuwu.top:80\",\"connection\":\"upgrade\",\"cf-connecting-ip\":\"183.136.132.78\",\"x-scheme\":\"http\",\"cache-control\":\"max-age=0\",\"accept-encoding\":\"gzip, br\",\"user-agent\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\"}","request_query": "mobile=578887","request_param": null,"request_cost": 3,"request_code": "200","request_position": null,"response_code": "200","response_result": "Result(code=200, msg=获取手机号信息成功, data=PhoneInfo(phoneNumber=77777, province=云南, city=文山, zipCode=663000, areaCode=0876, phoneType=电信))","report_errors": null,"create_time": "29/8/2024 19:18:44","end_time": "29/8/2024 19:18:46"}]
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring八股文

重点 描述一下bean的生命周期 简述版 调用构造器 或者是通过工厂的方式创建Bean对象给bean对象的属性注入值调用初始化方法&#xff0c;进行初始化&#xff0c; 初始化方法是通过init-method来指定的.使用IOC容器关闭时&#xff0c; 销毁Bean对象 详细&#xff1a; 1. 实例化 …

Qt QCustomPlot画色阶图

工作中用到QCustomPlot画曲线图和色阶图&#xff0c;并且在色阶图上添加文字&#xff0c;圆圈或者几条线段画一些图形&#xff0c;这里写个简单的例子把这几个功能记录一下&#xff0c;代码在这里&#xff1a; https://download.csdn.net/download/Sakuya__/89681279https://…

ggml 简介

ggml是一个用 C 和 C 编写、专注于 Transformer 架构模型推理的机器学习库。该项目完全开源&#xff0c;处于活跃的开发阶段&#xff0c;开发社区也在不断壮大。ggml 和 PyTorch、TensorFlow 等机器学习库比较相似&#xff0c;但由于目前处于开发的早期阶段&#xff0c;一些底层…

『功能项目』怪物受击后显示受击状态UI【12】

本专栏每10章会做一次项目优化&#xff0c;但不影响具体功能 我们可以打开优化前的项目10也可以打开优化后的项目11 双击King或者怪物熊预制体 - 进入预制体空间后创建一个Image改名为StateUI01 代表第一个受击状态 修改Canvas的渲染模式 - 改为世界WorldSpace 调节Image&…

3分钟千人被裁,IBM中国 “灭霸式“裁员背后原因?

2024年8月23日&#xff0c;IMB即有员工传出“无法访问系统”&#xff0c;“无法连接到公司网络”的消息&#xff0c;后续传出裁员的传闻。 图片来源网络 2024年8月26日周一&#xff0c;IBM召开3分钟的会议&#xff0c;宣布彻底关闭IBM中国研发部门&#xff0c;之后直接切断会议…

【Go高性能】测试(单元测试、基准测试)

Go测试 一、分类1. 单元测试2. 基准测试 二、基准测试1. 介绍2. 基准测试基本原则3. 使用testing包构建基准测试3.1 执行基准测试3.2 基准测试工作原理3.3 改进基准测试的准确性3.3.1 -benchtime3.3.2 -count3.3.3 -cpu 4. 使用benchstat工具比较基准测试(可跳过&#xff09;4.…

SpringBoot日常:Spring之@PostConstruct解析

简介 spring的Bean在创建的时候会进行初始化&#xff0c;而初始化过程会解析出PostConstruct注解的方法&#xff0c;并反射调用该方法。 PostConstruct 的使用和特点 只有一个非静态方法能使用此注解&#xff1b;被注解的方法不得有任何参数&#xff1b;被注解的方法返回值必…

数据主权与隐私保护的深入探讨

随着数字化进程的加速&#xff0c;数据已成为当今世界的重要资源。数据主权和隐私保护这两个概念也越来越受到关注。数据主权涉及到国家对数据的控制权和管理权&#xff0c;而隐私保护则关乎个人数据的安全性和隐私权利。两者相互交织&#xff0c;共同塑造了数字时代的法律、经…

[RIS]GRES: Generalized Referring Expression Segmentation

1. BaseInfo TitleGRES: Generalized Referring Expression SegmentationAdresshttps://arxiv.org/pdf/2306.00968Journal/TimeCVPR2023Author南洋理工Codehttps://github.com/henghuiding/ReLARead20240829TableVisonLanguage 2. Creative Q&A 考虑结果多目标和无目标&…

2024软考:一场与“难”共舞的奇妙冒险,你值得拥有!

在这个时代&#xff0c;如果说有什么考试能让IT界的勇士们闻风丧胆&#xff0c;又爱又恨&#xff0c;那软考绝对能C位出道&#xff0c;成为众多技术大佬心中的“白月光”与“朱砂痣”。随着岁月悠悠&#xff0c;2024年的软考似乎又悄悄地在难度上动了点小心思&#xff0c;让人不…

【C++ Primer Plus习题】6.5

问题: 解答: #include <iostream> using namespace std;int main() {float salary 0;float tax 0;while (salary>0){cout << "请输入您的工资:";cin >> salary;if (cin.fail())break;if (salary < 5000){tax 0;}else if (salary < 15…

风控领域特征工程

在金融行业&#xff0c;风险控制&#xff08;风控&#xff09;是核心环节&#xff0c;它关乎资产安全、合规性以及机构的长期稳健发展。随着大数据时代的到来&#xff0c;金融机构面临着前所未有的数据量和复杂性。在这样的背景下&#xff0c;风控领域特征工程应运而生&#xf…

20240829版图的层次

1 最常用 Esc&#xff1a;取消操作 i&#xff1a;插入元件版图 c&#xff1a;复制 m&#xff1a;移动 u&#xff1a;撤销上一步操作 q&#xff1a;查看属性 f&#xff1a;全局视图 e&#xff1a;显示设置&#xff08;图层、栅格、走线模式等&#xff09; r&#xff1a;矩形填充…

<Rust>egui学习之小部件(六):如何在窗口中添加菜单栏部件?

前言 本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析&#xff0c;主要讲解egui的源代码、部件属性、如何应用。 环境配置 系统&#xff1a;windows 平台&#xff1a;visual studio code 语言&#xff1a;rust 库&#xff1a;egui、eframe 概述 本文是本专栏的第六篇博…

【爬虫软件】采集抖音博主的主页发布作品

这是我用python开发的抖音爬虫采集软件&#xff0c;可自动按博主抓取已发布视频。 软件界面截图&#xff1a; 爬取结果截图&#xff1a; 几点重要说明&#xff1a; 软件使用演示视频&#xff1a; https://www.bilibili.com/video/BV1Kb42187qf 完整讲解文章&#xff1a; ht…

释放金融交易的未来:掌握量化机器人技术

在金融交易的竞技场上&#xff0c;量化机器人技术正成为投资者手中的一张王牌&#xff0c;引领着交易策略的未来。本文将向您展示量化机器人如何成为金融交易的变革者&#xff0c;并向您展示如何利用这一技术来优化您的投资策略。 量化机器人的力量 量化机器人技术是金融交易领…

Anaconda3简介与安装步骤

目录 Anaconda3简介与功能 1.Anaconda3简介 2.主要功能和特点 3.使用场景 4.总结 Anaconda3安装 1.Anaconda3下载 1.1我的百度网盘 1.2官网下载 1.2.1访问官网 1.2.2输入邮箱 1.2.3登录你的邮箱下载&#xff08;你的噶&#xff09; 2.安装 2.1双击安装 2.2选择安…

Linux——nginx 负载均衡

常规的web服务器一般提供对于静态资源的访问&#xff0c;比如说&#xff1a;图片、web样式 网站提供的大部分交互功能都需要web编程语言的支持&#xff0c;而web服务对于程序的调用&#xff0c;不管编译型语言还是解释型语言&#xff0c;web服务同将对于应用程序的调用递交给通…

路别走窄了,华为认证的这些方向,比数通值钱

华为认证作为全球领先的ICT技术认证之一&#xff0c;以其高标准和权威性在全球范围内受到认可。它不仅代表了专业技能的国际水平&#xff0c;更是IT专业人士职业生涯中的重要里程碑。但谈论起华为认证&#xff0c;似乎大家都默认首选数通。 不止在华为认证&#xff0c;而是在整…

Vue使用v-model收集各种表单数据、过滤器

目录 1. 使用v-model收集各种表单数据2. 日期格式化3. 过滤器 1. 使用v-model收集各种表单数据 若<input type“text”/>&#xff0c;则v-model收集的是value值&#xff0c;用户输入的就是value值若<input type“radio”/>&#xff0c;则v-model收集的是value值&a…