JaVers:自动化数据审计

news/2024/5/9 0:36:32/文章来源:https://blog.csdn.net/allway2/article/details/128100762

在开发应用程序时,我们经常需要存储有关数据如何随时间变化的信息。此信息可用于更轻松地调试应用程序并满足设计要求。在本文中,我们将讨论 JaVers 工具,该工具允许您通过记录数据库实体状态的更改来自动执行此过程。

Javers如何工作?

库的操作基于以 JSON 格式在专用表中存储有关业务数据实体的信息。JaVers允许您将这些信息存储在MongoDB,H2,PostgreSQL,MySQL,MariaDB,Oracle和Microsoft SQL Server等数据库中。

使用MongoDB时,JaVers会创建两个集合来存储审计数据:

  • jv_head_id– 用于存储包含commitId 最后一个值的文档的集合
  • jv_snapshots– 此集合包含有关由于创建、更新或删除操作而对业务实体所做的更改的详细信息。

另一方面,如果您决定使用其中一个关系数据库,JaVers 将创建以下表:

  • jv_global_id– 用于存储每个更改的唯一标识符的表
  • jv_commit – 包含有关数据修改的时间和作者信息的表
  • jv_commit_property – 一个附加表,允许您存储前一个表中数据的其他信息,例如用户的标识符和用户名。ID 和作为更改作者的用户的名称
  • jv_snapshot– 此表存储有关实体的哪些属性因给定操作而更改的信息,以及每个属性的值。

为了提供适当的算法来比较不同版本的对象,JaVers 对几种数据类型进行操作:实体、值对象、容器基元。

为每个类指示适当的数据类型,可以通过 3 种方式完成:

  • 明确地 – 使用寄存器...() 方法或对所选类添加适当的注释
  • 隐式 – 依靠 JaVers 根据类层次结构自动检测给定类的类型
  • 默认值 – 将所有类视为 ValueObjects

值得注意的是,JaVers 默认映射来自javax.persistence包的注解,这使得在实现我们的数据库实体时无需添加额外的注解。

实现

要开始使用 JaVers 工具,我们需要向项目添加适当的依赖项。根据我们将在其中存储审计数据的数据库,我们有两个选项可供选择:


  • https://mvnrepository.com/artifact/org.javers/javers-spring-boot-starter-sql
  • https://mvnrepository.com/artifact/org.javers/javers-spring-boot-starter-mongo

在本文中,我们将使用 PostgreSQL 数据库,因此我们在 pom 文件中包含以下依赖项:

<dependency> <groupId>org.javers</groupId> <artifactId>javers-spring-boot-starter-sql</artifactId> <version>6.6.3</version> 
</dependency>

库的工作方式将以应用程序为例呈现,用于存储有关公司正在进行的项目的信息。我们应用程序的数据库实体的结构和实现如下:

Project.java

@Entity
public class Project {@Id@GeneratedValueprivate UUID id;@NotNullprivate String name;@NotNull@Embeddedprivate ProjectDetails details;@OneToMany(mappedBy = "project")private List&lt;Member&gt; members = new ArrayList&lt;&gt;();@Builder@AllArgsConstructor@NoArgsConstructor@Embeddablepublic static class ProjectDetails {@NotNullprivate LocalDateTime startTime;@NotNullprivate LocalDateTime endTime;}
}

Member.java

@Entity
public class Member {@Id@GeneratedValueprivate UUID id;@NotNullprivate String name;@NotNullprivate String surname;@NotNullprivate String role;@ManyToOne@JoinColumn(name = "project_id")private Project project;
}

在数据库中,我们应该有以下可用的表列表:

数据审计

要指示哪些业务数据应该接受审计机制,我们可以使用三种方式。

第一种是用@JaversSpringDataAuditable注释标记所选实体的存储库。添加此注释后,调用任何方法来修改此存储库上的数据将导致有关此操作的信息放置在其中一个 JaVers 表中。

在我们的应用程序中,我们只会将注释添加到Project类存储库中,如下所示:

    @Repository@JaversSpringDataAuditablepublic interface ProjectRepository extends JpaRepository&lt;Project, UUID&gt; {}@Repositorypublic interface MemberRepository extends JpaRepository&lt;Member, UUID&gt; {}
第二种方法,允许我们调用数据的审计机制,是使用@JaversAuditable注释,我们可以在所选方法上方添加注释来修改数据。此类解决方案的示例如下所示:

服务层方法

    @JaversAuditablepublic void save(Project project) {//save project
}

存储库层方法

@Override
@JaversAuditable
S extends Project> S save(S entity);

我们可以保存审计数据的最后一种方法是在Javers类的对象上调用commit方法,我们可以使用依赖注入机制使用它。实际显示此解决方案的代码片段如下所示:

@RequiredArgsConstructor
public class ProjectService {private final Javers javers;public void commitProject() {Project project = new Project();//for simplicity ommited passing parametersjavers.commit("author", project);}
}

作者提供程序配置

在实践中使用这些方法之前,我们仍然需要指定谁是记录的审计数据的作者。下面显示了用于确定此信息的基本配置示例。

 @Configuration
public class JaversAuthorConfiguration {@Beanpublic AuthorProvider provideJaversAuthor() {return new SimpleAuthorProvider();}private static class SimpleAuthorProvider implements AuthorProvider {@Overridepublic String provide() {return "Freddie Mercury";}}
}

在实践中审计数据

为了在实践中验证所讨论的机制,调用了插入和修改数据方法,从而生成了INITIALUPDATE类型的审计数据。调用每个方法的结果如下所示:

添加新数据

插入新业务数据的方法:

    public void save() {Project.ProjectDetails projectDetails = Project.ProjectDetails.builder().startTime(LocalDateTime.now()).endTime(LocalDateTime.now().plusDays(14)).build();Project project = Project.builder().name("Project 1").details(projectDetails).build();Member member = Member.builder().name("Brian").surname("May").role("guitarist").project(project).build();project.getMembers().add(member);projectRepository.saveAndFlush(project);
}

调用上述方法的结果是在jv_snapshot表中生成的以下条目:

值得注意的是,尽管仅在项目实体存储库上添加了@JaversSpringDataAuditable注释,但成员实体数据也已写入。

默认情况下,JaVers 包括属于审核实体的所有嵌套模型。我们可以通过在要从审计机制中省略的字段上添加@DiffIgnore注释来更改此行为。

在我们的例子中,这个注释的使用如下所示:

@DiffIgnore@Builder.Default@OneToMany(mappedBy = "project", cascade = CascadeType.ALL)
private List<Member> members = new ArrayLis<>();

修改现有数据

反过来,修改以前插入的数据的方法是:

   public void update(UUID uuid) {Project project = projectRepository.getById(uuid);project.setName("Live Aid");projectRepository.saveAndFlush(project);
}

但是,调用上述方法会导致生成其他条目,如下表所示:

下载审核数据

由于库提供的API,存储的审计数据可以从存储库中检索,称为JaVers查询语言(link:JQL (JaVers Query Language) examples — JaVers Documentation)。可用方法返回的数据可以以以下三种形式之一呈现:

  • 影子 – 包含域对象的历史数据,这些数据是从快照(快照)重新创建的
  • 更改 – 表示两个对象属性之间的差异
  • 快照 – 包含域对象的历史数据,表示为具有值的属性映射

以下是以所讨论的每种形式返回数据的代码片段。此外,在每个代码段下,还显示了调用该方法后返回的数据示例。

影子查询

查询:

 public String getShadow() {JqlQuery query = QueryBuilder.byClass(Project.class).build();List&lt;Shadow&lt;Object&gt;&gt; shadows = javers.findShadows(query);return javers.getJsonConverter().toJson(shadows);
}
响应:
  [{"commitMetadata": {"author": "Freddie Mercury","properties": [],"commitDate": "2022-05-03T20:02:27.554","commitDateInstant": "2022-05-03T18:02:27.554689400Z","id": 2.00},"it": {"id": "37bfc44c-ab29-44b5-869c-b39b705bdfdf","name": "Live Aid","details": {"startTime": "2022-05-03T20:02:12.274037","endTime": "2022-05-17T20:02:12.274037"}}},{"commitMetadata": {"author": "Freddie Mercury","properties": [],"commitDate": "2022-05-03T20:02:12.343","commitDateInstant": "2022-05-03T18:02:12.343208800Z","id": 1.00},"it": {"id": "37bfc44c-ab29-44b5-869c-b39b705bdfdf","name": "Project 1","details": {"startTime": "2022-05-03T20:02:12.2740372","endTime": "2022-05-17T20:02:12.2740372"}}}
]

如我们所见,返回的响应包含有关同一对象不同版本的信息。例如,返回的数据没有关于给定版本中哪个值已更改的专用信息。

更改查询

查询:

   public String getChanges() {JqlQuery query = QueryBuilder.byClass(Project.class).build();Changes changes = javers.findChanges(query);return javers.getJsonConverter().toJson(changes);
}
响应:
  [{"changeType": "ValueChange","globalId": {"entity": "io.devapo.javerssample.entity.Project","cdoId": "37bfc44c-ab29-44b5-869c-b39b705bdfdf"},"commitMetadata": {"author": "Freddie Mercury","properties": [],"commitDate": "2022-05-03T20:02:27.554","commitDateInstant": "2022-05-03T18:02:27.554689400Z","id": 2.00},"property": "name","propertyChangeType": "PROPERTY_VALUE_CHANGED","left": "Project 1","right": "Live Aid"},{"changeType": "NewObject","globalId": {"entity": "io.devapo.javerssample.entity.Project","cdoId": "37bfc44c-ab29-44b5-869c-b39b705bdfdf"},"commitMetadata": {"author": "Freddie Mercury","properties": [],"commitDate": "2022-05-03T20:02:12.343","commitDateInstant": "2022-05-03T18:02:12.343208800Z","id": 1.00}},{"changeType": "InitialValueChange","globalId": {"entity": "io.devapo.javerssample.entity.Project","cdoId": "37bfc44c-ab29-44b5-869c-b39b705bdfdf"},"commitMetadata": {"author": "Freddie Mercury","properties": [],"commitDate": "2022-05-03T20:02:12.343","commitDateInstant": "2022-05-03T18:02:12.343208800Z","id": 1.00},"property": "id","propertyChangeType": "PROPERTY_VALUE_CHANGED","left": null,"right": "37bfc44c-ab29-44b5-869c-b39b705bdfdf"},{"changeType": "InitialValueChange","globalId": {"entity": "io.devapo.javerssample.entity.Project","cdoId": "37bfc44c-ab29-44b5-869c-b39b705bdfdf"},"commitMetadata": {"author": "Freddie Mercury","properties": [],"commitDate": "2022-05-03T20:02:12.343","commitDateInstant": "2022-05-03T18:02:12.343208800Z","id": 1.00},"property": "name","propertyChangeType": "PROPERTY_VALUE_CHANGED","left": null,"right": "Project 1"}
]

在上面的示例中,我们可以看到仅针对Project类中的字段返回更改信息,省略了嵌入的ProjectDetails类型的值。

生成的响应列出了有关对象创建和特定字段值分配的信息。因此,在以Changes 的形式调用数据查询时,值得通过设置适当的筛选器来缩小搜索区域。

快照查询

查询:

public String getSnapshot() {JqlQuery query = QueryBuilder.byClass(Project.class).build();List&lt;CdoSnapshot&gt; snapshots = javers.findSnapshots(query);return javers.getJsonConverter().toJson(snapshots);
}
响应:
 [{"commitMetadata": {"author": "Freddie Mercury","properties": [],"commitDate": "2022-05-03T20:02:27.554","commitDateInstant": "2022-05-03T18:02:27.554689400Z","id": 2.00},"globalId": {"entity": "io.devapo.javerssample.entity.Project","cdoId": "37bfc44c-ab29-44b5-869c-b39b705bdfdf"},"state": {"name": "Live Aid","details": {"valueObject": "io.devapo.javerssample.entity.Project$ProjectDetails","ownerId": {"entity": "io.devapo.javerssample.entity.Project","cdoId": "37bfc44c-ab29-44b5-869c-b39b705bdfdf"},"fragment": "details"},"id": "37bfc44c-ab29-44b5-869c-b39b705bdfdf"},"changedProperties": ["name"],"type": "UPDATE","version": 2},{"commitMetadata": {"author": "Freddie Mercury","properties": [],"commitDate": "2022-05-03T20:02:12.343","commitDateInstant": "2022-05-03T18:02:12.343208800Z","id": 1.00},"globalId": {"entity": "io.devapo.javerssample.entity.Project","cdoId": "37bfc44c-ab29-44b5-869c-b39b705bdfdf"},"state": {"name": "Project 1","details": {"valueObject": "io.devapo.javerssample.entity.Project$ProjectDetails","ownerId": {"entity": "io.devapo.javerssample.entity.Project","cdoId": "37bfc44c-ab29-44b5-869c-b39b705bdfdf"},"fragment": "details"},"id": "37bfc44c-ab29-44b5-869c-b39b705bdfdf"},"changedProperties": ["name","details","id"],"type": "INITIAL","version": 1}
]

在上面的示例中,我们可以看到Snapshot响应包含与Shodow响应类似的数据集,但包含一些其他元素,例如更改值的列表或审计数据类型(初始更新)。

总结

上面的文章介绍了JaVers工具,它允许您促进和部分自动化数据审计过程。在我们看来,此工具可以让您满足许多项目要求,同时实现它所需的少量工作。我们很高兴与该库分享我们的经验,并鼓励您尝试一下。

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

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

相关文章

vue Router

Vue项目各文件含义 1.src文件夹 是我们真正敲代码的文件夹&#xff0c; 2.assets放静态资源 3.components放组件 4.App.vue主组件 5.main.js项目的入口文件 Vue Router 在router/index.js路由文件中配置路由&#xff0c;设置路由跳转规则 import Vue from vue import Vu…

android Framework 中用到了哪些跨进程通信方式?

文章目录Linux 有哪些跨进程的通信方式&#xff1f;管道本地 Socket共享内存信号Linux 有哪些跨进程的通信方式&#xff1f; Binder 机制是Android基于Linux的一种独特的IPC机制。我们常用的AMS&#xff0c;PMS 等都是通过Binder机制来完成跨进程通信的&#xff0c;那么除了Bin…

【并发】深入理解Java线程的底层原理

线程基础知识 线程与进程 进程 操作系统会以进程为单位&#xff0c;分配系统资源&#xff08;CPU时间片、内存等资源&#xff09;&#xff0c;进程是资源分配的最小单位。 当一个程序被运行&#xff0c;从磁盘加载这个程序的代码至内存&#xff0c;这时就开启了一个进程。 线…

使用 Mason 创建自己的 Flutter brick

使用 Mason 创建自己的 Flutter brick 原文 https://medium.com/gytworkz/create-your-own-flutter-brick-using-mason-7abc70d0324e 前言 谁不喜欢用最少的努力完成大部分事情呢&#xff1f;我当然知道! &#xff01;Mason 帮我完成了几个简单的步骤。 在本文中&#xff0c;我…

Redis——》数据类型:List(列表)

推荐链接&#xff1a; 总结——》【Java】 总结——》【Mysql】 总结——》【Redis】 总结——》【Spring】 总结——》【SpringBoot】 总结——》【MyBatis、MyBatis-Plus】 Redis——》数据类型&#xff1a;List&#xff08;列表&#xff09;一、简介…

复现黑客在后门中藏匿后门

PHP实现在后门中藏匿后门 在攻击渗透的时候会传入shell后门方便进行远控。其中的后门包括多种类型&#xff0c;大马是功能最全的直接提供了可视化的界面方便攻击者进行提权、扫描、上传等一系列的操作。 但有很多hacker不讲武德&#xff0c;在写好的大马中藏入自己的后门&…

VBA Regex 正则表达式应用介绍

. VBA正则表达式介绍 正则表达式或 RegEx 用于在字符串中查找特定的字符。 本文将展示一个 VBA RegEx 示例,并演示为什么在 VBA 中使用正则表达式如此强大。 正则表达式是一个比较大的话题,关于这方面的书很多。 同时也是一个让许多人感到害怕的话题,因为它的语法比较神秘和…

C++入门笔记

C 入门笔记Functions in CC header Files下面主要是我学习C的一个笔记&#xff0c;记录学习中遇到的一些重点事项。下面是视频的连接https://www.bilibili.com/video/BV1Ay4y1i7Z6/?p10&spm_id_from333.1007.top_right_bar_window_history.content.click&vd_sourcee6e…

记录--两行CSS让页面提升了近7倍渲染性能!

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 前言 对于前端人员来讲&#xff0c;最令人头疼的应该就是页面性能了&#xff0c;当用户在访问一个页面时&#xff0c;总是希望它能够快速呈现在眼前并且是可交互状态。如果页面加载过慢&#xff0c;你…

第四章. Pandas进阶—时间序列

第四章. Pandas进阶 4.9 时间序列 1.重采样&#xff08;resample&#xff09; 在Pandas中&#xff0c;对时间序列频率的调整称为重采样&#xff0c;即时间序列从一个频率转换到另一个频率的过程&#xff0c;由周统计变成月统计 1).语法&#xff1a; 4.8章 第4点 已介绍过&…

MySQL数据库行级锁之间隙锁、临键锁

间隙锁 默认情况下&#xff0c;InnoDB在 REPEATABLE READ事务隔离级别运行&#xff0c;InnoDB使用 next-key 锁进行搜索和索引扫描&#xff0c;以防止幻读。 索引上的等值查询(唯一索引)&#xff0c;给不存在的记录加锁时, 优化为间隙锁 。索引上的等值查询(非唯一普通索引)&…

如果把网络原理倒过来看,从无到有,一切如此清晰(下)

人生若只如初见。 前言 当我在台灯下&#xff0c;听着远隔17年前五月天的歌&#xff0c;而在数日后&#xff0c;我的文字也会纵使相隔万里远的来到你的屏幕前&#xff0c;就觉得这一切妙不可言。 OSI 网络七层模型 《如果把网络原理倒过来看&#xff0c;从无到有&#xff0c…

Seal库官方示例(二):encoders.cpp解析

补充一个常用的SIMD操作原理 图片来自的Hang Shao的文章。 完整代码 这个代码主要功能是编码明文&#xff0c;使得能够使用更加完整的明文多项式&#xff08;前一个只用到了一个多项式的常量&#xff09;&#xff0c;也就是SIMD操作。主要包含了两个部分&#xff0c;一个是BG…

HLS + ffmpeg 实现动态码流视频服务

一、简介 如下图&#xff0c;包含三部分&#xff0c;右边一列为边缘节点&#xff1b;中间一列代表数据中心&#xff1b;左边一列是项目为客户提供的一系列web管理工具&#xff1a; 具体来说在我们项目中有一堆边缘节点&#xff0c;每个节点上部署一台强大的GPU服务器及N个网络…

精彩回顾 | 苏州农商银行新一代云原生信息科技架构体系实践

11月18日&#xff0c;2022年第五届中国金融科技产业大会暨第四届中新&#xff08;苏州&#xff09;数字金融应用博览会“基础软件与云原生系统软件”分论坛成功举办。该论坛由由中国计算机学会CTO CLUB&#xff08;苏州&#xff09;承办&#xff0c;江苏省金融科技云原生融合创…

目标检测数据标注项目分析-产品缺陷检测

什么是生产过程中的产品缺陷检测? 生产过程中的缺陷检测是保证产品质量的重要环节。及时发现故障或缺陷&#xff0c;并采取适当的措施&#xff0c;我们可以降低运行和质量相关的风险。但在一般视觉系统中&#xff0c;每个缺陷都必须经过检查及预处理才能被检测到&#xff0c;…

javaSE - Arrays - 数组的定义与使用

一、数组基本用法 1.1、什么是数组 数组本质上就是让我们能 “批量” 创建相同类型的变量 也可以说是存储一组相同数据类型的数据的集合 如: 如果需要表示两个数据, 那么直接创建两个变量即可 int a; int b 如果需要表示五个数据, 那么可以创建五个变量 int a1; int a2; int …

[附源码]Python计算机毕业设计Django的4s店车辆管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

DPU网络开发SDK——DPDK(一)

随着软件定义网络SDN的不断发展&#xff0c;网络数据转发面的需求越来越多样化&#xff0c;这体现在更快的数据包处理速率&#xff0c;更高的网络吞吐带宽&#xff0c;更灵活的自定义网络协议。传统的硬件设备无法满足网络协议的自定义&#xff0c;而基于Linux内核网络协议栈的…

【能效管理】变电所运维云平台在上海某医院的设计分析

摘要&#xff1a;本文概述了变电所电力运维技术&#xff0c;分析了医院变电所中存在的技术设备老化和技术荷载不足的技术性问题&#xff0c;并从主变低压进出线路监测故障、环境监测故障、设备档案记录、运维排班记录、分析报告五个方面探讨了变电所电力运维技术的具体应用。变…