hibernate - Envers 查询 - 返回 REVTYPE 以及修改的字段

我需要在 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,但没有一个显示如何执行此操作。它们都展示了如何根据修订或返回修订检索实体。除了返回的实体之外,这些实体都没有以下信息 -

  1. 谁做了改变
  2. 这种变化是什么时候发生的
  3. 它是什么类型的变化。添加/更新/删除

请注意,我希望尽可能少的查询来加快历史 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/

相关文章:

java - 如果单例不好!为什么spring bean默认是单调的

r - R中的双重居中

azure - 当结果具有相同分数时在 Azure 搜索中进行分页

scikit-learn - 具有高斯过程的多输出空间统计

c++ - 复制具有线程安全规则建议的非const参数的构造函数?

sql - 将前导零添加到 varchar 列

azure - 将 CloudFlare CDN 与 Azure Blob 存储结合使用

persistence - 在 Quartz 调度程序中看到异常导致作业无法运行

python-3.x - 安装anaconda3后找不到conda命令

java - 使用 Java 8 Streams 将 Map 的 Map 转换为 Lists