问题
I'm using Spring Boot and Hibernate Envers with a custom RevisionEntity
and RevisionListener
to store additional information like username, ip in the revision info. It works fine.
As a new requirement I also need to store modification comment from the user. So if a user changes an entity he/she also needs to enter a reason for this change. This text should be saved among the other revision information.
I have the text in my Controller
and in the Service
class as well, but how can I populate the RevisionListener
with this information?
回答1:
The ideal answer to your question depends on the versions of both Hibernate and Spring Framework that you are currently using as some new features added in the later versions of both making injecting application state into the RevisionListener
callback tremendously easier to obtain.
Using Hibernate 5.2 or prior
If you are using Hibernate 5.2 or prior, you're going to be restricted to the legacy approach of injecting the application state using ThreadLocal
variables. In a web application, this can easily be done either by setting up a web filter or doing this as a part of your web controller.
The goal is to initialize the ThreadLocal
prior to calling whatever business service/bean that performs the persistence operation and clearing the state after the persistence operation has been committed. Since most spring-based applications tend to wrap the service method in a @Transactional
annotation then handling the initialization and clearing of the ThreadLocal
in the controller seems logical.
Since the ThreadLocal
is a global variable that is scoped to the executing thread, the listener will be able to ask the thread local instance for the value in order to set it on the custom revision entity. The most important thing is to set it before the persistence operation starts and to clear it after its saved.
Using Hibernate 5.3+ in a CDI environment
This likely doesn't apply to you since you're in a Spring environment, but for the sake of completeness of all the possible configuration choices, I'm including it.
If you are using Hibernate 5.3 or later in a CDI-based environment, Hibernate added default support for CDI injection, basically allowing certain objects created by Hibernate to actually become CDI beans and support having state injected into them. In other words
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.
}
}
Using Hibernate 5.3+ but with Spring 5.0 or prior
In order to get Spring Framework bean injection to work, you must be using Spring Framework 5.1 or later where they added that support, otherwise when using Spring Framework 5.0 or prior with Hibernate, you must use the legacy approach with ThreadLocal
variables.
See Using Hibernate 5.2 or prior
Using Hibernate 5.3+ with Spring 5.1+
If you are using Hibernate 5.3 or later with Spring Framework 5.1 or later, then you're in luck. In this use case, you can mimic the default CDI support automatically because Spring Framework 5.1 provides their own bean registry implementation and wires it automatically into Hibernate's framework. In short, this means that you can easily auto-wire Spring beans into the RevisionListener
just as if you were using 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.
}
}
来源:https://stackoverflow.com/questions/56040031/hibernate-envers-custom-field-for-user-input