我需要在 UI 上显示实体的修改历史。像这样的 -
|-------------------------------------------------------------------------------------------------------------------------------------| |Entity name | Entity ID | Action by | Action on | Action Type | Old value | New value | |-------------|-------------|-------------|----------------------|---------------|--------------------------|-------------------------| |Person | 1 | John Doe | 2017-04-12 12:00:00 | Add | | name: Lily, Role: Admin | |Person | 1 | John Doe | 2017-04-15 12:00:00 | Update |name: Lily | name: Lily Smith | |Subject | 5 | Mary | 2017-04-17 12:00:00 | Update |name: Maths | name: Mathematics | |Subject | 6 | Mary | 2017-04-17 12:00:00 | Delete |name: Science, credits: 5 | | |-------------------------------------------------------------------------------------------------------------------------------------|
我使用 Hibernate envers 来存储我需要的所有数据。但是我在读取所有数据以显示上面我需要的内容时遇到问题。我在互联网上搜索了很多博客、问题文章、文档、javadoc,但没有一个显示如何执行此操作。它们都展示了如何根据修订或返回修订检索实体。除了返回的实体之外,这些实体都没有以下信息 -
请注意,我希望尽可能少的查询来加快历史 API 响应。
我正在使用 hibernate 和 envers 版本:'5.2.9.Final'
非常感谢任何帮助。
谢谢!
这是代码-
每个实体类上面的注解-
@Audited(withModifiedFlag = true)
自定义修订监听器 -
public class CustomRevisionListener implements RevisionListener { private static final Logger logger = LogManager.getLogger(CustomRevisionListener.class); public void newRevision(Object revisionEntity) { logger.info("newRevision, starts revisionEntity="+revisionEntity); CustomRevisionEntity revision = (CustomRevisionEntity) revisionEntity; String name = "unknown"; try{ //user custom userdetails.User to store id and name both? //or just store id in string format here? org.springframework.security.core.userdetails.User springUser = (org.springframework.security.core.userdetails.User) SecurityContextHolder .getContext().getAuthentication().getPrincipal(); name = springUser.getUsername(); //get logged in username }catch(Exception e){ logger.error("error getting username", e); } logger.info("newRevision, name="+name); User user = new User(); user.setName(name); revision.setUser(user); //for testing logger.info("newRevision, setting userId="+user.getId()); } }
自定义修订实体 -
@Entity @Table(name="REVISIONS") @RevisionEntity(CustomRevisionListener.class) public class CustomRevisionEntity extends DefaultRevisionEntity { private static final long serialVersionUID = -6113123831136684807L; @ManyToOne @JoinColumn(name="USER_ID") private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
envers 配置 -
org.hibernate.envers.track_entities_changed_in_revision=true org.hibernate.envers.global_with_modified_flag=true org.hibernate.envers.store_data_at_delete=true org.hibernate.envers.audit_strategy=org.hibernate.envers.strategy.ValidityAuditStrategy org.hibernate.envers.audit_strategy_validity_store_revend_timestamp=true
阅读审核 -
public List getAllAudits() { logger.debug("getAllAudits starts"); //HERE IS WHERE I NEED HELP. //below code is just for trials. I need something which will read all audits and relevant info I described above ArrayList list = (ArrayList) AuditReaderFactory.get(entityManager) .createQuery() .forRevisionsOfEntity(Organization.class, true, true) // .add(AuditEntity.id().eq(bitacoraControlId)) .addOrder(AuditEntity.revisionNumber().asc()) .getResultList(); for(int i=0; i revisions = reader.getRevisions(Organization.class, 2); for(Number revNum:revisions){ Organization article =reader.find(Organization.class, 2, revNum); System.out.println("Revision No: " + revNum); System.out.println("Title: " + article.getId()); System.out.println("Content: " + article.getName()); } logger.debug("getAllAudits list size="+list.size()); return list; }
最佳答案
好的,所以我找到了答案。这是我必须分别阅读每种类型的实体的审计并将它们合并到一个列表中的方法 -
AuditQuery query = AuditReaderFactory.get(entityManager)
.createQuery()
.forRevisionsOfEntity(clazz, false /*IMP*/, true)
.addOrder(AuditEntity.revisionNumber().desc());
//This return a list of array triplets of changes concerning the specified revision.
// The array triplet contains the entity, entity revision information and at last the revision type.
ArrayList<Object[]> list = (ArrayList) query.getResultList();
for(int i=0; i < list.size(); i++){
Object[] triplet = list.get(i);
BaseEntity entity = (BaseEntity) triplet[0];
CustomRevisionEntity revisionEntity = (CustomRevisionEntity) triplet[1];
RevisionType revisionType = (RevisionType) triplet[2];
...//populate DTO
}
如果 RevisionType 是“MOD” 要仅使用已更改的字段获取旧值和新值,我必须获取以前的版本并逐个字段进行比较。虽然Envers确实在表格中记录了这个字段的修改信息,但是并没有提供很好的读取方式。
public BaseEntity getPreviousVersion(BaseEntity entity, int current_rev) {
AuditReader reader = AuditReaderFactory.get(entityManager);
Number prior_revision = (Number) reader.createQuery()
.forRevisionsOfEntity(entity.getClass(), false, true)
.addProjection(AuditEntity.revisionNumber().max())
.add(AuditEntity.id().eq(entity.getId()))
.add(AuditEntity.revisionNumber().lt(current_rev))
.getSingleResult();
if (prior_revision != null)
return reader.find(entity.getClass(), entity.getId(), prior_revision);
else
return null;
}
https://stackoverflow.com/questions/43580238/