识别会话超时

5

我正在使用servlet构建一个Java网络棋盘游戏。 我需要知道当用户30秒没有响应时,我要使用

session.setMaxInactiveInterval(30);

但是我需要在服务器端知道时间结束后,以便让这个玩家退出。

现在当玩家返回并尝试做某事时,他会遇到超时,我可以在服务器上看到。

我该如何在servlet中知道会话何时超时?!

谢谢。

3个回答

18

您需要实现HttpSessionListener接口。当会话创建或销毁时,它会收到通知事件。特别是在会话被销毁之后,即超时期结束/会话失效之后,它的方法sessionDestroyed(HttpSessionEvent se)会被调用。您可以通过HttpSessionEvent#getSession()调用获取存储在会话中的信息,并随后对会话进行必要的任何安排。此外,请确保在web.xml中注册您的会话侦听器:

<listener>
    <listener-class>FQN of your sessin listener implementation</listener-class>
</listener>

如果您最终想要区分无效和会话超时,您可以在侦听器中使用以下行:
long now = new java.util.Date().getTime();
boolean timeout = (now - session.getLastAccessedTime()) >= ((long)session.getMaxInactiveInterval() * 1000L);

谢谢,但在这种情况下,我只能在浏览器刷新后才能获得sessionDestroyed()。或者我做错了什么吗? - YotamB
关于会话超时,您无需进行任何操作,如操纵浏览器,您的servlet容器将为您处理该情况。请注意,会话不会在超时期满后立即被收集。Servlet容器会定期检查已超时的会话,并在找到符合销毁条件的会话时触发监听器方法并销毁会话。 - skuntsel

1
另一种不基于空闲间隔猜测的方法是在用户触发注销时在会话中设置属性。例如,如果您可以在处理用户触发的注销的方法中放置以下内容:
httpServletRequest.getSession().setAttribute("logout", true);
// invalidate the principal
httpServletRequest.logout();
// invalidate the session
httpServletRequest.getSession().invalidate();

然后你可以在HttpSessionListener类中添加以下内容:
@Override
public void sessionDestroyed(HttpSessionEvent event) {
    HttpSession session = event.getSession();
    if (session.getAttribute("logout") == null) {
        // it's a timeout
    }
}

1
我最终使用了 HttpSessionListener,并在一个比 setMaxInactiveInterval 更长的间隔内进行刷新。因此,如果用户在 30 秒内没有进行任何操作,在接下来的 40 秒内进行刷新后,我会到达 sessionDestroyed()。
还需要注意的是,您需要创建新的 ServletContext 才能访问 ServletContext。
ServletContext servletContext=se.getSession().getServletContext();

谢谢!


你解决了这个问题吗? - Suresh Atta
考虑一个用户在20秒内打开两个浏览器标签页-如果不小心处理,这种情况可能导致他们永远不会退出登录。 - Brad Mace

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接