JSF捕获会话超时

JSF捕获会话超时,jsf,session,timeout,Jsf,Session,Timeout,是否有可能“拦截”会话超时 我尝试了HttpSessionListener,但据我所知,当调用HttpSessionListener.sessionDestroyed()方法时,会话已经被破坏。(因此我没有机会确定超时会话的用户) 另一个选项是PhaseListener,在restoreView阶段检查会话是否是“新的” 但是,我需要在会话超时的“第二天”执行一些操作-不在以后的刷新中执行,也不在以后的登录中执行 (背景:需要移除某些对象的锁,用户在运行到超时时可能正在处理这些锁。) 有没有办法

是否有可能“拦截”会话超时

我尝试了
HttpSessionListener
,但据我所知,当调用HttpSessionListener.sessionDestroyed()方法时,会话已经被破坏。(因此我没有机会确定超时会话的用户)

另一个选项是PhaseListener,在restoreView阶段检查会话是否是“新的”

但是,我需要在会话超时的“第二天”执行一些操作-不在以后的刷新中执行,也不在以后的登录中执行

(背景:需要移除某些对象的锁,用户在运行到超时时可能正在处理这些锁。)

有没有办法做到这一点


编辑: 尝试1:在有问题的SessionBean上使用@PreDestroy:

@SessionScoped
@Named
public class SessionBean1 implements Serializable {
   ...
  @PostConstruct
  private void pconstruct(){
     System.out.println("PostConstructing Session Bean 1");
  }
  @PreDestroy
  public void destroy(){
     System.out.println("PreDestroying Session Bean 1");
  } 
}

预期结果:当会话超时或用户注销时,destroy()将被校准

结果:两者都没有发生

22:29:11,199 INFO  [stdout] (http--0.0.0.0-8090-1) ---- Started RESTORE_VIEW 1 ----
22:29:11,208 INFO  [stdout] (http--0.0.0.0-8090-1) ---- Started RENDER_RESPONSE 6 ----
22:29:11,890 INFO  [stdout] (http--0.0.0.0-8090-1) PostConstructing Session Bean 1
22:29:11,898 INFO  [stdout] (http--0.0.0.0-8090-1) -- Finished Request --
22:30:11,905 INFO  [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Session Listener says 'destroyed'.

尝试2:尝试在SessionListener内截获会话超时,这显然会注意到超时:

public class SessionListener implements HttpSessionListener {

    @Inject
    private MySession mySession;

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("Destroying Session of owner: " + mySession.getCurrentUser().getShortName());
    }
}
预期结果:仍然可以访问会话bean

结果:“ContextNotActivieException”:

22:38:57,948 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/test]] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Session event listener threw exception: org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type javax.enterprise.context.SessionScoped
    at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:598) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
    at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:71) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
    at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:79) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
    at my.namespace.test$Proxy$_$$_WeldClientProxy.getCurrentUser(MySession$Proxy$_$$_WeldClientProxy.java) [classes:]
    at my.namespace.listener.SessionListener.sessionDestroyed(SessionListener.java:16) [classes:]
    at org.apache.catalina.session.StandardSession.expire(StandardSession.java:690) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.session.StandardSession.isValid(StandardSession.java:585) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.session.ManagerBase.processExpires(ManagerBase.java:390) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.session.ManagerBase.backgroundProcess(ManagerBase.java:375) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1316) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1601) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590) [jbossweb-7.0.13.Final.jar:]
    at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_33]

尝试3:检查会话属性是否有要使用的内容:

public class SessionListener implements HttpSessionListener {

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        int i=0;
        while (se.getSession().getAttributeNames().hasMoreElements()){
            String name = se.getSession().getAttributeNames().nextElement();
            System.out.println("Checking " + name);
            Object value = se.getSession().getAttribute(name);
            System.out.println("value was: " + value);

            if (i++ == 20){
                break;
            }
        }
    }


    @Override
    public void sessionCreated(HttpSessionEvent se) {
        // nothing to do right here.
    }
}
预期结果:可用属性列表

结果:无限循环:

22:47:48,025 INFO  [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Checking org.jboss.weld.context.conversation.ConversationIdGenerator
22:47:48,025 INFO  [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) value was: org.jboss.weld.context.conversation.ConversationIdGenerator@1edd87d
22:47:48,026 INFO  [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Checking org.jboss.weld.context.conversation.ConversationIdGenerator
22:47:48,027 INFO  [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) value was: org.jboss.weld.context.conversation.ConversationIdGenerator@1edd87d
22:47:48,028 INFO  [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Checking org.jboss.weld.context.conversation.ConversationIdGenerator
22:47:48,029 INFO  [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) value was: org.jboss.weld.context.conversation.ConversationIdGenerator@1edd87d
编辑:

最后,我使用了HttpSessionListener并在SessionMap中创建了一个手动条目,与所有会话范围的bean一起:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(“user_id”,5)

此值可以在SessionListener中访问,并允许我关闭给定用户的所有锁

我尝试了HttpSessionListener,但据我所知,当调用HttpSessionListener.sessionDestroyed()方法时,会话已经被破坏。(因此我没有机会确定超时会话的用户)

我不确定这是怎么形成问题的。您仍然可以通过
HttpSessionEvent
参数获得具体的
HttpSession
实例,您可以在该实例上调用
getAttribute()
方法等,以便在登录用户存储为会话属性的情况下检查该用户

User user = (User) event.getSession().getAttribute("user");
// ...

更新:根据您失败的尝试:

  • 不确定为什么不调用
    @PreDestroy
    。这将是CDI实现的具体问题。它至少与JSF/Servlet无关

  • 您不应该获取已注入的
    @命名的
    实例。您应该直接获取具体实例作为会话属性。对具体的托管bean名称使用
    HttpSession#getAttribute()

  • 在每次迭代过程中都要重新创建迭代器。您应该创建它一次,并在每次迭代中重用它。将
    getAttributeNames()
    放在
    之外,而
    。这个问题与JSF/Servlet无关,只与基本Java相关


  • 我这样做的方法是使UserBean本身成为一个
    HttpSessionListener
    。然后它仍然有自己的状态,因此它知道自己是谁,不管调用回调时会话是否仍然有属性。

    在以后的问题中,如果您在代码中显示您是如何尝试这个和那个的,这将很有帮助。@BalusC会记住这一点@BalusC添加了一些示例,这是我迄今为止所尝试的。我有一个SessionScoped
    mySessionBean
    ,在项目中使用。我使用
    event.getSession.getAttributeNames().hasMoreElements()
    event.getSession.getAttributeNames().nextElement
    来检查调用
    SessionDestroy
    时属性映射中的内容。迭代没有解决任何问题,所以我假设它已经为您的更新空了(除非我没有错拍)thx。1.)似乎是一个已知的问题,但不清楚这是一个bug还是设计的问题。的确,我的错。迭代正确显示所有可用变量。实现2.)有点难看,因为jboss构建的bean有一个非常难看的名称,其中包含文件路径、焊接代理ID和whatev。因此,我现在正在评估另一个答案。:)我试过了,但运气不好。调用
    sessionDestroyed
    方法的那一刻,sessionScoped bean的所有变量都已经
    null
    。这可能是由于JBoss处理会话bean的方式造成的(假设会话bean在调用该方法之前被销毁,结果是一个“新的”(空的)会话bean)。
    User user = (User) event.getSession().getAttribute("user");
    // ...