2011-11-30 99 views
2

我想實現一個審計日誌記錄模塊到我現有的系統,我想保存實際記錄的用戶信息,它只是httpSession。在休眠攔截器中獲取http會話/請求

我使用休眠/彈簧/支柱2,爲了得到實際登錄的用戶信息,並致電saveLog服務,我需要ServletContext中去尋找那些服務豆或獲得HttpServletRequest的...

我有一直在尋找和似乎將會話綁定到ThreadLocal usign Filter是唯一的方法? something like thisthis (last answer)

還有其他建議嗎?這是一種共同模式還是一種良好的做法?

回答

3

Spring可以將當前請求綁定到線程開箱即用。如果您使用DispatcherServlet,則會自動完成,否則您需要聲明RequestContextFilter

然後您可以通過RequestContextHolder訪問請求屬性。

+0

我一直在測試,一切都按我的預期感謝 – Kossel

0

根據您的Hibernate版本,您可能能夠使用Envers來適應細粒度的審計日誌記錄。這包括從會話變量添加「當前用戶」到給定的修訂的能力:

@Entity 
@RevisionEntity(ExampleListener.class) 
public class ExampleRevEntity extends DefaultRevisionEntity { 
    private String username; 

    public String getUsername() { return username; } 
    public void setUsername(String username) { this.username = username; } 
} 

這與Hibernate集成很好地通過一系列的事件監聽器,它可以叫出春天像這樣:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
... 
    <property name="eventListeners"> 
     <map> 
      <entry key="post-insert" value-ref="enversEventListener"/> 
      <entry key="post-update" value-ref="enversEventListener"/> 
      <entry key="post-delete" value-ref="enversEventListener"/> 
      <entry key="pre-collection-update" value-ref="enversEventListener"/> 
      <entry key="pre-collection-remove" value-ref="enversEventListener"/> 
      <entry key="post-collection-recreate" value-ref="enversEventListener"/> 
     </map> 
    </property> 
</bean> 

然後您可以通過Envers查詢api查詢審計修訂版。

在最近的幾個項目中使用它之後,這是我使用Hibernate時的首選審計技術。

applicationContext.getBean("currentUser", User.class); 

只要你的用戶設置:

要回答你的問題,你就可以建立一個Hibernate攔截或Envers RevisionListener通過從當前Spring上下文中查找來訪問「當前用戶」作爲Spring中的scoped bean。

+0

我一直在尋找到Envers,但據我所知它將不得不爲每個實體創建2個表,這不是我想要的。我想將審計日誌保存到只有一個表中。 – Kossel

+0

對於我們來說,保存到多個表中(1個用於審計實體,1個用於審計歷史記錄,1個用於中央修訂票),具有一系列優點。將審計歷史記錄保留在活動實體之外是一種性能幫助,有助於保持域和控制器代碼的正確分段:將歷史記錄與實際記錄分開。 –

0

彈簧啓動示例(spring-boot-starter 1.2.4.RELEASE)。

在某些控制器:

@RequestMapping("login") 
public UserBean login(@RequestParam("email") String email, 
         @RequestParam("password") String password, 
         HttpSession session) { 
    // getting usser 
    session.setAttribute("currentUser", user); 
    return user; 
} 

註冊冬眠聽衆

import org.hibernate.event.service.spi.EventListenerRegistry; 
import org.hibernate.event.spi.*; 
import org.hibernate.internal.SessionFactoryImpl; 
import org.hibernate.jpa.HibernateEntityManagerFactory; 
import org.springframework.stereotype.Component; 
import org.springframework.web.context.request.RequestAttributes; 
import org.springframework.web.context.request.RequestContextHolder; 

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

@Component 
public class UiDateListener implements PostLoadEventListener, PreUpdateEventListener { 
    @Inject EntityManagerFactory entityManagerFactory; 

    @PostConstruct 
    private void init() { 
     HibernateEntityManagerFactory hibernateEntityManagerFactory = (HibernateEntityManagerFactory) this.entityManagerFactory; 
     SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl) hibernateEntityManagerFactory.getSessionFactory(); 
     EventListenerRegistry registry = sessionFactoryImpl.getServiceRegistry().getService(EventListenerRegistry.class); 
     registry.appendListeners(EventType.POST_LOAD, this); 
     registry.appendListeners(EventType.PRE_UPDATE, this); 
    } 

    @Override 
    public void onPostLoad(PostLoadEvent event) { 
     final Object entity = event.getEntity(); 
     if (entity == null) return; 

     final UserBean currentUser = (UserBean) RequestContextHolder.currentRequestAttributes().getAttribute("currentUser", RequestAttributes.SCOPE_SESSION); 
     // some logic after entity loaded 
    } 

    @Override 
    public boolean onPreUpdate(PreUpdateEvent event) { 
     final Object entity = event.getEntity(); 
     if (entity == null) return false; 

     // some logic before entity persist 

     return false; 
    } 
}