Springboot项目怎么设计业务操作日志功能?

news2024/10/7 12:19:22

目录

前言

需求描述与分析

系统日志

操作日志

设计思路

Spring AOP

Filter和HandlerInterceptor

过滤器

拦截器

SpringAOP、过滤器、拦截器对比

实现方案

环境配置

依赖配置

表结构设计

代码实现

测试

调试方法

验证结果

总结


前言

很久以前都想写这篇文章,一直没有空,但直到现在我对当时的情景还有印象,之所以有印象是因为需求很简单,业务操作日志的记录与查询的功能,但是具体实现真的很烂,具体的烂法会在反面示例里细说,领导以及客户层面很认可,一系列迷之操作,让我印象深刻。

需求描述与分析

客户侧提出需求很简单:要对几个关键的业务功能进行操作日志记录,即什么人在什么时间操作了哪个功能,操作前的数据报文是什么、操作后的数据报文是什么,必要的时候可以一键回退。

日志在业务系统中是必不可少的一个功能,常见的有系统日志、操作日志等:

系统日志

这里的系统日志是指的是程序执行过程中的关键步骤,根据实际场景输出的debug、info、warn、error等不同级别的程序执行记录信息,这些一般是给程序员或运维看的,一般在出现异常问题的时候,可以通过系统日志中记录的关键参数信息和异常提示,快速排除故障。

操作日志

操作日志,是用户实际业务操作行为的记录,这些信息一般存储在数据库里,如什么时间哪个用户点了某个菜单、修改了哪个配置等这类业务操作行为,这些日志信息是给普通用户或系统管理员看到。

通过对需求的分析,客户想要是一个业务操作日志管理的功能:

1、记录用户的业务操作行为,记录的字段有:操作人、操作时间、操作功能、日志类型、操作内容描述、操作内容报文、操作前内容报文

2、提供一个可视化的页面,可以查询用户的业务操作行为,对重要操作回溯;

3、提供一定的管理功能,必要的时候可以对用户的误操作回滚;

反面实现

明确需求后,就是怎么实现的问题了,这里先上一个反面的实现案例,也是因为这一个反面案例,才让我对这个简单的需求印象深刻。

这里我以一个人员管理的功能为例还原一下,当时的具体实现:

1、每个接口里都加一段记录业务操作日志的记录;

2、每个接口里都要捕获一下异常,记录异常业务操作日志;

下面是伪代码:

@RestController
@Slf4j
@BusLog(name = "人员管理")
@RequestMapping("/person")
public class PersonController2 {
    @Autowired
    private IPersonService personService;
    @Autowired
    private IBusLogService busLogService;
    //添加人员信息
    @PostMapping
    public Person add(@RequestBody Person person) {
       try{
           //添加信息信息
        Person result = this.personService.registe(person);
        //保存业务日志
        this.saveLog(person);
        log.info("//增加person执行完成");        
       }catch(Exception e){
           //保存异常操作日志
           this.saveExceptionLog(e);       
       }
        return result;
    }
}

这种通过硬编码实现的业务操作日志管理功能,最大的问题就是业务操作日志收集与业务逻辑耦合严重,和代码重复,新开发的接口在完成业务逻辑后要织入一段业务操作日志保存的逻辑,已开发上线的接口,还要重新再修改织入业务操作日志保存的逻辑并测试,且每个接口需要织入的业务操作日志保存的逻辑是一样的。

设计思路

如果对AOP有一些印象的话,最好的方法就是使用aop实现:

1、定义业务操作日志注解,注解内可以定义一些属性,如操作功能名称、功能的描述等;

2、把业务操作日志注解标记在需要进行业务操作记录的方法上(在实际业务中,一些简单的业务查询行为通常没有必要记录);

3、定义切入点,编写切面:切入点就是标记了业务操作日志注解的目标方法;切面的主要逻辑就是保存业务操作日志信息;

Spring AOP

AOP (Aspect Orient Programming),直译过来就是 面向切面编程,AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向切面编程,实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术,AOP可以拦截指定的方法并且对方法增强,而且无需侵入到业务代码中,使业务与非业务处理逻辑分离;而SpringAOP,则是AOP的一种具体实现,Spring内部对SpringAOP的应用最经典的场景就是Spring的事务,通过事务注解的配置,Spring会自动在业务方法中开启、提交业务,并且在业务处理失败时,执行相应的回滚策略;与过滤器、拦截器相比,更加重要的是其适用范围不再局限于SpringMVC项目,可以在任意一层定义一个切点,织入相应的操作,并且还可以改变返回值;

Filter和HandlerInterceptor

之所以没有选择Filter和HandlerInterceptor,而是AOP来实现业务操作日志功能,是因为Filter和HandlerInterceptor自身的一些局限性:

过滤器

过滤器(Filter)是与servlet相关联的一个接口,主要适用于java web项目中,依赖于Servlet容器,是利用java的回调机制来实现过滤拦截来自浏览器端的http请求,可以拦截到访问URL对应的方法的请求和响应(ServletRequest request, ServletResponse response),但是不能对请求和响应信息中的值进行修改;一般用于设置字符编码、鉴权操作等;如果想要做到更细一点的类和方法或者是在非servlet环境中使用,则是做不到的;所以凡是依赖Servlet容器的环境,过滤器都可以使用,如Struts2、SpringMVC;

 

 

拦截器

拦截器的(HandlerInterceptor)使用范围以及功能和过滤器很类似,但是也是有区别的。首先,拦截器(HandlerInterceptor)适用于SpringMVC中,因为HandlerInterceptor接口是SpringMVC相关的一个接口,而实现java Web项目,SpringMVC是目前的首选选项,但不是唯一选项,还有struts2等;因此,如果是非SpingMVC的项目,HandlerInterceptor无法使用的;其次,和过滤器一样,拦截器可以拦截到访问URL对应的方法的请求和响应(ServletRequest request, ServletResponse response),但是不能对请求和响应信息中的值进行修改;一般用于设置字符编码、鉴权操作等;如果想要做到更细一点的类和方法或者是在非servlet环境中使用,则也是是做不到的;

总之,过滤器和拦截器的功能很类似,但是拦截器的适用范围比过滤器更小;

SpringAOP、过滤器、拦截器对比

在匹配中同一目标时,过滤器、拦截器、SpringAOP的执行优先级是:过滤器>拦截器>SpringAOP,执行顺序是先进后出,具体的不同则体现在以下几个方面:

1、作用域不同

  • 过滤器依赖于servlet容器,只能在 servlet容器,web环境下使用,对请求-响应入口处进行过滤拦截;
  • 拦截器依赖于springMVC,可以在SpringMVC项目中使用,而SpringMVC的核心是DispatcherServlet,而DispatcherServlet又属于Servlet的子类,因此作用域和过滤器类似;
  • SpringAOP对作用域没有限制,只要定义好切点,可以在请求-响应的入口层(controller层)拦截处理,也可以在请求的业务处理层(service层)拦截处理;

2、颗粒度的不同

  • 过滤器的控制颗粒度比较粗,只能在doFilter()中对请求和响应进行过虑和拦截处理;
  • 拦截器提供更精细颗粒度的控制,有preHandle()、postHandle()、afterCompletion(),可以在controller对请求处理之前、请求处理后、请求响应完毕织入一些业务操作;
  • SpringAOP,提供了前置通知、后置通知、返回后通知、异常通知、环绕通知,比拦截器更加精细化的颗粒度控制,甚至可以修改返回值;

实现方案

环境配置

jdk版本:1.8开发工具:Intellij iDEA 2020.1

springboot:2.3.9.RELEASE

mybatis-spring-boot-starter:2.1.4

依赖配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

表结构设计

create table if not exists bus_log
(
   id bigint auto_increment comment '自增id'
      primary key,
   bus_name varchar(100) null comment '业务名称',
   bus_descrip varchar(255) null comment '业务操作描述',
   oper_person varchar(100) null comment '操作人',
   oper_time datetime null comment '操作时间',
   ip_from varchar(50) null comment '操作来源ip',
   param_file varchar(255) null comment '操作参数报文文件'
)
comment '业务操作日志' default charset ='utf8';

代码实现

1、定义业务日志注解@BusLog,可以作用在控制器或其他业务类上,用于描述当前类的功能;也可以用于方法上,用于描述当前方法的作用;

2、把业务操作日志注解BusLog标记在PersonController类和方法上; 

3、编写切面类BusLogAop,并使用@BusLog定义切入点,在环绕通知内执行过目标方法后,获取目标类、目标方法上的业务日志注解上的功能名称和功能描述, 把方法的参数报文写入到文件中,最后保存业务操作日志信息;

测试

调试方法

平时后端调试接口,一般都是使用postman,这里给大家安利一款工具,即Intellij IDEA的Test RESTful web service,功能和使用和postman差不多,唯一的好处就是不用在电脑上再额外装个postman,功能入口:工具栏的Tools-->http client-->Test RESTful web service

 

另外还有一种用法,我比较喜欢用这种,简单几句就可以发起一个http请求,还可以一次批量执行;

 

验证结果

总结

业务操作日志记录中包含了用户操作的功能名称、功能描述、操作人、操作时间和操作的参数报文,参数报文之所以选择存储在文件中,是因为正常情况下,是不需要知道具体的参数报文,只有在回滚操作的时候才会用到,可以根据上一次的参数报文逆向操作。

 

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

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

相关文章

[ 应急响应基础篇 ] Windows系统隐藏账户详解(Windows留后门账号)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

Spring Web MVC DispatcherServlet详解—官方原版

一、概述 Spring Web MVC是基于Servlet API构建的原始Web框架&#xff0c;从一开始就包含在Spring框架中。正式名称“SpringWebMVC”来自其源模块&#xff08;Spring-webmvc&#xff09;的名称&#xff0c;但它更常见的名称是“SpringMVC”。 与Spring Web MVC并行&#xff0c…

【AIGC】GitHub Copilot 免费注册及在 PyCharm 中的安装使用

欢迎关注【youcans的 AIGC 学习笔记】原创作品 《GitHub Copilot 免费注册及在 VS Code 中的安装使用》 《GitHub Copilot 免费注册及在 PyCharm 中的安装使用》 GitHub Copilot 免费注册及在 PyCharm 中的安装使用1. GitHub Copilot 功能介绍2. 用户注册与申请2.1 个人订阅 Gi…

经典算法50例-无敌五十剑-算法五十重天

这里写目录标题1.汉诺塔2.费式数列3.巴斯卡三角形4.三色棋5.老鼠走迷官&#xff08;一&#xff09;6.老鼠走迷官&#xff08;二&#xff09;7.骑士走棋盘8.八皇后9.八枚银币10.生命游戏11.字串核对12.双色、三色河内塔13.背包问题14.蒙地卡罗法求 PI15.Eratosthenes筛选求质数1…

LeetCode——遍历序列构造二叉树

105从前序与中序遍历序列构造二叉树 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,15,2…

3.12、生成者消费者模型

3.12、生成者消费者模型1.生产者消费者模型介绍2.一个没有实现线程同步的生产者消费者模型1.生产者消费者模型介绍 生产者消费者模型是一种多线程的设计模式&#xff0c;用于解决生产者和消费者之间的同步和协作问题。 在生产者消费者模型中&#xff0c;生产者和消费者通过共享…

代码随想录算法训练营第五十五天 | 392.判断子序列、115.不同的子序列

打卡第55天。 今日任务 392.判断子序列115.不同的子序列 392.判断子序列 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xf…

哪个品牌的蓝牙耳机便宜耐用?内行公认四大便宜耐用的蓝牙耳机

蓝牙耳机发展至今&#xff0c;品牌众多&#xff0c;且各品牌旗下拥有无数不同价格的耳机&#xff0c;各自的主打优势又不一样。那么&#xff0c;哪个品牌的蓝牙耳机便宜耐用&#xff1f;下面&#xff0c;我来给大家推荐四款便宜耐用的蓝牙耳机&#xff0c;一起来看看吧。 一、…

【数据结构】第九站:树和二叉树

目录 一、树的概念及结构 1.树的概念 2.树的相关概念 3.树的表示 二、二叉树的概念及结构 1.概念 2.特殊的二叉树 3.二叉树的性质 三、二叉树的存储结构 一、树的概念及结构 1.树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个…

Redis缓冲区溢出及解决方案

缓冲区(buffer)&#xff0c;是内存空间的一部分。也就是说&#xff0c;在内存空间中预留了一定的存储空间&#xff0c;这些存储空间用来缓冲输入或输出的数据&#xff0c;这部分预留的空间就叫做缓冲区。 一、Redis缓冲区溢出影响 在Redis中&#xff0c;主要有三个场景用到了…

数据资产目录建设方法

以信息技术为核心的第四次经济革命使得全球经济进入到数字化转型时期&#xff0c;对于今天的企业来说&#xff0c; 数字化转型已经不是可做可不做的自选题&#xff0c; 而是必须付诸行动的必选题。 从数字化转型的实践经验中我们可以得知&#xff0c;企业的数据资产是企业数字…

Flink CDC 在京东的探索与实践

摘要&#xff1a;本文整理自京东资深技术专家韩飞&#xff0c;在 Flink Forward Asia 2022 数据集成专场的分享。本篇内容主要分为四个部分&#xff1a; 京东自研 CDC 介绍京东场景的 Flink CDC 优化业务案例未来规划点击查看直播回放和演讲 PPT 一、京东自研 CDC 介绍 京东自研…

pdf转换成word怎么转换?这个方法一学就会!

在日常工作和生活中&#xff0c;我们常常会遇到需要将PDF文件转换为Word文档的情况。这个过程有时候会令人感到麻烦和心累&#xff0c;需要特殊操作才能完成。但实际上&#xff0c;通过选择正确的方法&#xff0c;文件格式转换只需要几秒钟的时间。如果你感到不可思议&#xff…

ChatGPT-4 来了,附国内体验地址

chatgpt4是什么&#xff1f; 2022年12月&#xff0c;openAI发布了chatgpt模型&#xff0c;这个属于GPT-3.5系列模型中的一个。上个月&#xff0c;openAI又发布了超级升级版的GPT-4模型。所以&#xff0c;你想问的chatgpt4模型是指代GPT-4模型。 相比前一个版本&#xff0c;它…

智能硬件蓝牙配网方案概要

智能硬件开发系列 Google Protobuf 实践使用开发智能硬件蓝牙配网方案概要JNI开发必学C基础JNI开发必学C使用实践Android Studio 4.0.NDK项目开发详细教学Android NDK与JNI的区别有何不同&#xff1f;Android Studio 4.0.NDK .so库生成打包Android JNI的深度进阶学习Android S…

【Leetcode】题库-爽刷简单题(1)

目录 写在前面&#xff1a; 题目&#xff1a;67. 二进制求和 - 力扣&#xff08;Leetcode&#xff09; 解题思路&#xff1a; 代码&#xff1a; 过过过过过过啦&#xff01;&#xff01;&#xff01;&#xff01; 题目&#xff1a;83. 删除排序链表中的重复元素 - 力扣&a…

linux之jdk1.8环境安装与配置和Maven安装与配置

文章目录一、jdk1.8环境安装1、官网下载&#xff1a;<https://www.oracle.com/java/technologies/downloads/#java8>2、在usr文件夹下新建一个java文件夹3、解压完成后&#xff0c;将文件jdk文件传入到java目录下二、配置环境&#xff08;重点&#xff09;1、按 i 进行编…

docker环境下搭建rocketmq集群

rocketmq是一个分布式消息中间件&#xff0c;分布式的意思就是多台机器可以通过网络连接协同工作&#xff0c;因此rocketmq可以运行在多台机器上&#xff0c;以达到超越单机的服务能力。rocketmq的架构图如下所示 我们首先搭建一个最小的rocketmq集群&#xff0c;需要启动一个n…

MySQL安装配置与连接Navicat

本文详细记录win11系统MySQL安装配置与Navicat连接过程&#xff0c;每个知识点都解释了&#xff0c;不止安好了&#xff0c;你还学懂了&#xff01;你不知道选择哪个版本&#xff0c;不知道参数啥意思&#xff0c;不知道哪种安装方式好&#xff1f;这里都有答案&#xff01;&am…

最大二叉树

1题目 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums 构建的 最…