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

Med*_*dha 3 hibernate

我需要在 UI 上显示实体的修改历史。像这样的东西——

    |------------------------------------------------- -------------------------------------------------- ----------------------------------|
    |实体名称 | 实体 ID | 行动者 | 对 | 采取行动 动作类型 | 旧值 | 新价值 |
    |-------------|-------------|------------|------- ---------------|------------------------------|---------------- --------|-------------------------|
    |人 | 1 | 约翰·多伊 | 2017-04-12 12:00:00 | 添加 | | 姓名:莉莉,角色:管理员 |
    |人 | 1 | 约翰·多伊 | 2017-04-15 12:00:00 | 更新|名称:百合| 姓名:莉莉·史密斯 |
    |主题 | 5 | 玛丽 | 2017-04-17 12:00:00 | 更新 |名称:数学 | 名称: 数学 |
    |主题 | 6 | 玛丽 | 2017-04-17 12:00:00 | 删除 |名称:科学,学分:5 | |
    |------------------------------------------------- -------------------------------------------------- ----------------------------------|

我使用 Hibernate envers 来存储我需要的所有数据。但是我在读取所有数据以显示上面需要的内容时遇到问题。我在互联网上搜索了很多博客、问题文章、文档、javadoc,但没有一个显示如何执行此操作。所有这些都展示了如何根据修订或返回修订检索实体。除了返回的实体之外,这些实体都没有以下信息 -

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

请注意,我希望尽可能少的查询次数来加速历史 API 响应。

我正在使用 hibernate 和 envers 版本:'5.2.9.Final'

高度赞赏的任何帮助。

谢谢!

更新

这是代码 -

每个实体类上方的注释-

    @Audited(withModifiedFlag = true)

自定义修订侦听器 -

    公共类 CustomRevisionListener 实现 RevisionListener {

        私有静态最终记录器记录器 = 
        LogManager.getLogger(CustomRevisionListener.class);

        公共无效新修订(对象修订实体){
            logger.info("newRevision, 开始revisionEntity="+revisionEntity);

            CustomRevisionEntity 修订版 = (CustomRevisionEntity) 修订实体;

            字符串名称 = "未知";

            尝试{
                // 用户自定义 userdetails.User 来存储 id 和 name 两者? 
                // 或者只是在此处以字符串格式存储 id?
                org.springframework.security.core.userdetails.User springUser = 
                        (org.springframework.security.core.userdetails.User) SecurityContextHolder
                        .getContext().getAuthentication().getPrincipal();
                name = springUser.getUsername(); //获取登录用户名
            }catch(异常e){
                logger.error("获取用户名错误", e);
            }

            logger.info("newRevision, name="+name);

            用户用户 = 新用户();
            user.setName(name);
            修订版.setUser(用户); //用于检测

            logger.info("newRevision, setting userId="+user.getId());
        }
    }

自定义修订实体 -

    @实体
    @Table(name="修订版")
    @RevisionEntity(CustomRevisionListener.class)
    公共类 CustomRevisionEntity 扩展 DefaultRevisionEntity {

        private static final long serialVersionUID = -6113123831136684807L;

        @ManyToOne
        @JoinColumn(name="USER_ID")
        私人用户用户;

        公共用户 getUser() {
            返回用户;
        }

        公共无效设置用户(用户用户){
            this.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

阅读审核——

        公共列表 getAllAudits() {
            logger.debug("getAllAudits 开始");

            //这里是我需要帮助的地方。
            //以下代码仅用于试验。我需要一些可以读取我上面描述的所有审计和相关信息的东西

            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 修订 = reader.getRevisions(Organization.class, 2);
            for(Number revNum:revisions){
                组织文章 =reader.find(Organization.class, 2, revNum);
                System.out.println("修订号:" + revNum);
                System.out.println("标题:" + article.getId());
                System.out.println("内容:" + article.getName());        

            }

            logger.debug("getAllAudits list size="+list.size());

            退货清单;
        }

Med*_*dha 5

好的,所以我找到了我的答案。这是我必须分别阅读每种类型实体的审计并将它们合并到一个列表中的方法 -

    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
    }
Run Code Online (Sandbox Code Playgroud)

如果 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;
}
Run Code Online (Sandbox Code Playgroud)