如何使用 hibernate envers 审计日志获取 JIRA 之类的更改历史记录?

How to get JIRA like change history using hibernate envers audit log?

我正在尝试在 UI 上显示 JIRA 之类的更改历史记录。我正在使用 Spring Data JPA 并且我已经使用 Envers (v5.3.7) 配置了审计跟踪。对于特定实体,我可以使用 AuditQuery 通过其主键值获取所有修订的列表。

是否有一种简单的方法可以跨修订计算 "delta" 并确定已更改的属性? (有旧值和新值)

我已将 @Audited(withModifiedFlag = true) 注释添加到我的实体 class。它在 <entity>_aud table 中为每个 属性 添加一列,指示 属性 是否已更改。我想弄清楚如何使用这些额外的列。

如果你需要像 JIRA 这样的东西,你必须自己构建它。

我建议您使用 Hibernate 拦截器:

http://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#events

正如您在以下示例中看到的,您获得了当前和之前的状态,然后可以创建增量并将其存储在您自己的变更日志中 table:

public static class LoggingInterceptor extends EmptyInterceptor {
    @Override
    public boolean onFlushDirty(
        Object entity,
        Serializable id,
        Object[] currentState,
        Object[] previousState,
        String[] propertyNames,
        Type[] types) {
            LOGGER.debugv( "Entity {0}#{1} changed from {2} to {3}",
                entity.getClass().getSimpleName(),
                id,
                Arrays.toString( previousState ),
                Arrays.toString( currentState )
            );
            return super.onFlushDirty( entity, id, currentState,
                previousState, propertyNames, types
        );
    }
}

这是我的代码

import javax.annotation.PostConstruct;
import javax.persistence.EntityManagerFactory;

import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PreUpdateEvent;
import org.hibernate.event.spi.PreUpdateEventListener;
import org.hibernate.internal.SessionFactoryImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class AuditListener implements PreUpdateEventListener {   
    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @PostConstruct
    private void init() {
        SessionFactoryImpl sessionFactory = entityManagerFactory.unwrap(SessionFactoryImpl.class);
        EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);

        // You can also add listener for a specific entity-type instead of event-group
        // In my case I needed global event listener
        registry.getEventListenerGroup(EventType.PRE_UPDATE).appendListener(this);
    }

    @Override
    public boolean onPreUpdate(PreUpdateEvent event) {
        String[] propertyNames = event.getPersister().getPropertyNames();
        Object[] oldValues = event.getOldState();
        Object[] newValues = event.getState();
        for (int index = 0; index < propertyNames.length; index++) {
            String propertyName = propertyNames[index];
            Object oldValue = oldValues[index];
            Object newValue = newValues[index];

            // This is just sample code
            boolean changed = oldValue != newValue;
            if (changed) {
                System.out.println("Audit log -> Property: " + propertyName + ", Old value: " + oldValue + ", New value: " + newValue);

                // Actual code that persists audit log
                ...
                ...
            }
        }
        return false;
    }
}