【问题标题】:JSF Catch Session TimeoutJSF 捕获会话超时
【发布时间】:2013-03-18 19:58:06
【问题描述】:

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

我尝试了HttpSessionListener,但据我所知,当调用 HttpSessionListener.sessionDestroyed()` 方法时,Session 已经被销毁。 (所以我没有机会确定用户,拥有超时的会话)

另一个选项是 PhaseListener,在 restoreView-Phase 中检查 Session 是否是“新的”。

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

(背景:需要解除某些对象的锁,用户可能在运行超时时一直在工作。)

有没有办法做到这一点?


编辑: 尝试 1:在有问题的 SessionBeans 上使用 @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");
  } 
}

 public class SessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        //nothing to do right here.
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("Session Listener says 'destroyed'.");
    }
} 

预期结果:会话超时或用户注销时会调用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());
    }
}

预期结果:仍然可以访问 Session bean。

结果:'ContextNotActiveException':

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 并在所有 Session Scoped bean 旁边创建了一个手动输入 SessionMap:FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("user_id", 5)

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

【问题讨论】:

  • 在以后的问题中,如果您在代码中显示您是如何尝试这个和那个的,将会很有帮助。
  • @BalusC 会记住这一点!
  • @BalusC 添加了示例,到目前为止我都尝试过。

标签: jsf session timeout


【解决方案1】:

我尝试了 HttpSessionListener,但据我所知,当调用 HttpSessionListener.sessionDestroyed()` 方法时,Session 已经被销毁。 (所以我没有机会确定用户,拥有超时的会话)

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

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

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

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

  2. 您不应该抓取注入的@Named 实例。您应该直接将具体实例作为会话属性获取。在具体托管 bean 名称上使用 HttpSession#getAttribute()

  3. 您在每次迭代期间都在重新创建迭代器。您应该创建一次并在每次迭代中重用它。将getAttributeNames() 放在while 之外。此问题与 JSF/Servlet 无关,仅与基本 Java 有关。

【讨论】:

  • 我有一个 SessionScoped mySessionBean,在项目中使用。我使用event.getSession.getAttributeNames().hasMoreElements()event.getSession.getAttributeNames().nextElement 来检查当SessionDestroy 被调用时属性映射中的内容。迭代没有解决任何问题,所以我认为它已经是空的(除非我没有犯错误)
  • 感谢您的更新。 1.) 似乎 是一个已知问题,但尚不清楚它是错误还是设计。 3.) 的确,我的错。迭代正确显示所有可用变量。实现 2.) 有点难看,因为 jboss 构造的 bean 有一个非常难看的名称,其中包含文件路径、焊接代理 ID 和什么。所以我目前正在评估另一个答案。 :)
【解决方案2】:

我这样做的方法是使 UserBean 本身成为HttpSessionListener。然后它仍然拥有自己的所有状态,因此它知道它“是谁”,无论调用回调时会话是否仍然具有属性。

【讨论】:

  • 我试过这个,但没有运气。在调用sessionDestroyed 方法的那一刻,sessionScoped bean 的所有变量都已经是null。这可能是由 JBoss 处理 Session bean 的方式引起的(假设 Session bean 在方法被调用之前被销毁,以“新”(空)会话 bean 结束。)。
猜你喜欢
  • 2012-10-14
  • 2013-03-29
  • 2012-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-24
  • 2012-09-27
  • 1970-01-01
相关资源
最近更新 更多