我在Spring启动应用程序中使用spring-data-envers。我可以成功记录我的实体的审核。
现在,我需要在UI中向用户显示审计数据。就像搜索表单一样,用户可以选择持续时间和实体,以便查看审计日志。
string-data-envers提供的RevisionRepository只有以下三种方法。
@NoRepositoryBean
public interface RevisionRepository<T, ID extends Serializable, N extends Number & Comparable<N>> {
/**
* Returns the revision of the entity it was last changed in.
*
* @param id must not be {@literal null}.
* @return
*/
Revision<N, T> findLastChangeRevision(ID id);
/**
* Returns all {@link Revisions} of an entity with the given id.
*
* @param id must not be {@literal null}.
* @return
*/
Revisions<N, T> findRevisions(ID id);
/**
* Returns a {@link Page} of revisions for the entity with the given id.
*
* @param id must not be {@literal null}.
* @param pageable
* @return
*/
Page<Revision<N, T>> findRevisions(ID id, Pageable pageable);
}
如何编写自定义查询以获取特定用户在两个日期之间对实体的所有修订。
请注意,我在user_rev_entity表中添加了其他列,用于存储用户ID和修改日期。如果我将此表与entity_aud表连接,我可以得到结果。
以下是我的Audit表的脚本。
CREATE TABLE `user_rev_entity` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`timestamp` bigint(20) NOT NULL,
`created_by` bigint(20) NOT NULL,
`created_date` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
CREATE TABLE `revchanges` (
`rev` int(11) NOT NULL,
`entityname` varchar(255) DEFAULT NULL,
KEY `FK_et6b2lrkqkab5mhvxkv861n8h` (`rev`),
CONSTRAINT `FK_et6b2lrkqkab5mhvxkv861n8h` FOREIGN KEY (`rev`) REFERENCES `user_rev_entity` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE `roles_aud` (
`role_id` bigint(20) NOT NULL,
`rev` int(11) NOT NULL,
`revtype` tinyint(4) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
`description_mod` bit(1) DEFAULT NULL,
`display_name` varchar(255) DEFAULT NULL,
`display_name_mod` bit(1) DEFAULT NULL,
`is_enabled` bit(1) DEFAULT NULL,
`enabled_mod` bit(1) DEFAULT NULL,
`title` varchar(255) DEFAULT NULL,
`title_mod` bit(1) DEFAULT NULL,
PRIMARY KEY (`role_id`,`rev`),
KEY `FK_pkqm51vsc35w2axvnns4bpas9` (`rev`),
CONSTRAINT `FK_pkqm51vsc35w2axvnns4bpas9` FOREIGN KEY (`rev`) REFERENCES `user_rev_entity` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
因此,基本上我正在寻找特定用户在特定时间内为实体说出的所有更改。
会有更多这样的实体。
Spring Data Envers不支持您在spring数据jpa中习惯的自定义查询。它所做的只是提供方便的RevisionRepository
界面。
但是,您可以使用Revisions<N, T> findRevisions(ID id)
方法并从服务层应用过滤器。这是一个例子。
@Service
public UserService {
@Resource
private UserRepository userRepository;
public List<Revision<Integer, User>> findRevisionsBetweenDates(int id, Date startDate, Date endDate){
return userRepository.findRevisions(id).getContent().stream().filter(
revision -> revision.getEntity().getCreatedDate().getTime() > startDate.getTime() &&
revision.getEntity().getCreatedDate().getTime() < endDate.getTime()
).collect(Collectors.toList());
}
它不是一个完美的选择,因为您将从数据库中获取所有修订版本。但是,这是保持数据库抽象的最简单方法。
否则,您必须跳过Spring Data Envers并使用Envers API。
祝你好运,问候
你看过AuditReaderFactory和AuditReader吗?
查看AuditReader的createQuery文档:
与此AuditReader实例关联的查询创建者,可以使用该查询创建者创建并稍后执行查询。
这将返回一个AuditQueryCreator,您可以使用它来创建如下查询:
AuditQuery query = getAuditReader().createQuery()
.forRevisionsOfEntity(MyEntity.class, false, true);
forRevisionsOfEntity有几个选项,请参阅AuditQueryCreator文档。
该查询应该允许您使用AuditCriterion选择特定的修订版本
Hibernate包含与此相关的文档:http://docs.jboss.org/hibernate/orm/5.0/userGuide/en-US/html_single/#revisions-of-entity
您可以使用与上一个查询相同的方式向此查询添加约束。还有一些额外的可能性:
- 使用AuditEntity.revisionNumber(),您可以在修订号上指定约束,预测和顺序,其中修改了审计实体
- 类似地,使用AuditEntity.revisionProperty(propertyName),您可以在修订实体的属性上指定约束,预测和顺序,对应于修改被审计实体的修订版本
- AuditEntity.revisionType()允许您按上述方式访问修订的类型(ADD,MOD,DEL)。
编辑我尝试了一个实际的解决方案。我有很少的envers和hibernate标准经验,所以这可能不对,但也许它会帮助你开始。
AuditQuery query = getAuditReader().createQuery()
.forRevisionsOfEntity(MyEntity.class, false, true);
query.add(AuditEntity.revisionProperty("createdDate").gt(minDate))
.add(AuditEntity.revisionProperty("createdDate").lt(maxDate))
.add(AuditEntity.revisionProperty("createdBy").eq(userId));
//the documentation shows getSingleResult returns a number
//so i'm guessing a resultList also contains numbers
List<Number> resultList = query.getResultList();
要获得所有修改,您只需:
AuditQuery query = auditReader.createQuery().forRevisionsOfEntity(MyEntity.class, false, false);
List<Object[]> result = query.getResultList();
// and loop over the result list
for (Object[] tuple : result) {Item item = (Item) tuple[0];}