envers
Spring Data JPA,Spring Security和Envers是我个人喜欢使用的库(我倾向于认为它们在各自的类别中被认为是同类中最好的)。 无论如何,我想实现一个我认为简单的用例:实体必须经过Envers审核,但是修订必须包含发起该操作的用户的身份。 尽管看起来很简单,但要实现这一目标我仍然要克服一些挑战。 本文列出了它们,并提供了可能的解决方案。
我使用Spring MVC作为Web框架,配置为使用Spring Security。 为了简化我的开发,Spring Security配置了可识别的登录名/密码。 可以轻松地将其连接到更合适的后端。 本着同样的精神,我在H2内存数据库上的驱动程序管理器连接周围使用了数据源包装器。 只需通过Spring配置更改即可。
典型的流程由我的Spring MVC控制器处理,并传递到注入的服务,该服务管理Spring Data JPA存储库(访问数据库的组件)。
在开发过程中,以下事实已被证明是一个障碍(阅读要克服的障碍):
LocalContainerEntityManagerFactoryBean
参数化Spring配置,然后使用要使用的实现来配置EntityManager工厂bean(在本例中为Hibernate)。 一些传递的参数可跨不同的JPA实现移植,而其他地址则专门针对Envers,因此是完全不可移植的。 <beanid="transactionManager"class="org.springframework.orm.jpa.JpaTransactionManager">
<propertyname="jpaDialect">
<beanclass="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
</bean>
<beanclass="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<propertyname="dataSource"ref="dataSource"/>
<propertyname="jpaVendorAdapter">
<beanclass="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<propertyname="generateDdl"value="true"/>
<propertyname="database"value="H2"/>
<propertyname="showSql"value="true"/>
</bean>
</property>
<propertyname="jpaProperties">
<props>
<propkey="org.hibernate.envers.auditTablePrefix"></prop>
<propkey="org.hibernate.envers.auditTableSuffix"> _HISTORY </prop>
</props>
</property>
</bean>
Auditable
接口的形式提供了一些审计功能。 Auditables有createdBy
, createdDate
, modifiedBy
和modifiedDate
性能。 不幸的是,该库没有存储实体的先前状态:我们必须使用提供此功能的Envers 从好的方面来说,尽管我搜索了所有示例,但最新版本的Hibernate不仅随Envers一起提供,而且由于使用了智能服务提供商 ,因此不需要注册Envers侦听器的任何配置。 您只需要在类路径上提供JAR,JAR本身就负责注册。 这使Envers集成更加简单。
除了添加Spring Data Envers,几乎没有想象力,因为它是Envers的基本用法。
@RevisionEntity(AuditingRevisionListener.class)
@Entity
publicclassAuditedRevisionEntityextendsDefaultRevisionEntity{
privatestaticfinallongserialVersionUID=1L;
privateStringuser;
publicStringgetUser(){
returnuser;
}
publicvoidsetUser(Stringuser){
this.user=user;
}
}
publicclassAuditingRevisionListenerimplementsRevisionListener{
@Override
publicvoidnewRevision(ObjectrevisionEntity){
AuditedRevisionEntityauditedRevisionEntity=(AuditedRevisionEntity)revisionEntity;
StringuserName=SecurityContextHolder.getContext().getAuthentication().getName();
auditedRevisionEntity.setUser(userName);
}
}
Presto,您完成了...
……不是吗? 当写入数据库时,上述解决方案可以完美地工作。 麻烦之处在于尝试从那里获取信息,因为Spring Data API不允许这样做(还可以吗?)。 因此,基本上有三个选项(假设您关心检索:用户可能看不到这种信息,并且在需要访问数据时始终可以连接到数据库以进行查询):
Revisionsrevisions=stuffRepository.findRevisions(stuff.getId());
ListauditedRevisionEntities=newArrayList();
for(Revisionrevision:revisions.getContent()){
Fieldfield=ReflectionUtils.findField(Revision.class,"metadata");
// Oh, it's ugly!
ReflectionUtils.makeAccessible(field);
@SuppressWarnings("rawtypes")
RevisionMetadatametadata=(RevisionMetadata)ReflectionUtils.getField(field,revision);
AuditedRevisionEntityauditedRevisionEntity=(AuditedRevisionEntity)metadata.getDelegate();
// Do what your want with auditedRevisionEntity...
}
集成异构库几乎不是一个过渡。 对于Spring Data JPA和Envers,由于使用了Spring Data Envers库,因此就像馅饼一样容易。 但是,如果需要使审核数据可访问,则需要进一步集成。
这篇文章的来源是在这里 ,在Eclipse / Maven的格式。
翻译自: https://blog.frankel.ch/spring-data-spring-security-and-envers-integration/
envers