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

操作留痕功能实现与探讨

操作留痕功能实现与探讨

背景

接手了一个单体应用项目,看系统介绍,说实现了【高性能的操作日志留痕】功能,就有点好奇它是怎么设计的,是阻塞队列还是怎样的线程池。结果我打开代码一看,真的是笑洗个人了。它是做了一个接口给前端去调用,代码和多线程一分钱关系都没有,直接是调用到接口,拼装了一下内容就入库了。这玩意哪里高性能了,url远程调用性能高?同步代码高?倒不是说这种方案完全不可取,文末会分析一下这适用于什么场景和优化建议。

最常用操作留痕设计

基于后端去实现操作留痕都会不可避免地对原代码有侵入性,但是我们要想出入侵性最低的方案——基于注解去实现。这么一来我们只需要在方法上加上一个注解和一些参数的设置,就可以完成操作日留痕功能的嵌入了。

操作留痕相对于主业务来说,它并不是重要的部分,所以我们没必要去等待操作留痕功能入库完成后再返回数据。操作留痕对于用户来说是无感的,应该用异步去实现。

编码实现

1.罗列操作留痕需要记录什么信息,哪些信息是可以自动获取的,哪些是要Hard Code的

package org.example.springboot.job.domain;import lombok.Data;import java.util.Date;@Data
public class OptLogRecord {private Long id;    		// 主键private String userName; 	// 操作人员private String userId;		// 用户idprivate String optFunc;     // 菜单功能模块private String menuTitle;    // 具体的菜单private String optButton;     // 按钮private String status;      // 操作结果private Date optTime;       // 操作时间private String optReturn;   // 返回结果}

以上是最基本的操作留痕信息,进阶考虑的话,可以有:请求参数、操作ip、操作地点、请求url、失败后的错误信息等。

其中,功能模块菜单按钮 这些业务类的信息是我们程序中无法区分的。当然,如果你能维护非常完美的方法名与业务信息的匹配枚举的话,那么我们可以通过切点获取方法名再映射出对应的业务信息。嗯,确实不错,就是有点麻烦。在这里我就使用Hard Code的方式去实现了。有需要的可以自己去实现方法名与业务信息的映射关系。

2.创建注解

package org.example.springboot.job.annotation;import java.lang.annotation.*;@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OptLog {String optFunc() default "";	// 功能模块String menuTitle() default "";	// 菜单标题String optButton() default "";	// 按钮}

3.对使用了注解的方法进行切面织入

导入依赖

<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version>
</dependency>

创建切面类

@Aspect
@Component
public class OptLogAspect {}

以下代码内容均为OptLogAspect中的内容,为了方便步骤讲解,拎出来说明

  1. 指明该切面指向的切点为OptLog

        @Pointcut("@annotation(org.example.springboot.job.annotation.OptLog)")public void optLogPointCut() {}
    
  2. 我们需要在使用注解的方法执行完成之后再记录他操作的信息

        // 这个result是使用了注解的方法的返回值@AfterReturning(pointcut = "optLogPointCut()", returning = "result")public void doAfterReturning(JoinPoint joinPoint, Object result) {handleOptLog(joinPoint, result, "SUCCESS");}
    

    这个handleOptLog方法还没实现,别急

  3. 如果出现了异常呢,那肯定是操作失败了,我们也要记录操作失败的信息

        @AfterThrowing(value = "optLogPointCut()")public void doAfterThrowing (final JoinPoint joinPoint) {handleOptLog(joinPoint, null, "FAILED");}
    
  4. 实现handleOptLog方法

        protected void handleOptLog(final JoinPoint joinPoint, Object result, String status) {MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();OptLog optLog = methodSignature == null ? null : methodSignature.getMethod().getAnnotation(OptLog.class);if (optLog == null) return;// TODO:获取当前用户 根据自己系统方式去获取用户OptLogRecord record = new OptLogRecord();// TODO: 设置用户名与用户id略过record.setStatus(status);    // 根据不同的切面来区分是否操作成功record.setOptReturn(result.toString());record.setOptTime(new Date());// 读取使用注解时的参数record.setOptFunc(optLog.optFunc());record.setMenuTitle(optLog.menuTitle());record.setOptButton(optLog.optButton());// 异步保存数据库TimerTask task = new TimerTask() {@Overridepublic void run() {// insert语句保存到数据库System.out.println("insert:" + record.toString());}};ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();executorService.schedule(task, 10, TimeUnit.MILLISECONDS);}
    

    这里的异步日志是使用定时任务线程去完成,延时10ms执行,不影响原本的方法执行效率。

注解使用示范

    @GetMapping("/test")@OptLog(optFunc = "系统管理", menuTitle = "菜单管理", optButton = "添加菜单")public String testCall() throws InterruptedException {Thread.sleep(1000);log.info("hello");AtomicInteger integer = new AtomicInteger();return "test";}

睡眠1秒模拟非常复杂的业务执行时间,测试结果如下

在这里插入图片描述

总结

到此该操作留痕功能基本已经实现完成,有些地方还需要继续优化和规范化。比如使用枚举、常量去规范一些Hard Code。

回到上面的问题,这种通过调用接口去实现操作留痕的方案,适用于对后端业务无法切入的情况。比如你开发的是一款具备身份权限校验等功能的快速框架,别人通过调用你的jar包即可改造自己已有的系统。为了方便别人的开发,不对已有代码进行过多的改造,那就只能通过这种调接口的方式实现操作留痕。

前端基于axios的拦截器,对发起的请求进行拦截,将操作记录信息通过接口调用的方式保存。这种方案的最大缺点就是对于大多数的业务场景都需要多进行一次http请求,这种性能开销不可忽视。如果说前端对操作留痕的http请求使用异步,那么日志留痕的可靠性也会降低不少,但随之提升的性能也会非常多。

当http请求到达后端时,后端采用异步入库,也可以提升不少的性能,但前端就无法得知操作留痕是否完成。

相关文章:

操作留痕功能实现与探讨

操作留痕功能实现与探讨 背景 接手了一个单体应用项目&#xff0c;看系统介绍&#xff0c;说实现了【高性能的操作日志留痕】功能&#xff0c;就有点好奇它是怎么设计的&#xff0c;是阻塞队列还是怎样的线程池。结果我打开代码一看&#xff0c;真的是笑洗个人了。它是做了一…...

深入浅出消息队列MSMQ

消息队列MSMQ&#xff0c;相信稍有开发经验的小伙伴都了解一些。开始讲解之前&#xff0c;我们先弄清楚一件事&#xff0c;为什么我们要使用MSMQ&#xff1a; 您可能认为您能够通过一个简单的数据库表(一个应用程序往其中写入数据&#xff0c;另一个应用程序从中读取数据)来应用…...

Maven多模块开发

POM主要功能 maven学习教程很多&#xff0c;就不在赘述可以参考以下网站&#xff0c;这里只说明maven实际运用。 https://blog.csdn.net/xwh3165037789/article/details/121545762 菜鸟教程 Maven POM POM是在使用Maven构建项目最重要的部分&#xff0c; POM 中所有信息位于&l…...

QT之OpenGL帧缓冲

QT之OpenGL帧缓冲1. 概述1.1 帧缓冲的创建与删除1.2 帧缓冲的数据来源1.2.1 数据源与帧缓冲的关系1.2.2 纹理Attachment1.2.3 渲染缓冲对象Attachment1.2.4 两者的区别1.2.5 关于两者的使用场景2. Demo3. 后期处理4. 参考1. 概述 OpenGL管线的最终渲染目的地被称作帧缓冲(fram…...

$ 6 :选择、循环

if-else语句 #include <stdio.h> //判断输入值是否大于0 int main() {int i;while (scanf("%d",&i)){if (i > 0)//不要在括号后加分号{printf("i is bigger than O\n");}else {printf("i is not bigger than O\n");}}return O; } …...

【项目设计】高并发内存池 (四)[pagecache实现]

&#x1f387;C学习历程&#xff1a;入门 博客主页&#xff1a;一起去看日落吗持续分享博主的C学习历程博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 也许你现在做的事情&#xff0c;暂时看不到成果&#xff0c;但不要忘记&…...

玩转qsort——“C”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容还是我们的深度剖析指针呀&#xff0c;上篇博客我们学习了回调函数这个知识点&#xff0c;但是没有写完&#xff0c;因为&#xff1a;小雅兰觉得qsort值得单独写出来&#xff01;&#xff01;&#xff01;好啦&#xff0c;就…...

【干货】又是一年跳槽季!Nginx 10道核心面试题及解析

Nginx是一款轻量级的高性能Web服务器和反向代理服务器&#xff0c;由俄罗斯的Igor Sysoev开发。它具有占用资源少、高并发、稳定性高等优点&#xff0c;被广泛应用于互联网领域。在Nginx的面试过程中&#xff0c;面试官通常会提出一些核心问题&#xff0c;本文将介绍一些常见的…...

【线程安全的HashMap有哪些,CurrentHashMap底层是怎么实现线程安全的】

在 Java 中&#xff0c;线程安全的 HashMap 通常有以下几种实现&#xff1a; Collections.synchronizedMap 方法&#xff1a;该方法可以将 HashMap 转换为线程安全的 Map。 Hashtable 类&#xff1a;Hashtable 是一种线程安全的集合类&#xff0c;它与 HashMap 类似&#xff0…...

C语言-结构体【详解】

一、 结构体的基础知识 结构是一些值的集合&#xff0c;这些值称为成员变量结构的每个成员可以是不同类型的变量 &#xff08;1&#xff09;结构体的声明 写法一&#xff1a; 注&#xff1a; 括号后边的分号不能忘结构体末尾可以不创建变量&#xff0c;在主函数中再创建 struc…...

浏览器输入url到页面渲染完成经历了哪些步骤

一、URL解析 这一步比较容易理解&#xff0c;在浏览器地址栏输入url后&#xff0c;浏览器会判断这个url的合法性 &#xff0c;以及是否有可用缓存&#xff0c;如果判断是 url 则进行域名解析&#xff0c;如果不是 url &#xff0c;则直接使用搜索引擎搜索 二、域名解析 输入…...

大数据技术之Hadoop(Yarn)

第1章Yarn资源调度器思考&#xff1a;1&#xff09;如何管理集群资源&#xff1f;2&#xff09;如何给任务合理分配资源&#xff1f;Yarn是一个资源调度平台&#xff0c;负责为运算程序提供服务器运算资源&#xff0c;相当于一个分布式的操作系统平台&#xff0c;而MapReduce等…...

5.建造者模式

目录 简介 四个角色 应用场景 实现步骤 和工厂模式的区别 简介 建造者模式也叫生成器模式&#xff0c;是一种对象构建模式&#xff1b;它可以把复杂对象的建造过程抽象出来(抽象类别)&#xff0c;使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象&#xff1b;…...

数据库基础-数据库基本概念(1-1)

你好&#xff0c;欢迎来到数据库基础系列专栏&#xff0c;欢迎留言互动哦~ 目录一、数据库基础1. 数据库基本概念1.1 数据库1.2 什么是数据库管理软件1.3 表1.4 行1.5 列和数据类型1.6 主键1.7 什么是 SQL一、数据库基础 1. 数据库基本概念 1.1 数据库 数据库是一个以某种有…...

学习笔记-架构的演进之服务容错策略-服务发现-3月day01

文章目录前言服务容错容错策略附前言 “容错性设计”&#xff08;Design for Failure&#xff09;是微服务的一个核心原则。 使用微服务架构&#xff0c;拆分出的服务越来越多&#xff0c;也逐渐导致以下问题&#xff1a; 某一个服务的崩溃&#xff0c;会导致所有用到这个服务…...

采编式AIGC视频生产流程编排实践

作者 | 百度人工智能创作团队 导读 本文从业务出发&#xff0c;系统介绍了采编式 TTV的实现逻辑和实现路径。结合业务拆解&#xff0c;实现了一个轻量级服务编排引擎&#xff0c;有效实现业务诉求、高效支持业务扩展。 全文6451字&#xff0c;预计阅读时间17分钟。 01 背景 近…...

Leetcode23. 合并k个升序链表

一、题目描述&#xff1a; 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 示例 1&#xff1a; 输入&#xff1a;lists [[1,4,5],[1,3,4],[2,6]]输出&#xff1a;[1,1,2,3,4,4,5,6]解释&#…...

从用户出发,互联网产品策划方法论

【一】从用户到需求 产品经理需要具备两个非常重要的技能,一个叫策划,一个叫感知用户。 我们在分析问题的时候往往会说“这么做,我认为用户会怎么怎么样”、“用户会认为这样很不爽”,当我们这样说时,很有可能是把自己当成了用户,用某些特定的情感或记忆代表了用户。 当我…...

STM32 E18-D80NK红外检测

本文代码使用 HAL 库。 文章目录前言一、E18-D80NK 红外传感器&#xff1a;1. E18-D80NK 的介绍2. 电器特性二、红外检测小实验代码讲解三、实验现象总结前言 这篇文章介绍 如何使用 STM32 控制 E18-D80NK 进行红外检测。 一、E18-D80NK 红外传感器&#xff1a; 1. E18-D80N…...

Linux常用命令--进程和计划任务管理

一、程序和进程的关系 1、程序 ①保存在硬盘、光盘等介质中的可执行代码和数据 ②静态保存的代码 2、进程 ①在cpu及内存中运行及进程代码 ②动态执行的代码 ③父&#xff08;fork&#xff09;、子进程&#xff0c;每个程序可以创建一个或多个进程 父进程和子进程的区别&am…...

Unity TextMeshPro

Unity TextMeshPro 简介 TextMeshPro(也简称为TMP)号称是Unity的终极文本解决方案,它是Unity 的 UI 文本和旧版文本网格体的完美替代品。 功能强大且易于使用,使用高级文本渲染技术以及一组自定义着色器;提供实质性的视觉质量改进,同时在文本样式和纹理方面为用户提供令人…...

虹科分享| 浅谈HK-Edgility边缘计算平台

上周&#xff0c;我们推出了虹科新品HK-Edgility边缘计算平台以及uCPE解决方案。本篇文章我们再来谈一谈到底什么是边缘计算&#xff1f;为什么需要边缘计算&#xff1f;边缘计算和云计算有什么关系&#xff1f;HK-Edgility边缘计算平台将为您带来什么&#xff1f;一、边缘计算…...

React Router v6详解

旧版本React Router使用方式 BrowserRouter&#xff1a;通过 history 库&#xff0c;传递 history 对象&#xff0c;location 对象Switch&#xff1a;匹配唯一的路由 Route&#xff0c;展示正确的路由组件Route&#xff1a;视图承载容器&#xff0c;控制渲染 UI 组件 新版本R…...

帮助100w人成功入职的软件测试面试常见问题以及答案

测试面试题怎么来设计测试方案根据测试需求&#xff08;包括功能需求和非功能性需求&#xff09;&#xff0c;识别测试要点&#xff0c;识别测试环境要求&#xff0c;安排测试轮次&#xff0c;根据项目计划和开发计划做整体的测试安排。被测试的特性&#xff1a;通过对需求规格…...

tensorflow2.4--2.回归问题分析

文章目录前言流程案例操作前言 流程 回归问题预测连续值,在某个区间内变动. 常见的线性回归问题模型是yaxb,然而现实世界由于大量的数据偏差以及复杂度,同时还有大量的噪声,往往达不到如此的精确解,实际解决问题时需要考虑噪声的存在 对于噪声,往往我们已经假设了它符合高斯…...

【2023】DevOps、SRE、运维开发面试宝典之Kafka相关面试题

文章目录 1、消息队列的流派2、kafka的优势3、Kafka与Zookeeper的关系4、Kafka消息队列各组件概念5、Kafka消息队列应用场景6、Kafka消息收发的过程7、Kafka消息数据存储概念8、kafka消息的偏移量概念原理9、Kafka消息数据的顺序消费概念原理10、Kafka单播消费消息的原理11、Ka…...

CentOS系统编译安装PHP-5.6.27版本

一、手动安装编译工具&#xff1a; yum install -y gcc gcc-c 二、添加用户和用户组&#xff1a; groupadd web useradd -M -s /sbin/nologin -g web php 三、yum安装依赖&#xff1a; yum -y install libmcrypt libmcrypt-devel mcrypt mhash libxml2-devel libpng-devel l…...

和风SDK查询城市ID(保姆级教程)

android studio版本&#xff1a;2021.2.1例程名&#xff1a;hfserachcityid这几天没什么事做&#xff0c;而且我原来那个“项目”因为免费api不能用了&#xff0c;只能改为和风的免费api,但需要申请&#xff0c;而且还要城市ID&#xff0c;玩天气的基本都知道城市ID这个东西&am…...

暴力递归到动态规划

暴力递归到动态规划 假设有排成一行的n个位置&#xff0c; 记为1~n&#xff0c;n-定大于或等于2。开始时机器人在其中的m位置上(m 一定是1~n中的一个)。如果机器人来到1位置&#xff0c;那么下一步只能往右来到2位置&#xff1b;如果机器人来到n位置&#xff0c; 那么下一步只能…...

Java:Java仍然处于领先地位?

没有多少编程语言能够自吹自擂并持续流行20多年&#xff0c;但Java就是其中之一。Java应用程序不仅局限于web和移动开发&#xff0c;而且给大数据和人工智能留下了深刻的印象。不用多说&#xff0c;让我们讨论一下Java流行的几个原因!!1.实用性根据JamesGosling的说法&#xff…...

广东省城乡住房建设厅网站首页/月饼营销软文

1、首先进入组件服务&#xff0c;查看组件服务/计算机/我的电脑/COM应用程序&#xff0c;结果报错“COM 无法与 Microsoft 分布式事务协调程序交谈”&#xff0c;无法查看里面的对象。 2、进入事件查看器&#xff0c;发现msdtc服务没有正常启动。 3、删除注册表中的键&#xff…...

禁止指定ip访问网站/开一个网站需要多少钱

LinuxShell col命令 Linux col命令用于过滤控制字符。 在许多UNIX说明文件里&#xff0c;都有RLF控制字符。当我们运用shell特殊字符">“和”>>"&#xff0c;把说明文件的内容输出成纯文本文件时&#xff0c;控制字符会变成乱码&#xff0c;col指令则能有…...

wordpress导入error 500/成人大专

在有些情况下死锁是可以避免的。本文将展示三种用于避免死锁的技术&#xff1a; 加锁顺序加锁时限死锁检测加锁顺序 当多个线程需要相同的一些锁&#xff0c;但是按照不同的顺序加锁&#xff0c;死锁就很容易发生。 如果能确保所有的线程都是按照相同的顺序获得锁&#xff0c;那…...

wordpress精简化教程/seo网站关键词优化方式

问题 1&#xff1a;C 中的类可以定义多个对象&#xff0c;那么对象构造的顺序是怎样的&#xff1f; 问题 2&#xff1a;对象构造顺序会带来什么影响呢&#xff1f; 对象构造往往与构造函数相关联&#xff0c;构造函数体有可能是非常复杂的程序逻辑组成&#xff0c;不同类的构造…...

html编辑器中文版/搜索引擎优化方法总结

如图所示&#xff1a;打开file-->setting-->Editor-->General&#xff0c;搜索show&#xff0c;然后勾选上Show quick documentation on mouse move(将信息在鼠标移动到方法上时进行提示)转载于:https://www.cnblogs.com/alisande/p/10713388.html...

刚开始的网站开发公司/网站如何快速收录

hadoop是用Java语言实现的开源软件框架&#xff0c;可以支持多种语言&#xff0c;我学习的时候用得自然就是Java了。 在开始编程之前需要做一些配置工作&#xff1a; Hadoop开发&#xff1a;Hadoop为HDFS和Mapreduce提供了基础的支持&#xff0c;叫hadoop common。Hadoop有一个…...