用于用户输入的 Hibernate Envers 自定义字段

Hibernate Envers custom field for user input

我正在使用 Spring Boot 和 Hibernate Envers 以及自定义 RevisionEntityRevisionListener 来存储附加信息,例如修订信息中的用户名、ip。效果很好。

作为新需求,我还需要存储用户的修改评论。因此,如果用户更改实体 he/she 还需要输入此更改的原因。此文本应与其他修订信息一起保存。

我的 ControllerService class 中都有文本,但是如何用这些信息填充 RevisionListener

您问题的理想答案取决于您当前使用的 Hibernate 和 Spring Framework 的版本,因为在这两个版本的更高版本中添加了一些新功能,将应用程序状态注入 RevisionListener回调非常容易获得。

使用 Hibernate 5.2 或更早版本

如果您使用的是 Hibernate 5.2 或更早版本,您将只能使用使用 ThreadLocal 变量注入应用程序状态的传统方法。在 Web 应用程序中,这可以通过设置 Web 过滤器或作为 Web 控制器的一部分来轻松完成。

目标是在调用执行持久化操作的任何业务 service/bean 之前初始化 ThreadLocal 并在提交持久化操作后清除状态。由于大多数 spring-based 应用程序倾向于将服务方法包装在 @Transactional 注释中,然后在控制器中处理 ThreadLocal 的初始化和清除似乎是合乎逻辑的。

由于 ThreadLocal 是作用域为执行线​​程的全局变量,侦听器将能够向线程本地实例询问值,以便在自定义修订实体上设置它。最重要的是在持久化操作开始前设置,保存后清除。

在 CDI 环境中使用 Hibernate 5.3+

这可能不适用于您,因为您处于 Spring 环境中,但为了所有可能的配置选择的完整性,我将其包括在内。

如果您在 CDI-based 环境中使用 Hibernate 5.3 或更高版本,Hibernate 添加了对 CDI 注入的默认支持,基本上允许 Hibernate 创建的某些对象实际成为 CDI bean 并支持将状态注入到它们中。也就是说

public class CustomRevisionListener implements RevisionListener {
  @Inject
  private UserReasonBean reasonBean;

  @Override
  public void newRevision(Object revisionEntity) {
    // inside this method, you can get the reason from the injected reasonBean
    // and now set the reason on the custom revision entity instance.
  }
}

使用 Hibernate 5.3+ 但使用 Spring 5.0 或更早版本

为了使 Spring Framework bean 注入工作,您必须使用 Spring Framework 5.1 或更高版本(他们添加了该支持),否则在使用 Spring Framework 5.0 或在使用 Hibernate 之前,您必须使用带有 ThreadLocal 变量的传统方法。

请参阅使用 Hibernate 5.2 或更早版本

将 Hibernate 5.3+ 与 Spring 5.1+

一起使用

如果您将 Hibernate 5.3 或更高版本与 Spring Framework 5.1 或更高版本一起使用,那么您很幸运。在此用例中,您可以自动模仿默认的 CDI 支持,因为 Spring Framework 5.1 提供了他们自己的 bean 注册表实现并将其自动连接到 Hibernate 的框架中。简而言之,这意味着您可以轻松地将 auto-wire Spring bean 放入 RevisionListener 中,就像您使用 CDI 一样。

public class CustomRevisionListener implements RevisionListener {
  @Autowired
  private UserReasonBean reasonBean;

  @Override
  public void newRevision(Object revisionEntity) {
    // inside this method, you can get the reason from the injected reasonBean
    // and now set the reason on the custom revision entity instance.
  }
}