✨ 哈喽,屏幕前的每一位开发者朋友,你们好呀!✨​

当你点开这篇文章时,或许正对着 IDE 里闪烁的光标发呆,或许刚解决一个卡了三天的 bug,正端着咖啡松口气 —— 不管此刻的你在经历什么,都想先和你说声:“辛苦了,同行者!” 👋​

作为一名摸爬滚打多年的开发工程师,我始终觉得,我们敲出的每一行代码,不仅是业务逻辑的堆叠,更是无数个 “踩坑与爬坑” 的缩影。从第一次上线时的手忙脚乱,到如今能冷静应对突发 bug;从对着文档啃源码的迷茫,到能给新人讲清设计思路 —— 这些藏在键盘敲击声里的成长,太值得被好好梳理和分享了。 📝​

所以,这一系列文章里,不会有太多高深的架构理论,也不会罗列晦涩的技术文档。我想聊的,是那些 “教科书里没写” 的实战细节:​

比如上线前必做的 3 个自查动作(亲测能减少 80% 的线上问题)🛡️;​

比如和产品经理 “友好沟通” 需求的 5 个小技巧(避免反复改需求到崩溃)🤝;​

比如如何用最少的时间,快速定位线上性能瓶颈(曾靠这招拯救过一次紧急故障)🚀;​

再比如那些看似 “浪费时间” 的重构,其实藏着怎样的长期价值…… ♻️​

当然,更想和大家聊聊 “技术之外” 的事:如何平衡加班与生活(毕竟身体是敲代码的本钱)💪,如何在团队中清晰表达自己的想法(别让好方案被沉默埋没)🗣️,甚至是 “35 岁焦虑” 来袭时,我是如何调整心态的…… 🌱​

如果你也和我一样,相信 “经验不是用来炫耀的资本,而是能帮同行少走弯路的路灯”,那不妨坐下来喝杯茶,一起在评论区聊聊:你最近遇到的最大挑战是什么?有没有哪个瞬间,让你觉得 “啊,原来我真的成长了”? 💬​

毕竟,开发这条路从来不是孤军奋战。我们分享的每一个踩坑故事,都可能成为别人的指路牌;你留下的每一条评论,或许也会给我新的启发。 🌟​

那么,准备好了吗?让我们开始这场 “代码背后的成长对话” 吧!接下来的每一篇,都等你来拍砖、补充、共鸣 —— 因为最好的经验,永远在交流里生长。 🌱​

目录

一.需求分析

二.实现逻辑(完全由后端实现)

1.自定义注解OperatorLog

2.在所有controller的方法上,添加该自定义注解

3.编写切面类OperationLogAspect

三.效果展示

1.使用一下管理系统的某个功能

2.查看数据库,肯定会多一条操作日志

四.特别声明


一.需求分析

我要实现的效果是,我访问管理系统的任何一个功能之后,都要往数据库插入一条操作日志。

举例:我在管理系统中,新增了一条合同记录,此时就需要往数据库插入一条操作日志,样式如下

二.实现逻辑(完全由后端实现)

1.自定义注解OperatorLog

@Target(ElementType.METHOD)//表明这个注解只能加在方法上
@Retention(RetentionPolicy.RUNTIME)//表明这个注解在程序运行的时候还能被读取到,而不是用完就丢)
public @interface OperationLog {String moduleName();//模块名String operationType();//操作类型
}

2.在所有controller的方法上,添加该自定义注解

举例:

3.编写切面类OperationLogAspect

@Aspect
@Component
public class OperationLogAspect {//注入SysOperationLogMapper对象@Autowiredprivate SysOperationLogMapper sysOperationLogMapper;//拦截所有加了@OperationLog注解的方法,进行功能无侵入增强(环绕通知)@Around("@annotation(operationLog)")public Object around(ProceedingJoinPoint joinPoint, OperationLog operationLog) throws Throwable {//ProceedingJoinPoint joinPoint:拦截的方法本身(我们要拦截controller层的方法)//OperationLog operationLog:在所拦截的方法上,添加的注解内容//获取当前的HTTP请求对象HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();//1.获取请求的controller方法的模块名称、操作类型(从注解中获取)String moduleName = operationLog.moduleName();String operationTypeStr = operationLog.operationType();//2.获取本次请求的请求方式(如GET、POST、PUT、DELETE)String requestMethod = request.getMethod();//3.获取请求发起人的用户名称(直接从请求对象中获取即可(别的服务放进去的))//3.1先获取controller方法的参数实体类Object[] args = joinPoint.getArgs();Object entity = args[0];//必须默认controller的实体类参数放在第一个//3.2通过反射,拿到实体类中的用户名称(curUserName)Method getCurUserName = entity.getClass().getMethod("getCurUserName");String operator = (String)getCurUserName.invoke(entity);//4.获取请求发起人的主机ipString hostIp = ClientIpUtil.getClientIpAddress(request);//5.获取操作时间(就是当前的时间)Date operationTime = new Date();//6.先默认操作状态为成功Integer operationStatus = 1;//7.获取请求方法的全类名,如:com.hxb.xltj.controller.SysLogControllerString methodFullName = joinPoint.getTarget().getClass().getName();//System.out.println(methodFullName);//8.被增强的controller方法的返回结果(字符串类型)String methodResult = null;//9.请求路径String requestUrl = request.getRequestURI();//10.请求参数String requestParam = JSON.toJSONString(entity);try{//放行被增强的方法Object result = joinPoint.proceed();//查看被增强方法是否执行成功if(result instanceof ResultBody){ResultBody resultBody = (ResultBody) result;//如果返回的结果响应码不是“000000”,则说明请求失败了,直接令该日志的状态为0(失败)operationStatus = !resultBody.getReturnCode().equals("000000")? 0:1;//如果是“导出”操作,就将返回体ResultBody的data属性设为空(不给前端展示,太长了)if(operationTypeStr.equals("导出")){methodResult = "";}else{//给返回结果赋值methodResult = result.toString();}}//将结果返回出去,不要让切面吞被增强方法的原有逻辑return result;}catch(Exception e){throw e;//继续抛出异常,不影响原有错误处理}finally{//看看都获取到了哪些日志信息//System.out.println(moduleName);//测试模块//System.out.println(operationType);//查询//System.out.println(requestMethod);//POST//System.out.println(hostIp);//127.0.0.1//System.out.println(operationTime);//Thu Aug 21 10:48:07 CST 2025//System.out.println(operationStatus);//1(代表成功)//将操作类型转为整型,再存入数据库Integer operationType = operationTypeStr.equals("新增")?1:operationTypeStr.equals("删除")?2:operationTypeStr.equals("修改")?3:operationTypeStr.equals("查询")?4:operationTypeStr.equals("授权")?5:operationTypeStr.equals("导出")?6:operationTypeStr.equals("导入")?7:operationTypeStr.equals("强退")?8:operationTypeStr.equals("生成代码")?9:operationTypeStr.equals("清空数据")?10:null;//封装系统操作日志记录对象SysOperationLog sysOperationLog = new SysOperationLog(null, moduleName, operationType, requestMethod, operator, hostIp, operationStatus, operationTime,methodFullName,methodResult,requestUrl, requestParam,0,null,null);//将系统操作日志,存入数据库sysOperationLogMapper.insert(sysOperationLog);}}
}

上述代码,核心逻辑就是:获取到【系统日志表】需要的所有字段,然后写入数据库即可。

三.效果展示

1.使用一下管理系统的某个功能

2.查看数据库,肯定会多一条操作日志

四.特别声明

1.如果你想让管理系统的所有行为,都记录到操作日志表中,你需要把后端所有的controller方法,都加上自定义注解@OperatorLog(因为只有这样,才会被AOP切面进行代码无侵入增强)

2.由于AOP切面类OperationLogAspect里面,有一些反射操作(通过controller方法的形参获取操作信息),因此需要团队伙伴在写controller方法时,要遵循一定的约束(比如:controller方法必须通过Body接收参数,且Body参数必须放在形参列表的第一位)。

诸如此类,具体需要团队伙伴遵循哪些约束,需要具体看需求和代码逻辑,我们主要有这个意识就行,其他都好说。

以上就是通过SpringAOP切面编程,实现【记录系统操作日志】功能的详细流程,喜欢的话可以留个免费的关注呦~~~

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

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

相关文章

响应式编程框架Reactor【4】

文章目录七、调度与线程模型7.1 概述7.2 Scheduler: Reactor 的线程调度器7.3 两大核心操作符:subscribeOn vs publishOn7.4 示例详解7.4.1 subscribeOn()的全局影响7.4.2 publishOn() 的局部切换7.4.3 多个publishOn切换7.4.4 线程切换时序图7.5 核心调度器7.5.1 B…

第21节:环境贴图与PBR材质升级——构建电影级真实感渲染

第21节:环境贴图与PBR材质升级——构建电影级真实感渲染 概述 基于物理的渲染(Physically Based Rendering, PBR)是当代计算机图形学中最重要的技术进步之一,它彻底改变了实时渲染的质量标准。在本节中,我们将深入探索…

【ROS2】ROS2 基础学习教程 、movelt学习

主要博主 参考资料: ROS系列: b站荔枝橙 b战哈萨克斯坦x 《ROS 2机器人开发从入门到实践》6.2.2 在RViz中显示机器人_哔哩哔哩_bilibili 动手学ROS2–鱼香肉丝 ​​​​​​​ 古月居ros2教程 北京华清智能科技 ros教程 moveit系列: 爱喝青…

Java类加载与JVM详解:从基础到双亲委托机制

在Java开发中,理解JVM(Java虚拟机)和类加载机制是掌握高级特性的关键。本文将从JDK、JRE、JVM的关系入手,深入讲解JVM的内存结构,并详细剖析类加载的全过程,包括加载时机、流程以及核心机制——双亲委托模型…

准备机试--图【y总版】[重要]【最短路】

常用代码模板3——搜索与图论 - AcWing 一般,稀疏图(m约等于n):堆优化版本的dj;稠密图(mn^2):朴素dj 最短路的难点在于建图【抽象出点和边】 朴素dj

Python API接口实战指南:从入门到精通

🌟 Hello,我是蒋星熠Jaxonic! 🌈 在浩瀚无垠的技术宇宙中,我是一名执着的星际旅人,用代码绘制探索的轨迹。 🚀 每一个算法都是我点燃的推进器,每一行代码都是我航行的星图。 &#x…

Spring和mybatis整合后事务拦截器TransactionInterceptor开启提交事务流程

目录一、说明二、TransactionInterceptor开启事务(1)、拦截方法(2)、开启事务绑定数据库连接(3)、mybatis中sql执行数据库连接获取(4)、事务提交和当前线程ThreadLocal清理&#xff…

05.《ARP协议基础知识探秘》

ARP协议基本介绍与实践 文章目录**ARP协议基本介绍与实践**ARP概述ARP报文类型ARP工作过程解析ARP工作原理示意图无故ARP/免费ARP实验案例**实验目标**实验环境实验步骤ARP概述 作用:ARP(Address Resolution Protocol,地址解析协议&#xff…

互联网大厂面试:大模型应用开发岗位核心技术点解析

互联网大厂面试:大模型应用开发岗位核心技术点解析 第一轮:大模型基础与上下文工程 问题 1:你能简单介绍 Transformer 架构的工作原理吗? 小C:嗯,我理解是 Transformer 主要依赖自注意力机制(Se…

【深度学习新浪潮】有没有什么方法可以将照片变成线描稿,比如日式漫画的那种?

一、技术原理与研究进展 1. 线描生成的核心技术路径 传统方法:基于边缘检测(如Canny算子)和形态学操作,但难以处理复杂纹理和艺术风格。 深度学习方法: 端到端生成:使用U-Net架构(如ArtLine项目)直接学习照片到线描的映射,结合自注意力机制和感知损失提升细节保留能力…

NV032NV037美光固态闪存NV043NV045

NV032NV037美光固态闪存NV043NV045在数字化浪潮席卷全球的当下,存储技术的每一次突破都深刻影响着从个人消费到企业级应用的各个领域。美光科技作为行业领军者,其NV系列固态闪存产品始终以技术创新为核心驱动力。本文将聚焦NV032、NV037、NV043、NV045四…

天硕G40工业固态硬盘破解轨道存储难题

在高铁与轨道交通高速发展的今天,轨道检测探伤是保障列车安全运行的核心环节。据统计,我国铁路总里程已突破16万公里,日均检测数据量超10TB。加固平板一体机作为轨道探伤领域的“移动工作站”,需要在跨越大江南北的极端环境中实时…

基于Velero + 阿里云 OSS的Kubernetes 集群的备份与恢复

在 Kubernetes(K8s)中,备份和恢复是保障数据安全与业务连续性的关键环节,主要方式包括 ETCD 备份恢复 和 Velero 备份恢复,两者在备份粒度、恢复影响范围、存储位置等方面存在以下差异: 1、ETCD 备份恢复&…

解构与重构:“真人不露相,露相非真人” 的存在论新解 —— 论 “真在” 的行为表达本质

解构与重构:“真人不露相,露相非真人” 的存在论新解 —— 论 “真在” 的行为表达本质绪论:传统解释的突围 —— 从 “藏才” 到 “存真”“真人不露相,露相非真人” 这句谚语,自明代《西游记》以降,便长期…

数据结构:哈希表、排序和查找

一、哈希算法1.将数据通过哈希算法映射成一个健值,存取都在同一个位置,实现数据的高效存储和查找,时间复杂度由O(n)->O(1)2.哈希碰撞:多个数据通过哈希算法得到的键值相同二、哈希表1.构建哈希表存放0-100之间的数据2.哈希算法…

【Java基础】Java I/O模型解析:BIO、NIO、AIO的区别与联系(Netty入门必备基础)

Java I/O模型深度解析:BIO、NIO、AIO的区别与联系 引言 在Java的网络编程与文件操作中,I/O(输入/输出)模型是绕不开的核心话题。从早期的BIO(Blocking I/O)到Java 1.4引入的NIO(Non-blocking I/…

windows PowerToys之无界鼠标:一套键鼠控制多台设备

💻简介 在多设备协作的工作场景中,如何实现一套键鼠控制多台设备了?微软推出的 PowerToys 工具集中的 Mouse Without Borders(无界鼠标),通过软件层实现跨设备的键鼠共享与数据同步功能,为多台…

一道比较难的sql题,筛选出重复字段的行数

select * from 导入数据表; id city_column 1 北京,上海,广州 2 上海,上海,深圳 3 北京,杭州,北京 4 上海,广州,深圳select substring_index(khmc,,,1), * from 导入数据表 truncate table 导入数据表 select count(distinct khmc) from 导入数据表; …

【K8s】整体认识K8s之与集群外部访问--service

这一篇文章主要是对service发现新的理解 为什么要使用service服务发现? 首先pod的IP,是动态的,当我们重启一个pod的时候,它会给它分配一个新的IP,但是如果微服务a想要去调用微服务b,他是需要知道微服务b所有…

k8s(自写)

kubernetes k8s是什么?Kubernetes是什么?架构是怎么样的?6分钟快速入门_哔哩哔哩_bilibili kubernetes是google开源神器,介于应用服务和服务器之间,能够通过策略协调和管理多个应用服务,只需要一个yaml文…