我正在使用Hibernate envers来审核我的应用程序中的实体。我为每个实体分别有_audit表,然后在那些表中我有_mod boolean列来指示字段是否已更改。
但是,我没有得到如何在查询中使用该列,甚至我如何在代码中获取此数据?
例如以下代码给出了被审计人员的清单。如何检查哪些数据已更改?
List person = getAuditReader().createQuery()
.forEntitiesAtRevision(Person.class, 12)
.getResultList();
您可以循环遍历给定实体的所有字段,并查明该字段是否已更改。
示例代码段循环遍历第12号修订版的Person实体的所有字段,并查找已更新的字段的值。
public void processFields() throws Exception {
for (Field field : Person.class.getDeclaredFields()) {
final Person changedEntity = fetchEntityForRevisionWhenPropertyChanged(Person.class, 12, field.getName());
if (changedEntity != null) {
// Updated field value for the field. This will list all fields which are changed in given revision.
final Object fieldValue = getField(changedEntity, field.getName());
}
}
}
private <T> Object getField(final T object, final String fieldName) throws Exception {
return new PropertyDescriptor(fieldName, object.getClass()).getReadMethod().invoke(object);
}
private <T> T fetchEntityForRevisionWhenPropertyChanged(final Class<T> entityClass, final int revisionNumber, final String propertyName) {
final List<T> resultList = getAuditReader()
.createQuery()
.forEntitiesModifiedAtRevision(entityClass, revisionNumber)
.add(AuditEntity.property(propertyName).hasChanged())
.addOrder(AuditEntity.id().asc())
.getResultList();
if (CollectionUtils.isNotEmpty(resultList)) {
return resultList.get(0);
} else {
return null;
}
}
在任何情况下,如果要查找实体的先前版本以进行比较,可以使用以下方法:
public T getPreviousVersion(final Class<T> entityClass, final Long entityId, final Long currentRevisionNumber) {
final AuditReader reader = AuditReaderFactory.get(entityManager);
final Number previousRevision = (Number) reader.createQuery()
.forRevisionsOfEntity(entityClass, false, true)
.addProjection(AuditEntity.revisionNumber().max())
.add(AuditEntity.id().eq(entityId))
.add(AuditEntity.revisionNumber().lt(currentRevisionNumber))
.getSingleResult();
return Optional.ofNullable(previousRevision)
.map(previousRev -> reader.find(entityClass, entityId, previousRev))
.orElse(null);
}
您可以尝试使用Hibernate拦截器。 Here is关于拦截器的好文章。使用拦截器,您可以创建一个回调,它将在实体更新/创建等时执行。它会像这样:
public class EntityInterceptor extends EmptyInterceptor {
@Override
public boolean onFlushDirty(Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types) {
if ( entity instanceof YourEntity ) {
//do update stuff
return true;
}
return false;
}
}
您可以将currentState与previousState进行比较,以收集有关实体更改的信息,并将其保存到其他表中。