2014年12月15日 星期一

hibernate envers

Hibernate Envers 提供數據變更時, 進行自動的 audit 記錄, 但如果需要額外的資訊時, 需要一些客製的程式.

DB : Oracle
DOC : http://docs.jboss.org/envers/docs/#revisionlog
Bean 加上 annotation : @Audited, hibernate 會新增兩個 table,
1. REVINFO : 記錄版本號
2. Table Name_AUD 結尾(以下為例 : Table 會增加一個 TEST_AUDIT_AUD)

@Audited
@Entity
@Table(name = "TEST_AUDIT")
public class TestAudit implements java.io.Serializable {

    private static final long serialVersionUID = 1231323352543L;

    @Id
    @SequenceGenerator(name = "TEST_AUDIT_ID_SEQ", allocationSize = 1, initialValue = 1,
                    sequenceName = "TEST_AUDIT_ID_SEQ")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TEST_AUDIT_ID_SEQ")
    @Column(name = "ID")
    private Long id;

    @Column(name = "TITLE", nullable = false, length = 128)
    private String title;

    @Column(name = "DESCRIPTION", nullable = true, length = 256)
    private String description;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

}

但有時候我們需將 user info 也記錄起來, 此時會需要一個自定的 REVINFO TABLE, 官網文件中提供 2 個方法, 這裡採用不  extends 的方式.
我們需要 2 個 class :
1. 客製的 REVINFO :

@Entity
@RevisionEntity(ExampleListener.class)
public class ExampleRevEntity {
    @Id
    @GeneratedValue
    @RevisionNumber
    private int id;

    @RevisionTimestamp
    private long timestamp;

    private String username;

    // Getters, setters, equals, hashCode ...

}

public class ExampleListener implements RevisionListener {
    public void newRevision(Object revisionEntity) {
        ExampleRevEntity exampleRevEntity = (ExampleRevEntity) revisionEntity;
        User user = xxx.getUser(); // 補充1

        exampleRevEntity.setUsername(identity.getUsername());
    }
}

在 spring-mvc 中, 如果 user 的資訊有存在 session 裡, 可以透過

ServletRequestAttributes srAttrs = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
User user = srAttrs.getRequest().getSession().getAttribute("SESSION_KEY_USER");
logger.info("user name is {}", user.getName());

要使用 spring 的 RequestContextHolder (ThreadLocal) 必須在 web.xml 中加入
web.xml : add request listener
<listener>
  <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>