当前位置: 首页 > article >正文

SpringBoot3实战集成mzt-biz-log,一行代码搞定业务日志记录

作为后端开发者业务日志是线上问题排查、操作追溯和审计留痕的核心抓手。手写业务日志不仅重复代码量大还容易出现记录不规范、关键信息漏记错记的问题排查线上问题时往往效率极低。最近我在SpringBoot3项目中接入了mzt-biz-log这款轻量业务日志框架彻底摆脱了手写日志的繁琐注解式配置就能精准记录操作人、业务内容、变更前后数据和业务主键等核心信息全程无侵入、易扩展。本篇全是实打实的落地步骤不扯多余理论跟着一步步做就能直接跑通。一、环境准备技术集成优先保证版本适配本次采用稳定对齐的固定环境直接照搬就能规避所有兼容问题具体配置如下JDK 17SpringBoot 3.2.5Maven 3.8.6mzt-biz-log 3.0.6二、引入Maven核心依赖在项目pom.xml中添加框架核心依赖这款框架本身轻量无冗余依赖不会增加项目包体积搭配日常通用工具包即可正常使用。!-- 定义bizlog-sdk版本号推荐在pom.xml properties节点统一管理 -- properties bizlog-sdk.version3.0.6/bizlog-sdk.version /properties !-- mzt-biz-log 正确核心依赖适配SpringBoot 3.2.5 -- dependency groupIdio.github.mouzt/groupId artifactIdbizlog-sdk/artifactId version${bizlog-sdk.version}/version /dependency依赖引入后刷新Maven确保所有依赖下载完成如果中央仓库下载缓慢直接切换阿里云镜像就能加速。三、核心配置实现mzt-biz-log核心配置分为操作人获取和日志持久化两部分框架不限制日志存储介质支持数据库、ES、MongoDB等多种落地方式日常开发优先存入业务日志表。3.1 自定义操作人获取类框架无法自动获取登录用户信息需要自定义实现操作人获取接口从项目登录上下文、Token解析或者ThreadLocal中获取当前操作人这段代码可以直接适配项目登录体系复用。import com.mzt.logapi.beans.Operator; import com.mzt.logapi.service.IOperatorGetService; import org.springframework.stereotype.Component; Component public class CustomOperatorGetService implements IOperatorGetService { Override public Operator getUser() { // 替换为项目真实获取登录用户逻辑 // 示例return UserContext.getCurrentUser().getUsername(); // 测试阶段可暂用固定值上线后对接登录体系 return new Operator(admin); } }3.2 自定义日志持久化处理器实现框架日志记录接口重写核心保存方法调试阶段可以先打印控制台日志方便查看效果正式环境直接对接数据库Mapper将日志存入业务日志表全程不侵入任何业务代码。import com.mzt.logapi.beans.LogRecord; import com.mzt.logapi.service.ILogRecordService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.List; Slf4j Component public class CustomLogRecordService implements ILogRecordService { /** * 日志核心保存方法 */ Override public void record(LogRecord logRecord) { // 调试阶段控制台打印日志 log.info(业务日志); log.info(操作人{}, logRecord.getOperator()); log.info(业务类型{}, logRecord.getType()); log.info(业务ID{}, logRecord.getBizNo()); log.info(操作内容{}, logRecord.getAction()); log.info(操作时间{}, logRecord.getCreateTime()); log.info(); // 生产环境对接数据库实现日志入库 // BizLogEntity logEntity buildLogEntity(logRecord); // bizLogMapper.insert(logEntity); } Override public ListLogRecord queryLog(String bizNo, String type) { return List.of(); } Override public ListLogRecord queryLogByBizNo(String bizNo, String type, String subType) { return List.of(); } }3.3 开启日志注解功能在SpringBoot启动类上添加开启注解激活框架的日志记录功能这一步绝对不能省略否则注解会完全不生效。import com.mzt.logapi.starter.annotation.EnableLogRecord; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; SpringBootApplication EnableLogRecord(tenant ) public class Springboot3BizLogApplication { public static void main(String[] args) { SpringApplication.run(Springboot3BizLogApplication.class, args); } }至此核心配置全部完成没有繁琐的YAML配置整体结构清晰后续扩展和修改都很方便也不会对原有业务代码造成任何影响。四、业务代码接入实战配置完成后直接通过注解就能实现日志自动记录框架支持SpEL表达式可动态获取方法入参、业务数据灵活记录各类操作详情。接下来以用户管理模块为例演示编辑、删除场景的日志接入方式覆盖日常开发核心业务场景。4.1 准备业务实体类先创建基础的用户实体类模拟业务数据对象用于后续日志记录测试。import lombok.Data; Data public class UserInfo { private Long userId; private String username; private String phone; private Integer age; }4.2 注解实现业务日志记录在业务实现类的方法上添加日志注解框架会在方法执行成功后自动记录日志异常场景不记录完全符合日常业务日志的记录逻辑。针对数据修改场景可以通过框架上下文存入旧数据实现变更前后的对比记录。import com.example.bizlogdemo.entity.UserInfo; /** * 用户服务接口 * 提供用户信息的更新和删除操作 */ public interface UserService { /** * 更新用户信息 * p * 根据传入的用户信息对象更新对应用户的数据包括用户名、手机号、年龄等信息 * /p * * param user 包含更新信息的用户对象必须包含有效的 userId * return 更新成功返回 true失败返回 false */ boolean updateUser(UserInfo user); /** * 删除用户 * p * 根据用户 ID 删除对应的用户信息 * /p * * param userId 要删除的用户 ID * return 删除成功返回 true失败返回 false */ boolean deleteUser(Long userId); }import com.example.bizlogdemo.entity.UserInfo; import com.mzt.logapi.context.LogRecordContext; import com.mzt.logapi.starter.annotation.LogRecord; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; Service Slf4j public class UserServiceImpl implements UserService { /** * 编辑用户信息记录变更前后数据 */ Override LogRecord( bizNo {{#user.userId}}, success 编辑用户信息用户ID{{#user.userId}}修改前用户名{{#oldUser.username}}修改后用户名{{#user.username}}修改前手机号{{#oldUser.phone}}修改后手机号{{#user.phone}}, type user ) public boolean updateUser(UserInfo user) { // 查询数据库旧数据 UserInfo oldUser getUserById(user.getUserId()); log.info(执行用户更新操作用户ID{}, user.getUserId()); // 旧数据存入上下文供日志注解读取 LogRecordContext.putVariable(oldUser, oldUser); return true; } /** * 删除用户记录删除操作 */ Override LogRecord( bizNo {{#userId}}, success 删除用户用户ID{{#userId}}, type user ) public boolean deleteUser(Long userId) { log.info(执行用户删除操作用户ID{}, userId); return true; } /** * 模拟根据ID查询用户旧数据 */ private UserInfo getUserById(Long userId) { UserInfo oldUser new UserInfo(); oldUser.setUserId(userId); oldUser.setUsername(测试用户); oldUser.setPhone(13800138000); oldUser.setAge(20); return oldUser; } }实战小贴士数据修改场景通过LogRecordContext.putVariable()存入旧数据即可在注解中通过SpEL表达式调用实现变更对比记录新增场景直接记录业务内容bizNo使用生成后的主键即可。五、接口测试与日志验证编写控制层接口调用业务层方法测试日志是否正常记录确认整体集成效果。为了方便测试控制层接口我集成了knife4J直接生成接口文档。import com.example.shardingspheredemo.entity.UserInfo; import com.example.shardingspheredemo.service.UserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/user) Tag(name 用户管理接口, description 用户增删改查接口) public class UserController { Resource private UserService userService; PostMapping(/update) Operation(summary 更新用户, description 传入用户信息返回用户ID) ApiResponse(responseCode 200, description 新增成功, content Content(schema Schema(implementation String.class))) public String updateUser(RequestBody UserInfo user) { boolean result userService.updateUser(user); return result ? 修改成功 : 修改失败; } GetMapping(/delete/{userId}) Operation(summary 根据ID删除用户, description 传入用户ID删除用户数据) public String deleteUser(PathVariable Long userId) { boolean result userService.deleteUser(userId); return result ? 删除成功 : 删除失败; } }5.1 接口实测1. 用户编辑接口测试测试请求地址及参数如下测试结果日志打印如下2. 用户删除接口测试测试请求地址及参数如下测试结果日志打印如下六、实战扩展思路敏感数据脱敏针对手机号、身份证号等敏感信息自定义脱敏规则在日志记录前完成处理异步日志记录使用Async实现异步保存日志避免日志记录影响业务接口性能异常日志记录结合全局异常处理器记录操作失败日志完善全流程操作追溯批量业务日志框架支持批量操作场景循环遍历业务逻辑注解依旧正常生效七、总结mzt-biz-log 轻量无侵入稳定性强注解式开发彻底告别手写日志代码实现业务逻辑与日志记录完全解耦日志记录规范统一大幅提升线上问题排查和操作审计效率。单体应用和微服务项目均可快速接入尤其适合管理后台、电商等需要完善操作追溯的业务系统。可以先在测试项目调试落地确认无误后直接迁移至正式项目整体接入成本极低。使用过程中有什么问题欢迎在评论区留言讨论。

相关文章:

SpringBoot3实战集成mzt-biz-log,一行代码搞定业务日志记录

作为后端开发者,业务日志是线上问题排查、操作追溯和审计留痕的核心抓手。手写业务日志不仅重复代码量大,还容易出现记录不规范、关键信息漏记错记的问题,排查线上问题时往往效率极低。最近我在SpringBoot3项目中接入了mzt-biz-log这款轻量业…...

搞嵌入式开发的小伙伴应该都遇到过PID调参这个头疼的问题吧?今天咱们直接上干货,聊聊怎么在STM32上玩转PID自整定和温度控制。先扔个核心代码片段镇楼

基于STM32开发的PID自整定和PID温控和PWM输出程序源码,采用反馈法进行PID参数自动整定,得出系统临界值比例增益,自动计算调节,使系统进入正常状态。 程序源码注释详细typedef struct {float Kp;float Ki;float Kd;float integral_…...

智能指针相关

零、预备知识 右值: 表示不可寻址的临时数据值。 根据C11标准,右值分为纯右值(如字面量、表达式结果)和将亡值(即将销毁的对象)。 右值具有不可修改、无持久内存地址的特性 右值引用&&、移动语义…...

当立体车库遇上PLC仿真

西门子1200PLC立体车库 33立体车库 博图触摸屏仿真 不需要实物 自带人机界面,动画,可以仿真 还有接线图原理图 现在拥有自动出入仓库的功能 IO表已列出最近捣鼓了个挺有意思的项目——基于西门子1200PLC的33立体车库仿真。不用焊线接电机,纯…...

HTML基础教程(一)

目录 一、HTML基本概念 二、基础HTML (Tag) 三、Html常用格式 一、HTML基本概念 什么是HTML文件? HTML的英文全称是Hypertext Marked Language,中文叫做“超文本标记语言”。和一般文本的不同的是,一个HTML文件不…...

AI基石 | 对齐技术:从 RLHF 到 DPO —— 赋予大模型“三观”的终极进化

AI基石 | 对齐技术:从 RLHF 到 DPO —— 赋予大模型“三观”的终极进化 前言 如果 SFT(监督微调)后的模型是一个“懂事”的练习生,那么对齐后的模型就是一个“老练”的专家。 练习生虽然知道问答的格式,但依然存在两个…...

俄罗斯RT-2PM2“白杨-M“(Topol-M)洲际弹道导弹系统完整技术报告

Comprehensive Technical Report on Russias RT-2PM2 Topol-M Intercontinental Ballistic Missile System 报告日期:2026年3月11日 保密级别:公开来源情报(OSINT) 摘要(Executive Summary) RT-2PM2"…...

Java线程池面试题50道(含答案解析)

在Java后端开发面试中,线程池(ThreadPool) 是并发编程的重要考点之一。 在高并发系统中,合理使用线程池可以 提高系统性能、减少线程创建开销、避免资源耗尽。 很多互联网公司在面试Java工程师时都会重点考察: 线程池原…...

Clawdbot 杀红眼了,几天怒斩 80k+ Star!你真正的 AI 数字员工来了!!(附保姆级安装使用教程)

最近一款 AI 开源工具 Clawdbot 杀疯了,人送外号:大龙虾,短短几天时间,GitHub 上 Star 数量暴涨到 80k,因为名称与 Claude 相似,还被 Anthropic 公司警告被迫改名:Moltbot。 Moltbot 的核心是它…...

Python3.9环境配置太麻烦?试试这个Miniconda镜像,一键部署

Python3.9环境配置太麻烦?试试这个Miniconda镜像,一键部署 还在为配置Python开发环境而头疼吗?从源码编译安装,要解决一堆依赖问题;手动下载安装包,又担心版本冲突和路径混乱。特别是当你需要Python 3.9这…...

从原理到代码:深度解析Halcon中segment_contours_xld的Ramer算法实现

从原理到代码:深度解析Halcon中segment_contours_xld的Ramer算法实现 在机器视觉的工程实践中,我们常常需要将相机捕捉到的、由像素点构成的连续轮廓,转化为更高级、更易于理解和处理的几何基元,比如直线、圆弧或椭圆弧。这个过程…...

Keil5 vs Keil6:如何选择?附带Keil5中STM32开发环境搭建全攻略(含FreeRTOS移植准备)

Keil MDK 进化论:从经典到现代,如何为你的STM32项目选择最佳开发环境 作为一名在嵌入式领域摸爬滚打了多年的开发者,我至今还记得第一次打开Keil MDK时那种既兴奋又茫然的心情。那个经典的蓝色界面,几乎成了ARM Cortex-M开发的代名…...

第三期:基于立创·梁山派开发板的游戏机扩展板训练营全记录

第三期:基于立创梁山派开发板的游戏机扩展板训练营全记录 大家好,我是老张,一个在嵌入式行业摸爬滚打了十几年的工程师。最近,我作为导师完整地跟进了立创EDA举办的“梁山派游戏机扩展板训练营”第三期。看到很多朋友对如何从零开…...

OAuth2.0中state参数的深度应用:业务数据的安全传输与防CSRF实践

1. 不只是防CSRF:重新认识OAuth2.0的state参数 很多刚开始接触OAuth2.0的开发者,一看到state参数,第一反应就是“哦,防CSRF的”。这个理解没错,但只对了一半。在实际项目中,尤其是在需要深度集成的场景里&a…...

Ubuntu20.04下拯救者笔记本亮度调节失效?NVIDIA驱动加载顺序问题全解析

Ubuntu 20.04 下拯救者笔记本亮度调节失效?NVIDIA 驱动加载顺序问题全解析 最近在联想拯救者系列笔记本上安装 Ubuntu 20.04 的朋友,可能都遇到过同一个令人头疼的问题:屏幕亮度过高,刺眼得让人无法工作,而无论是系统设…...

SAR动目标检测系列:【5】多基线联合处理下的三维速度解耦

1. 从二维到三维:为什么我们需要多基线联合处理? 在上一篇文章里,我们聊透了如何利用单天线或者双天线SAR系统,去估计动目标的二维速度(也就是方位向和距离向的速度)。这就像你用手机拍一个移动的物体&…...

Flink实战:如何用KeyedProcessFunction实现温度异常检测(附完整代码)

从零构建实时温度异常检测系统:深入Flink KeyedProcessFunction核心实战 最近在帮一个做智慧农业的朋友处理温室大棚的监控数据,他们部署了上百个温湿度传感器,数据像潮水一样涌来。最头疼的不是数据量大,而是如何从这些实时流里快…...

KITTI 3D 数据可视化:从点云到鸟瞰图的实战解析

1. 从零开始:理解KITTI数据集与3D点云 大家好,我是老张,在自动驾驶这个行当里摸爬滚打了十来年,跟激光雷达和相机数据打了无数次交道。今天,我想跟你聊聊一个非常基础但又极其重要的技能:如何把KITTI数据集…...

内存马二:Filter

Filter内存马 源码学习 首先写一个普通的Filter了解一下重点数据的传递过程,断点到内部的一行,往上找。回到的是org.apache.catalina.core.ApplicationFilterChain#internalDoFilter,这部分找到filters找filters的赋值的地方,找到…...

uni-id-pages配置email

uniappuniclouduni-id-pages 配置邮箱教程 安装uni-id-pages插件下载插件并导入HbuilderX 修改/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/verify/send-email-code.js文件内容,将测试代码注释,添加发送邮件代码 // -- 测试代码// awai…...

Android 休眠机制详解 ——WakeLock、Doze 模式与待机功耗优化实战

前言 待机功耗高、耗电快、手表 / 手机一觉醒来掉电很多,90% 都是 “休眠没睡进去”。 一、为什么要讲 Android 休眠? 对手机 / 手表 / IoT 设备来说: 亮屏 性能息屏待机 续航 功耗测试的核心,就是看设备能不能正常休眠、睡不睡…...

C++中的装饰器模式高级应用

1、非修改序列算法这些算法不会改变它们所操作的容器中的元素。1.1 find 和 find_iffind(begin, end, value):查找第一个等于 value 的元素,返回迭代器(未找到返回 end)。find_if(begin, end, predicate):查找第一个满…...

LeetCode 3296.移山所需的最少秒数:优先队列

【LetMeFly】3296.移山所需的最少秒数:优先队列 力扣题目链接:https://leetcode.cn/problems/minimum-number-of-seconds-to-make-mountain-height-zero/ 给你一个整数 mountainHeight 表示山的高度。 同时给你一个整数数组 workerTimes,表…...

深入解析尺度空间理论及其在SIFT特征提取中的应用

1. 从“看画”说起:为什么我们需要尺度空间? 想象一下,你站在一幅巨大的油画前,比如梵高的《星空》。当你把鼻子都快贴到画布上时,你只能看到一小片区域,那里有清晰的、厚重的笔触和颜料的纹理。你后退一步…...

Spring Boot文件上传报错Failed to parse multipart servlet request的3种解决方案及适用场景

1. 问题重现:那个让人头疼的“Failed to parse multipart servlet request” 不知道你有没有遇到过这种情况:一个好好的Spring Boot文件上传功能,平时用着都挺顺溜,突然有一天,用户反馈说上传文件报错了。你赶紧去查日…...

0.96寸OLED取模实战:从基础字符到动态图像显示

1. 为什么你的OLED屏幕只能显示英文?聊聊取模这回事 你是不是也遇到过这种情况?兴冲冲地买回来一块小巧精致的0.96寸OLED屏幕,连上Arduino或者ESP32,跑了个示例程序,屏幕上“Hello World”亮起,感觉科技感满…...

【C++】MSYS2进阶:从零到一打造现代化C++工作流

1. 为什么你的C开发环境需要一个“瑞士军刀”? 如果你在Windows上折腾过C开发环境,大概率经历过一场噩梦:去MinGW官网下载编译器,手动配置环境变量,再单独安装CMake、Ninja、GDB……每个工具都有自己的安装包和路径&am…...

ESP32-C61 TIMG定时器与看门狗深度实践指南

ESP32-C61 定时器组(TIMG)与看门狗定时器深度实践指南1. TIMG 架构概览与中断机制解析ESP32-C61 的定时器组(TIMG)是系统级时间管理的核心硬件模块,集成于两个独立的定时器组(TIMG0 和 TIMG1)&a…...

提示工程架构师揭秘:AI提示系统个性化与用户画像结合的4大方法

提示工程架构师揭秘:AI提示系统个性化与用户画像结合的4大方法 摘要/引言 在当今AI技术飞速发展的时代,AI提示系统已广泛应用于各种场景。然而,通用的提示往往无法满足每个用户的特定需求。本文旨在解决如何通过将AI提示系统与用户画像相结合…...

立创Ai8051U测控开发板:从传感器采集到无线通信的综合嵌入式实战平台

立创Ai8051U测控开发板:从传感器采集到无线通信的综合嵌入式实战平台 最近有不少朋友问我,想找一个能“一站式”学习嵌入式系统所有核心环节的开发板,从最基础的GPIO控制,到传感器数据采集、存储、显示,再到无线通信和…...