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

Spring Data Envers 数据审计实战2 - 自定义监听程序扩展审计字段及字段值

上篇讲述了如何在Spring项目中集成Spring Data Envers做数据审计和历史版本查看功能。

之前演示的是业务表中已有的字段进行审计,那么如果我们想扩展审计字段呢?

比如目前对员工表加入了@Audited审计,员工表有个字段为dept_id,为了页面展示更人性化,我想把dept_id关联的部门名称(当时的快照值)也存入审计版本中,这样的话,在查看员工信息修改历史的时候,就可以看到当时员工对应的部门名称了。

我们看看如何把引用的快照信息保存到审计版本记录中,经过对spring data envers (基于hibernate envers)的源码阅读,发现目前没有可用手段能将额外的自定义审计信息保存到业务表对应的_aud审计表_aud表保存的字段比较固定,就是业务表中被审计的字段 + 审计基础字段(rev,revtype, revend, revend_tstmp, 分别为:审计版本号、操作类型【增删改】、审计下一个版本号、操作时间戳)。

那么就只能寄希望于审计实体表(revinfo)了,还好hibernate envers给我们留了口子去扩展这个表。

1. 自定义审计实体类,表名可以用revinfo也可以用其他的,必须要有审计版本/id和操作时间戳两个字段,可以自己加入新的字段(如下列代码中的extInfo字段)。

@Entity(name = "revinfo") //审计实体表名
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@RevisionEntity(MyRevisionListener.class) //自定义的监听(可处理扩展字段保存值)
public class MyRevisionEntity {private static final long serialVersionUID = 1L;@Id@GeneratedValue@RevisionNumber@Column(name = "rev")private int revNumb; //审计版本号 必要@RevisionTimestamp@Column(name = "revtstmp")private long timestamp; //审计时间 必要@Column(name = "ext", length = 1000)private String extInfo; //扩展字段
}

2. 我们看到上面还指定了一个监听类,没错,我们接下来就要创建这个类,并在这个类中定义当保存审计信息时我们要在扩展字段去插入什么值。

网上很多是实现RevisionListener接口,这里我建议实现EntityTrackingRevisionListener接口,它比RevisionListener更强大,多了entityChanged方法,可以帮助我们处理更多自定义的业务,且不污染业务审计表。

@Slf4j
public class MyRevisionListener implements EntityTrackingRevisionListener {@Overridepublic void newRevision(Object revisionEntity) {//这里可以自行设置业务表中被审计的字段保存何值到DB _aud表,字段类型需要与业务表中定义的一致,一般为了保持数据一致性,这里不做处理}@Overridepublic void entityChanged(Class entityClass, String entityName, Object entityId, RevisionType revisionType, Object revisionEntity) {//我们扩展额外的字段及字段值主要是重写这个方法......}
}

3. 那么我们如何控制在save员工信息的时候,将员工部门名称快照保存到审计实体表(revinfo)呢?

首先,你需要通过一些辅助方式将员工表和部门表关联起来,如果你们配置了@ManyToOne这类注解的话,可以读取注解进行操作。如果没有的话,建议自定义注解,简单配置关联关系即可。

我这里自定义了一个注解@AuditedExtInfo,可以配置被审计的字段需要保存什么值到revinfo表:

@AuditedExtInfo(referenceClass = Dept.class, displayField = "name") //自定义注解配置dept_id对应的是哪个实体类、以及保存哪个字段的快照值
@Column(name = "dept_id", length = 50)
private String deptId;

然后,在监听程序中,我们通过反射获取到deptId关联的部门对象的名称,进行保存:

    @SneakyThrows@Overridepublic void entityChanged(Class entityClass, String entityName, Object entityId, RevisionType revisionType, Object revisionEntity) {//将审计实体对象转换为自定义的审计实体类的对象MyRevisionEntityMyRevisionEntity myRevisionEntity = (MyRevisionEntity) revisionEntity;//获取Spring Data JPA的Repository (方便获取实体对象及关联的对象信息)//ApplicationContextHelper.getContext()这个是返回Spring的ApplicationContext的静态方法Repositories repositories = new Repositories(ApplicationContextHelper.getContext());//先获取到被审计的业务实体表对象,例如:我们需要找到此次save操作对应的员工信息,从而找到deptIdObject entityRepository = repositories.getRepositoryFor(entityClass).orElseThrow(() -> new RuntimeException("Not found entityRepository"));Object entity = ((Optional) MethodUtils.invokeMethod(entityRepository, "findById", entityId)).orElse(null);//遍历业务实体表的字段列表,找到注解字段信息Field[] fields = entityClass.getDeclaredFields();for (Field field : fields) {AuditedExtInfo conversion = field.getDeclaredAnnotation(AuditedExtInfo.class);if (Objects.isNull(conversion)) {//如果没有定义@AuditedExtInfo注解,则忽略此字段continue;}//找到了注解,获取该字段的值,然后用该字段的值(deptId)去查部门表的Repository的findById方法,找到部门对象String fieldValue = String.valueOf(FieldUtils.readDeclaredField(entity, field.getName(), true));Object referenceRepository = repositories.getRepositoryFor(conversion.referenceClass()).orElseThrow(() -> new RuntimeException("Not found referenceRepository"));Object referenceObj = ((Optional) MethodUtils.invokeMethod(referenceRepository, "findById", fieldValue)).orElse(null);//获取引用对象的相应字段的值,进行保存。如部门对象的name值String extInfo = String.valueOf(FieldUtils.readDeclaredField(referenceObj, conversion.displayField(), true));//如果此业务实体表要扩展多个字段的引用快照值,建议在myRevisionEntity的ext字段保存一个JSON或Map,或者定义多个字段 如ext1、ext2、ext3...myRevisionEntity.setExt(extInfo);break;}}

借助Hibernate envers预留的监听接口扩展自己的监听类,以及反射操作实体对象和JPA等手段,可以在Spring Data JPA进行save操作时,保存我们额外的审计字段及字段值。

相关文章:

Spring Data Envers 数据审计实战2 - 自定义监听程序扩展审计字段及字段值

上篇讲述了如何在Spring项目中集成Spring Data Envers做数据审计和历史版本查看功能。 之前演示的是业务表中已有的字段进行审计,那么如果我们想扩展审计字段呢? 比如目前对员工表加入了Audited审计,员工表有个字段为dept_id,为…...

一个 SpringBoot 项目能同时处理多少请求?

目录 1 问题分析 2 Demo 3 答案 4 怎么来的? 5 标准答案及影响参数一Tomcat配置 6 影响参数二 Web容器 7 影响参数三 Async 1 问题分析 一个 SpringBoot 项目能同时处理多少请求? 不知道你听到这个问题之后的第一反应是什么? 我大概…...

计算机网络——网络

计算机网络——网络 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU)前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家, [跳转到网站](https://www.captainbed.cn/qianqiu) 无线网络和移动网…...

C语言探索:选择排序的实现与解读

当我们需要对一组数据进行排序时,选择排序(Selection Sort)是一种简单但效率较低的排序算法。它的基本思想是每次从未排序的数据中选择最小(或最大)的元素,然后将其放置在已排序序列的末尾。通过重复这个过…...

Golang 学习(二)进阶使用

二、进阶使用 性能提升——协程 GoRoutine go f();一个 Go 线程上,可以起多个协程(有独立的栈空间、共享程序堆空间、调度由用户控制)主线程是一个物理线程,直接作用在 cpu 上的。是重量级的,非常耗费 cpu 资源。协…...

ubuntu22.04@laptop OpenCV定制化安装

ubuntu22.04laptop OpenCV定制化安装 1. 源由2. 默认配置3. 定制配置4. 定制安装5. 定制OpenCV-4.9.05.1 修改opencv.conf5.2 加载so文件5.3 修改bash环境变量5.4 增加pkgconfig5.5 检查OpenCV-4.9.0安装 6. 总结7. 参考资料 1. 源由 目前,能Google到的代码层次不齐…...

linux系统非关系型数据库redis

redis 介绍redis的特点:缓存 安装安装单机版redisredis的相关工具 介绍 redis是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库 redis的官网:redis.ioredis的特点: 丰富的数据结构 支持持久化 支持事务 支持主从缓存 类型 …...

【LeetCode: 292. Nim 游戏+ 博弈问题】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…...

Android 9.0 禁用adb reboot recovery命令实现正常重启功能

1.前言 在9.0的系统rom定制化开发中,在定制recovery模块的时候,由于产品开发需要要求禁用recovery的相关功能,比如在通过adb命令的 adb reboot recovery的方式进入recovery也需要实现禁用,所以就需要了解相关进入recovery流程来禁用该功能 2.禁用adb reboot recovery命…...

分析网站架构:浏览器插件

一、Wappalyzer 1.1 介绍 Wappalyzer 是一款用于识别网站所使用技术栈的浏览器插件。它能够分析正在浏览的网页,检测出网站所使用的各种技术和框架,如内容管理系统(CMS)、JavaScript库、Web服务器等。用户只需安装 Wappalyzer 插…...

CentOS7搭建Hadoop集群

准备工作 1、准备三台虚拟机,参考:CentOS7集群环境搭建(3台)-CSDN博客 2、配置虚拟机之间免密登录,参考:CentOS7集群配置免密登录-CSDN博客 3、虚拟机分别安装jdk,参考:CentOS7集…...

10.0 Zookeeper 权限控制 ACL

zookeeper 的 ACL(Access Control List,访问控制表)权限在生产环境是特别重要的,所以本章节特别介绍一下。 ACL 权限可以针对节点设置相关读写等权限,保障数据安全性。 permissions 可以指定不同的权限范围及角色。 …...

容器化技术基础概念:雪花服务器与凤凰服务器

雪花服务器与凤凰服务器:两种软件部署领域的基础设施对比 在软件部署领域,服务器管理在正常运行时间、效率和安全性方面发挥着关键作用。存在两种截然不同的方法:雪花服务器和凤凰服务器。了解它们之间的区别将帮助您选择最适合您需求的策略…...

解决maven 在IDEA 下载依赖包速度慢的问题

1.idea界面双击shift键 2.打开setting.xml文件 复制粘贴 <?xml version"1.0" encoding"UTF-8"?> <settings xmlns"http://maven.apache.org/SETTINGS/1.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:sc…...

用python编写爬虫,爬取二手车信息+实验报告

题目 报告要求 工程报告链接放在这里 https://download.csdn.net/download/Samature/88805518使用 1.安装jupyter notebook 2.用jupyter notebook打开工程里的ipynb文件&#xff0c;再run all就行 注意事项 可能遇到的bug 暂无&#xff0c;有的话私信我...

代码随想录算法训练营第二十九天|491.非递减子序列、46.全排列、47.全排列II

491.非递减子序列 思路&#xff1a;这道题最开始的时候&#xff0c;我想到两个问题&#xff1a;一个是如何维持递增的序列&#xff0c;一个是如何去重&#xff0c;写了一版代码&#xff0c;用的前面的去重方法&#xff0c;但是遇到一个case始终过不了&#xff0c;[1,2,3,4,5,6,…...

(2)(2.14) SPL Satellite Telemetry

文章目录 前言 1 本地 Wi-Fi&#xff08;费用&#xff1a;30 美元以上&#xff0c;范围&#xff1a;室内&#xff09; 2 蜂窝电话&#xff08;费用&#xff1a;100 美元以上&#xff0c;范围&#xff1a;蜂窝电话覆盖区域&#xff09; 3 手机卫星&#xff08;费用&#xff…...

OTG -- STM32 OTG驱动代码下载及简述(三)

目录 前沿 1 STM32 OTG标准库的获取 2 设备模式代码匹配开发板 2.1 OTG FS全速代码修改 2.2 OTG HS代码修改 2.2.1 OTG HS外部高速PHY运行在高速模式代码修改 2.2.2 OTG HS外部高速PHY运行在全速模式代码修改 2.2.3 OTG HS内部全速PHY运行在全速模式代码修改 前沿 前面…...

STM32F407 CAN参数配置 500Kbps

本篇CAN参数适用 芯片型号&#xff1a;STM32F407xx系统时钟&#xff1a;168MHz&#xff0c;CAN挂载总线APB1为42M波 特 率 &#xff1a;500Kpbs引脚使用&#xff1a;TX_PB9&#xff0c;RX_PB8&#xff1b;修改为PA11PA12后&#xff0c;参数不变。 步骤一、打勾开启CAN&#xf…...

python常用的深度学习框架

目录 一&#xff1a;介绍 二&#xff1a;使用 Python中有几个非常受欢迎的深度学习框架&#xff0c;它们提供了构建和训练神经网络所需的各种工具和库。以下是一些最常用的Python深度学习框架&#xff1a; 一&#xff1a;介绍 TensorFlow&#xff1a;由Google开发的TensorF…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...