如何在Java中访问HTTP会话

6
如何优雅地通过id获取任何http会话或获取Web应用程序中所有当前活动的http会话(Java 2 EE)?
目前,我有一个WebSessionListener,一旦会话被创建,我就将其放入ConcurrentHashMap()(map.put(sessionId,sessionObj)),一切都很好,我可以随时通过会话ID从该映射中检索HTTP会话,但似乎HttpSession对象永远不会完成...即使会话无效,映射仍然引用无效的会话对象...我还阅读了这篇文章,看起来WeakHashMap在我的情况下是不可接受的...
换句话说,我需要查看任何HttpSession的可能性,甚至获取所有当前活动的HttpSession并从中检索一些属性...
请建议 :)
更新
我需要访问HttpSession对象,因为以下原因:
有时用户会执行一些操作/请求,可能会影响另一个并发用户的工作,例如管理员应该禁用用户帐户,但是此用户正在使用系统,这种情况下我需要向管理员显示一条消息,例如“用户XXX当前正在使用系统”,因此我需要检查是否存在任何持有用户XXX凭据的HttpSession已存在且处于活动状态。因此,我需要这样的可能性来获取任何http会话或甚至所有会话。
我的当前实现是:SessionManager知道所有会话(ConcurrentMap),HttpSessionListener将会话放入/删除会话到SessionManager中。
我担心可能会出现的内存问题,并希望与某人讨论此问题,但目前我清楚地看到一切都应该正常工作,因为当sessionDestroyed()方法被调用时,所有无效的会话将从映射中删除...
非常感谢您的回复,但现在我明白问题只是想象 :)
3个回答

7
根据您的澄清:
有时用户执行某些操作/请求可能会影响另一个并发用户的工作,例如管理员应禁用用户帐户,但该用户当前正在使用系统,在这种情况下,我需要向管理员显示一条消息,例如“用户XXX正在使用系统”,因此我需要检查是否存在任何持有用户XXX凭据的HttpSession已经存在且处于活动状态。所以这就是为什么我需要这样的可能性来获取任何http会话甚至所有会话。
实际上,您不需要了解会话的任何内容。您只需要知道哪些用户已登录。为此,您可以让表示已登录用户的模型对象实现HttpSessionBindingListener。当然,我假设您正在按照设置/删除User模型作为会话属性的正常习惯来登录/注销用户。
public class User implements HttpSessionBindingListener {

    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        Set<User> logins = (Set<User>) event.getSession().getServletContext().getAttribute("logins");
        logins.add(this);
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        Set<User> logins = (Set<User>) event.getSession().getServletContext().getAttribute("logins");
        logins.remove(this);
    }

    // @Override equals() and hashCode() as well!

}

然后在您的管理应用程序中的某个地方,只需从 ServletContext 获取登录信息:

Set<User> logins = (Set<User>) servletContext.getAttribute("logins");

在Servlet中,我们应该在哪里初始化Set<User> logins?如果我在验证用户凭据后设置它,然后:Set<User> logins = new HashSet<>(); if((Set<User>) session.getServletContext().getAttribute("logins") != null){ logins = (Set<User>) session.getServletContext().getAttribute("logins"); } logins.add(loginUser); ServletContext context = getServletContext(); context.setAttribute("logins", logins);这是正确的方法吗? - yaylitzis

5
一般来说,你的Servlet容器会有自己的会话管理器,它负责维护会话的生命周期,并通过cookie、锚点参数或其他策略将传入请求与适当的会话关联起来。
优雅的做法是以任何允许的方式钩入该会话管理器。例如,你可以子类化默认的会话管理器,以便允许你访问任意会话。
但是,听起来你正在做的事情暴露了你的架构中潜在的问题。会话中包含的数据应该特定于该会话,因此通常情况下,你不需要查找任意一个会话来提供Web应用程序的标准逻辑。而管理/管家任务通常由容器处理 - 因此,你不需要干扰这个过程。
如果你说明了为什么要访问任意会话,则很可能另一种方法更适合你的目标。

4

Andrzej Doyle是非常正确的。但如果您真的非常想管理自己的会话列表,那么连接到容器的方法是通过HttpSessionListener - 示例代码

每当创建新会话时都会调用该侦听器,而且重要的是,当会话被销毁时也会调用它;这将允许您模拟容器的会话记录。

您可以使用web.xml将您的会话侦听器注册为应用程序的生命周期侦听器。

您可以使用ServletContext与容器中的其他进程通信您的会话列表,或者您可以使用静态类字段等更脏的方案。


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