2011-11-30 96 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; 
    } 
}