• 如何使用Hibernate Envers审核数据,包括用户名信息


    最近,我一直在一个项目中工作,该项目需要审核所有数据库事务,包括用户名。为此,我一直在使用Hibernate ORM Envers,它旨在实现持久类的简单审计/版本控制。

    为了在这篇文章中展示如何使用Hibernate Envers,我基于这个Spring boot JPA项目构建了一个示例项目。Spring Boot 可以轻松创建独立的、生产级的基于 Spring 的应用程序,您可以“直接运行”。在这种情况下,它非常方便,因为它包括:嵌入式雄猫,“入门”POM以简化您的Maven配置,以及随时可用的REST Web服务。

    这篇文章的结构分为 5 个简单的步骤,但是,最后 2 个步骤仅在您想将用户名(或任何其他信息)添加到修订版时才有用。

    1. 配置休眠模拟器

    2. 审计表

    3. 阅读修订版

    4. 为每个修订版添加用户名信息

    5. 阅读修订版,包括用户名

     

    1.配置休眠版本

    首先,您需要将 Hibernate Envers 依赖项添加到您的项目中。当我使用 Maven 来管理我的依赖项时,我需要做的就是将依赖项添加到我的pom文件中:

    1. <dependency>
    2. <groupId>org.hibernategroupId>
    3. <artifactId>hibernate-enversartifactId>
    4. <version>5.6.14.Finalversion>
    5. dependency>

    2. 审计表

    为了能够审核实体表,您只需要有一个具有主键的实体并使用注释@Audited。您可以在类的顶部使用注释@Audited(这将审核类的所有字段),也可以仅在要审核的字段中使用注释。

    添加@Audited注释后,您将看到将为每个实体创建一个后缀为“_AUD”的新表。此外,您还会发现已创建一个名为 REVINFO 的新表,其中包含所有修订信息。默认情况下,此表仅包含修订版的 id 和时间戳,尽管在第 4 节和第 5 节中,我将向您展示如何向此表添加更多数据,例如用户名。

    下面是一个经过审核的 Java 类的示例:

    1. @Entity
    2. @Audited
    3. public class City implements Serializable {
    4. private static final long serialVersionUID = 1L;
    5. @Id
    6. @GeneratedValue(strategy = GenerationType.AUTO)
    7. private Long id;
    8. @Column
    9. private String name;
    10. @Column
    11. private String state;
    12. @Column
    13. private String country;
    14. @Column
    15. private String map;
    16. //getters and setters
    17. }

    在这种情况下,我们将在数据库中自动拥有 2 个表,一个称为 City,另一个称为 City_AUD,其中包括所有 city 字段以及修订标识符和修订类型(创建、更新、删除)。

    3. 阅读修订版

    如果您已经在项目中配置了 Hibernate Envers,那么现在每次在数据库中添加或更新对象时,您都会看到另一行将添加到审核表中。现在我们想获得特定对象的不同修订。

    Hibernate Envers包含一个名为Audit Reader的类,它使任何修订都更容易阅读。您只需要使用实体管理器对其进行初始化。然后,您可以使用 find 方法查找任何修订版本:

    AuditReader reader = AuditReaderFactory.get(entityManager);
    reader.find(class, object id, revision id);

    下面是创建和更新 City 对象然后检查修订的示例

    1. final static String WRONG_STATE = “Wrong State”;
    2. final static String OXFORDSHIRE_STATE = “Oxfordshire”;
    3. @PersistenceContext
    4. private EntityManager entityManager;
    5. @Autowired
    6. private Transactor transactor;
    7. long cityId;
    8. @Test
    9. public void testSaveAndUpdateCity(){
    10. transactor.perform(() -> {
    11. addCity();
    12. });
    13. transactor.perform(() -> {
    14. updateCity(cityId);
    15. });
    16. transactor.perform(() -> {
    17. checkRevisions(cityId);
    18. });
    19. }
    20. private void addCity(){
    21. City city = new City(“Oxford”, “UK”);
    22. city.setState(WRONG_STATE);
    23. entityManager.persist(city);
    24. entityManager.flush();
    25. cityId = city.getId();
    26. }
    27. private void updateCity(long cityId) {
    28. City updateCity = entityManager.find(City.class, cityId);
    29. updateCity.setState(OXFORDSHIRE_STATE);
    30. entityManager.persist(updateCity);
    31. entityManager.flush();
    32. }
    33. private void checkRevisions(long cityId){
    34. AuditReader reader = AuditReaderFactory.get(entityManager);
    35. City city_rev1 = reader.find(City.class, cityId, 1);
    36. assertThat(city_rev1.getState(), is(WRONG_STATE));
    37. City city_rev2 = reader.find(City.class, cityId, 2);
    38. assertThat(city_rev2.getState(), is(OXFORDSHIRE_STATE));
    39. }

    事务处理器是一个自定义类,用于在单个事务中运行一段代码。正如您在checkRevisions函数中看到的,我们正在使用AuditReader来获取同一城市的不同修订。

    AuditReader 具有更多方法,可让您更轻松地查找任何修订版,请查看API以获取更多信息。

    4. 为每个修订版添加用户名信息

    如果您遵循了前 3 个步骤,您应该能够审核和阅读任何修订,对于某些项目,这就是您所需要的。但是,在其他情况下,您将需要审核更多信息,例如进行交易的人的用户名。为此,您需要实现以下 2 个类:

    • 修订实体
    • 修订侦听器

    修订实体是包含您要在每个事务中审核的数据的类。此类必须包含修订号和修订时间戳,您可以手动添加这两个字段,也可以扩展已包含它们的 DefaultRevisionEntity 类。

    下面是我的修订实体的示例,它扩展了 DefaultRevisionEntity 并具有用户名的属性:

    1. @Entity
    2. @RevisionEntity(UserRevisionListener.class)
    3. public class UserRevEntity extends DefaultRevisionEntity {
    4. private String username;
    5. public String getUsername() { return username; }
    6. public void setUsername(String username) { this.username = username; }
    7. }

    请注意,该类包含 @RevisionEntity(UserRevisionListener.class) 注释。修订侦听器是您需要在其中指定如何将其他数据填充到修订中的类。此类需要实现 RevisionListener 接口,该接口只有一个称为 newRevin 的方法。

    让我们看一个例子:

    1. public class UserRevisionListener implements RevisionListener {
    2. public final static String USERNAME = “Suay”;
    3. @Override
    4. public void newRevision(Object revisionEntity) {
    5. UserRevEntity exampleRevEntity = (UserRevEntity) revisionEntity;
    6. exampleRevEntity.setUsername(USERNAME);
    7. }
    8. }

    在此示例中,我正在审核具有相同用户名(“SUAY”)的任何事务,但在实际环境中,您应该从用户服务或用于记录用户的任何其他方法获取用户名。

    5. 阅读修订版,包括用户名

    为了获取用户信息,我使用方法“forRevisionsOfEntity”运行查询,该方法将返回三元组对象:实体,实体修订信息,最后是修订类型。只有第二个对象是我感兴趣的对象,因为它包含用户名信息。请看以下示例:

    1. @Test
    2. public void testUserRevisions() throws Exception{
    3. transactor.perform(() -> {
    4. addCity();
    5. });
    6. transactor.perform(() -> {
    7. checkUsers();
    8. });
    9. }
    10. private void checkUsers(){
    11. AuditReader reader = AuditReaderFactory.get(entityManager);
    12. AuditQuery query = reader.createQuery()
    13. .forRevisionsOfEntity(City.class, false, false);
    14. //This return a list of array triplets of changes concerning the specified revision.
    15. // The array triplet contains the entity, entity revision information and at last the revision type.
    16. Object[] obj = (Object[]) query.getSingleResult();
    17. //In this case we want the entity revision information object, which is the second object of the array.
    18. UserRevEntity userRevEntity = (UserRevEntity) obj[1];
    19. String user = userRevEntity.getUsername();
    20. assertThat(user, is(UserRevisionListener.USERNAME));
    21. }

    运行示例项目

    这篇文章中使用的所有代码都可以在github中找到。

    如果你想运行这个项目,你只需运行SampleDataJpaApplication

  • 相关阅读:
    数据结构与算法编程题11
    代码随想录训练营day48, 打家劫舍系列问题
    【2022】【论文笔记】基于激光直写氧化石墨烯纸的超薄THz偏转——
    不知道10年老电脑如何重装系统?其实很简单
    基于Springboot实现高校社团管理系统
    git reset origin --hard解决‘Your branch is ahead of ‘origin/xxxx‘ by xx commit.’
    凌鲨整体架构
    【Matplotlib绘制图像大全】(六):Matplotlib使用subplot()绘制多个子图
    搭建ELK+Filebead+zookeeper+kafka实验
    论文回顾:Playful Palette: An Interactive Parametric Color Mixer for Artists
  • 原文地址:https://blog.csdn.net/allway2/article/details/127970997