2016-06-14 25 views
3

它是REST風格的網絡應用程序。我使用Hibernate Envers來存儲歷史數據。除修訂號和時間戳外,我還需要存儲其他詳細信息(例如:IP地址和經過驗證的用戶)。 Envers提供了多種方式來創建一個非常棒的自定義修訂實體。我在修改實體上設置自定義數據時遇到問題。將額外數據傳遞給Hibernate Envers中的自定義修訂實例的方法?

@RevisionEntity(MyCustomRevisionListener.class) 
public class MyCustomRevisionEntity extends DefaultRevisionEntity { 
    private String userName; 

    private String ip; 

    //Accessors 
} 

public class MyCustomRevisionListener implements RevisionListener { 
    public void newRevision(Object revisionEntity) { 
     MyCustomRevisionEntity customRevisionEntity = (MyCustomRevisionEntity) revisionEntity; 
     //Here I need userName and Ip address passed as arguments somehow, so that I can set them on the revision entity. 
    } 
} 

由於newRevision()方法不允許任何額外的參數,我不能把我的自定義數據(如用戶名和IP)到它。我怎樣才能做到這一點?

Envers還提供了另一種方法爲:

使用org.hibernate.envers.RevisionListener是,改爲調用getCurrentRevision的另一種方法(類revisionEntityClass,布爾持續)的org.hibernate作爲的方法。 envers.AuditReader接口獲取當前修訂版,並填寫所需的信息。

因此,使用上面的方法,我將不得不做這樣的事情:

改變我現在的道法,如:

public void persist(SomeEntity entity) { 
    ... 
    entityManager.persist(entity); 
    ... 
} 

public void persist(SomeEntity entity, String userName, String ip) { 
    ... 
    //Do the intended work 
    entityManager.persist(entity); 
    //Do the additional work 
    AuditReader reader = AuditReaderFactory.get(entityManager) 
    MyCustomRevisionEntity revision = reader.getCurrentRevision(MyCustomRevisionEntity, false); 
    revision.setUserName(userName); 
    revision.setIp(ip); 

} 

我不對這種方法感覺不太舒服,因爲保持審計數據似乎是我的一個交叉問題。我通過HTTP請求對象獲取userName和Ip等數據。因此,所有數據都需要從應用程序(控制器)的入口點向下流到最低層(dao層)。

有沒有其他方法可以實現這個目標?我正在使用Spring。

我想像的是像Spring一樣保留有關特定方法調用所屬的「堆棧」的信息。因此,當調用newRevision()時,我知道入口點的哪個特定調用導致此調用。而且,我可以以某種方式獲得傳遞給調用堆棧的第一個方法的參數。

回答

5

這樣做的一個好方法是利用ThreadLocal變量。

舉個例子,春季安全有一個過濾器,初始化存儲在SecurityContextHolder一個線程局部變量,然後你可以簡單地做這樣的事情訪問從特定線程這樣的數據:

SecurityContext ctx = SecurityContextHolder.getSecurityContext(); 
Authorization authorization = ctx.getAuthorization(); 

所以,想象一下一個附加攔截器,您的Web框架會調用該函數,以便向Spring安全上下文添加其他信息,如果使用spring安全性,可能會在自定義用戶詳細信息對象中創建或創建您自己的持有者來保存偵聽器所需的信息。

然後它變成一個簡單的:

public class MyRevisionEntityListener implements RevisionListener { 
    @Override 
    public void newRevision(Object revisionEntity) { 
    // If you use spring security, you could use SpringSecurityContextHolder. 
    final UserContext userContext = UserContextHolder.getUserContext(); 
    MyRevisionEntity mre = MyRevisionEntity.class.cast(revisionEntity); 
    mre.setIpAddress(userContext.getIpAddress()); 
    mre.setUserName(userContext.getUserName()); 
    } 
} 

這感覺就像是最乾淨的方式給我。

值得注意的是,其他API getCurrentRevision(Session,boolean)已從Hibernate 5.2棄用,並計劃在6.0中刪除。雖然可能會引入其他方法,但執行此類邏輯的預期方式是使用RevisionListener

+0

太好了,謝謝!我會嘗試實施它併發布更新。 –

+0

@AnmolGupta你好,你有什麼更新? –

+0

ThreadLocal是處理這種情況的好方法,這就是我通常使用的方式。 –

相關問題