Spring Boot + MyBatis-Plus實現操作日志記錄

創建數據庫表

CREATE TABLE `sys_operation_log` (`log_id` bigint NOT NULL AUTO_INCREMENT COMMENT '日志ID',`operation_type` varchar(20) NOT NULL COMMENT '操作類型',`operation_module` varchar(50) NOT NULL COMMENT '操作模塊',`operation_desc` varchar(200) DEFAULT NULL COMMENT '操作描述',`request_method` varchar(10) DEFAULT NULL COMMENT '請求方法',`request_url` varchar(500) DEFAULT NULL COMMENT '請求URL',`request_params` text DEFAULT NULL COMMENT '請求參數',`response_result` text DEFAULT NULL COMMENT '響應結果',`user_id` varchar(36) DEFAULT NULL COMMENT '操作用戶ID',`user_name` varchar(50) DEFAULT NULL COMMENT '操作用戶名',`user_ip` varchar(50) DEFAULT NULL COMMENT '用戶IP',`user_agent` varchar(500) DEFAULT NULL COMMENT '用戶代理',`operation_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作時間',`execution_time` bigint DEFAULT NULL COMMENT '執行耗時(ms)',`status` tinyint DEFAULT 1 COMMENT '操作狀態(0失敗 1成功)',`error_msg` text DEFAULT NULL COMMENT '錯誤信息',PRIMARY KEY (`log_id`),KEY `idx_user_id` (`user_id`),KEY `idx_operation_time` (`operation_time`),KEY `idx_module_type` (`operation_module`, `operation_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系統操作日志表';

添加pom.xml依賴

<dependencies><!-- Spring Boot Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MyBatis-Plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>最新版本</version></dependency><!-- AOP --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- Lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
</dependencies>

創建實體類

import com.baomidou.mybatisplus.annotation.*;import java.util.Date;@Data
@TableName("sys_operation_log")
public class SysOperationLog {@TableId(value = "log_id", type = IdType.AUTO)private Long logId;private String operationType;private String operationModule;private String operationDesc;private String requestMethod;private String requestUrl;private String requestParams;private String responseResult;private String userId;private String userName;private String userIp;private String userAgent;@TableField(fill = FieldFill.INSERT)private Date operationTime;private Long executionTime;private Integer status;private String errorMsg;
}

添加mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;public interface SysOperationLogMapper extends BaseMapper<SysOperationLog> {
}

創建自定義注解

import java.lang.annotation.*;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Loggable {String operationType() default "";String module() default "";String description() default "";
}

創建AOP切面

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;@Aspect
@Component
@Slf4j
public class OperationLogAspect {private final SysOperationLogMapper logMapper;private final ObjectMapper objectMapper;public OperationLogAspect(SysOperationLogMapper logMapper, ObjectMapper objectMapper) {this.logMapper = logMapper;this.objectMapper = objectMapper;}@Around("@annotation(com.yourpackage.annotation.Loggable)")public Object logOperation(ProceedingJoinPoint joinPoint) throws Throwable {long startTime = System.currentTimeMillis();SysOperationLog operationLog = new SysOperationLog();Object result = null;try {// 獲取注解信息MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();Loggable loggable = method.getAnnotation(Loggable.class);// 填充日志基本信息operationLog.setOperationType(loggable.operationType());operationLog.setOperationModule(loggable.module());operationLog.setOperationDesc(loggable.description());operationLog.setOperationTime(new Date());// 獲取請求信息ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (attributes != null) {HttpServletRequest request = attributes.getRequest();operationLog.setRequestMethod(request.getMethod());operationLog.setRequestUrl(request.getRequestURI());operationLog.setUserIp(request.getRemoteAddr());operationLog.setUserAgent(request.getHeader("User-Agent"));}// 獲取用戶信息(根據你的系統實現)operationLog.setUserId("當前用戶ID");operationLog.setUserName("當前用戶名");// 獲取請求參數Object[] args = joinPoint.getArgs();operationLog.setRequestParams(objectMapper.writeValueAsString(args));// 執行目標方法result = joinPoint.proceed();// 記錄響應結果operationLog.setResponseResult(objectMapper.writeValueAsString(result));operationLog.setStatus(1);} catch (Exception e) {operationLog.setStatus(0);operationLog.setErrorMsg(e.getMessage());throw e;} finally {long endTime = System.currentTimeMillis();operationLog.setExecutionTime(endTime - startTime);// 異步保存日志(建議使用異步方式)logMapper.insert(operationLog);}return result;}
}

這是一個獲取用戶id和用戶名的示例方法

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;@Component
public class UserInfoUtils {// 根據你的安全框架實現獲取用戶信息public String getCurrentUserId() {// 示例:從Spring Security獲取return SecurityContextHolder.getContext().getAuthentication().getName();}public String getCurrentUsername() {// 實現獲取用戶名邏輯return "用戶名";}
}

使用

@RestController
@RequestMapping("/api")
public class DemoController {@Loggable(operationType = "QUERY", module = "用戶管理", description = "查詢用戶列表")@GetMapping("/users")public List<User> getUsers() {// 業務邏輯}
}

為了防止數據庫越來越大,可以刪除一年前的數據,我們可以通過數據庫層面實現

1. 創建存儲過程

DELIMITER $$CREATE PROCEDURE clean_old_logs()
BEGINDECLARE batch_size INT DEFAULT 1000;DECLARE deleted_rows INT DEFAULT 1;WHILE deleted_rows > 0 DODELETE FROM sys_operation_log WHERE operation_time < NOW() - INTERVAL 1 YEAR LIMIT batch_size;SET deleted_rows = ROW_COUNT();COMMIT;DO SLEEP(0.5); -- 防止鎖表太久END WHILE;
END$$DELIMITER ;

2. 創建定時事件,一天一次

CREATE EVENT execute_clean_procedure
ON SCHEDULE EVERY 1 DAY
STARTS CURRENT_TIMESTAMP + INTERVAL 1 DAY
DO
BEGINCALL clean_old_logs();
END

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/81494.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/81494.shtml
英文地址,請注明出處:http://en.pswp.cn/web/81494.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

開源多模態新標桿——BAGEL本地部署教程:7B參數撬動萬億數據

一、簡介 BAGEL &#xff0c;這是一個開源的多模態基礎模型&#xff0c;具有 70 億個激活參數&#xff08;總共 140 億個&#xff09;&#xff0c;并在大規模交錯多模態數據上進行訓練。 BAGEL 在標準多模態理解排行榜上超越了當前頂級的開源 VLMs 如 Qwen2.5-VL 和 InternVL…

SD卡+FATFS+Tinyjpeg圖片解碼顯示 (STM32F103VET6通過CubeMX快速建立工程)

先展示最終實現的功能效果如下: 1.目的與意義 為什么選用SD卡? 使用Nor-flash(W25Q系列)進行圖片的存取,需要先把圖片通過對應軟件批量處理為二進制bin文件,再通過SPI等通訊方式將 bin文件燒寫進Nor-flash才能進行使用,使用時還要記住每張圖片的首地址和對應字節數,MC…

數據結構-散列表查找(哈希表)

一&#xff0c;散列表查找定義 散列技術是在記錄的存儲位置和它的關鍵字之間建立一個確定的對應關系f&#xff0c;使得每個關鍵字key對應一個存儲位置f(key)。查找時&#xff0c;根據這個確定的對應關系找到給定值key的映射f(key)&#xff0c;若查找集中存在這個記錄&#xff0…

Stable Diffusion 簡單了解一下

1. 幫我簡單介紹一下:StableDiffusion ?? Stable Diffusion 是什么? Stable Diffusion 是一個 文本生成圖像(Text-to-Image) 的人工智能模型。你只需要輸入一句話,它就能根據這句話生成一張高質量的圖片。 比如: "一只穿著太空服的貓,在月球上彈吉他"St…

R語言科研編程-標準偏差柱狀圖

生成隨機數據 在R中&#xff0c;可以使用rnorm()生成正態分布的隨機數據&#xff0c;并模擬分組數據。以下代碼生成3組&#xff08;A、B、C&#xff09;隨機數據&#xff0c;每組包含10個樣本&#xff1a; set.seed(123) # 確保可重復性 group_A <- rnorm(10, mean50, sd…

普羅米修斯監控CPU\內存匯聚圖

要找出內存使用率大于80%的主機&#xff0c;你可以使用以下PromQL查詢。這個查詢會計算每個節點的內存使用率&#xff0c;然后篩選出使用率超過80%的節點&#xff1a; (avg by(nodename) ((node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)* on(instance) group…

飛牛fnNAS手機相冊備份及AI搜圖

目錄 一、相冊安裝應用 二、手機開啟自動備份 三、開始備份 四、照片檢索 五、AI搜圖設置 六、AI搜圖測試 七、照片傳遞 現代的手機,已經成為我們最親密的“伙伴”。自從手機拍照性能提升后,手機已經完全取代了簡單的卡片相機,而且與入門級“單反”相機發起了挑戰。在…

華為高斯數據庫(GaussDB)深度解析:國產分布式數據庫的旗艦之作

高斯數據庫介紹 一、高斯數據庫概述 GaussDB是華為自主研發的新一代分布式關系型數據庫&#xff0c;專為企業核心系統設計。它支持HTAP&#xff08;混合事務與分析處理&#xff09;&#xff0c;兼具強大的事務處理與數據分析能力&#xff0c;是國產數據庫替代的重要選擇。 產…

網頁 CSS美化2(詳解)

這是接著上一篇css基礎的第二篇&#xff1a;主要開始對頁面的布局進行學習 顯示模式&#xff1a; 塊級模式&#xff08;Block&#xff09; 特點 &#xff1a; 元素會獨占一行&#xff0c;在其前后會自動換行&#xff0c;與其他塊級元素在垂直方向上排列。 寬度默認為所在容器…

JSON解析性能優化全攻略:協程調度器選擇與線程池饑餓解決方案

簡介 JSON解析是現代應用開發中的基礎操作,但在使用協程處理時,若調度器選擇不當,會導致性能嚴重下降。特別是當使用Dispatchers.IO處理JSON解析時,可能觸發線程池饑餓,進而引發ANR或系統卡頓。本文將深入剖析這一問題的技術原理,提供全面的性能檢測方法,并給出多種優化…

python打卡第37天

知識點回顧&#xff1a; 過擬合的判斷&#xff1a;測試集和訓練集同步打印指標模型的保存和加載 僅保存權重保存權重和模型保存全部信息checkpoint&#xff0c;還包含訓練狀態 早停策略 作業&#xff1a;對信貸數據集訓練后保存權重&#xff0c;加載權重后繼續訓練50輪&#xf…

【洛谷P9303題解】AC- [CCC 2023 J5] CCC Word Hunt

在CCC單詞搜索游戲中&#xff0c;單詞隱藏在一個字母網格中。目標是確定給定單詞在網格中隱藏的次數。單詞可以以直線或直角的方式排列。以下是詳細的解題思路及代碼實現&#xff1a; 傳送門&#xff1a; https://www.luogu.com.cn/problem/P9303 解題思路 輸入讀取與初始化&…

LangGraph + LLM + stream_mode

文章目錄 LLM 代碼valuesmessagesupdatesmessages updatesmessages updates 2 LLM 代碼 from dataclasses import dataclassfrom langchain.chat_models import init_chat_model from langgraph.graph import StateGraph, STARTfrom langchain_openai import ChatOpenAI # 初…

Pydantic 學習與使用

Pydantic 學習與使用 在 Fastapi 的 Web 開發中的數據驗證通常都是在使用 Pydantic 來進行數據的校驗&#xff0c;本文將對 Pydantic 的使用方法做記錄與學習。 **簡介&#xff1a;**Pydantic 是一個在 Python 中用于數據驗證和解析的第三方庫&#xff0c;它現在是 Python 使…

批量文件重命名工具

分享一個自己使用 python 開發的小軟件&#xff0c;批量文件重命名工具&#xff0c;主要功能有批量中文轉拼音&#xff0c;簡繁體轉換&#xff0c;大小寫轉換&#xff0c;替換文件名&#xff0c;刪除指定字符&#xff0c;批量添加編號&#xff0c;添加前綴/后綴。同時還有文件時…

多語言視角下的 DOM 操作:從 JavaScript 到 Python、Java 與 C#

多語言視角下的 DOM 操作&#xff1a;從 JavaScript 到 Python、Java 與 C# 在 Web 開發中&#xff0c;文檔對象模型&#xff08;DOM&#xff09;是構建動態網頁的核心技術。它將 HTML/XML 文檔解析為樹形結構&#xff0c;允許開發者通過編程方式訪問和修改頁面內容、結構和樣…

【C/C++】紅黑樹學習筆記

文章目錄 紅黑樹1 基本概念1.1 定義1.2 基本特性推理1.3 對比1.4 延伸1.4.1 簡單判別是否是紅黑樹1.4.2 應用 2 插入2.1 插入結點默認紅色2.2 插入結點2.2.1 插入結點是根結點2.2.2 插入結點的叔叔是紅色2.2.3 插入結點的叔叔是黑色場景分析LL型RR型LR型RL型 3 構建4 示例代碼 …

網絡通信的基石:深入理解幀與報文

在這個萬物互聯的時代&#xff0c;我們每天都在享受著網絡帶來的便利——從早晨查看天氣預報&#xff0c;到工作中的視頻會議&#xff0c;再到晚上刷著短視頻放松。然而&#xff0c;在這些看似簡單的網絡交互背后&#xff0c;隱藏著精密而復雜的數據傳輸機制。今天&#xff0c;…

STM32 SPI通信(硬件)

一、SPI外設簡介 STM32內部集成了硬件SPI收發電路&#xff0c;可以由硬件自動執行時鐘生成、數據收發等功能&#xff0c;減輕CPU的負擔 可配置8位/16位數據幀、高位先行/低位先行 時鐘頻率&#xff1a; fPCLK / (2, 4, 8, 16, 32, 64, 128, 256) 支持多主機模型、主或從操作 可…

尚硅谷redis7-11-redis10大類型之總體概述

前提&#xff1a;我們說的數據類型一般是value的數據類型&#xff0c;key的類型都是字符串。 redis字符串【String】 string類型是二進制安全的,意思是redis的string可以包含任何數據,比如jpg圖片或者序列化的對象。 string類型是Redis最基本的數據類型,一個redis中字符串va…