如何在 Java 中访问 HTTP 会话
Posted
技术标签:
【中文标题】如何在 Java 中访问 HTTP 会话【英文标题】:How to access HTTP sessions in Java 【发布时间】:2011-03-15 05:46:33 【问题描述】:如何以优雅的方式通过 id 获取任何 http 会话或 Web 应用程序 (Java 2 EE) 中所有当前活动的 http 会话?
目前我有一个WebSessionListener
,一旦创建了会话,我就把它放在ConcurrentHashMap() (map.put(sessionId, sessionObj))
中,一切正常,我可以随时通过会话ID 从该映射中检索HTTP 会话,但它看起来像HttpSession
对象永远不会最终确定...即使会话无效,地图仍然引用无效的会话对象...我也读过this article,看起来WeakHashMap
在我的情况下是不可接受的...
换句话说,我需要查看任何 HttpSession 甚至获取所有当前活动的 HttpSession
并从那里检索一些属性...
请给某人建议:)
更新
由于以下原因,我需要访问 HttpSession 对象:
有时用户执行一些操作/请求可能会影响另一个并发用户的工作,例如管理员应该禁用用户帐户,但该用户当前正在使用系统,在这种情况下,我需要向管理员显示一条消息,例如“用户 XXX 当前正在使用系统”因此我需要检查是否有任何持有用户 XXX 凭据的 HttpSession 已经存在并且处于活动状态。所以这就是为什么我需要这种可能性来获得任何 http 会话甚至所有会话。
我目前的实现是:知道所有会话(ConcurrentMap)的 SessionManager 和将会话放入/删除会话管理器的 HttpSessionListener。
我担心可能发生的内存问题,我想与某人讨论这个问题,但目前我清楚地看到一切都应该正常,因为当 sessionDestroyed() 方法将被调用时,所有无效的会话都将从映射中删除。 ..
非常感谢您的重播,但现在我明白问题只是想象 :)
【问题讨论】:
【参考方案1】:根据您的说明:
有时用户执行一些操作/请求可能会影响另一个并发用户的工作,例如管理员应该禁用用户帐户但该用户当前正在使用系统,在这种情况下我需要向管理员显示消息例如“用户 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 的哪个位置初始化 SetSet<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);
这是正确的方法吗?一般来说,您的 servlet 容器将有自己的会话管理器,它负责维护会话的生命周期,并将传入请求与适当的会话相关联(通过 cookie、锚参数,无论它想要什么策略)。
执行此操作的优雅方法是以任何允许的方式连接到此会话管理器。你可以继承默认的,例如,允许你访问任意会话。
但是,听起来您正在做的事情掩盖了您的架构的潜在问题。会话中包含的数据应该特定于该会话,因此通常您不需要查找任意数据以提供 Web 应用程序的标准逻辑。并且管理/内务管理任务通常由容器为您处理 - 所以同样,您不需要干预。
如果您说明为什么您希望访问任意会话,则很可能另一种方法更适合您的目标。
【讨论】:
【参考方案3】:Andrzej Doyle 是非常正确的。但是,如果您真的非常想管理自己的会话列表,那么连接到容器的方法是通过 HttpSessionListener - example code。
每当创建新会话时都会调用监听器,重要的是,当会话被销毁时也会调用它;这将允许您模拟容器的会话簿记。
您使用 web.xml
将会话侦听器注册为您的应用的生命周期侦听器。
您可以使用ServletContext
将您的会话列表与容器中的其他进程通信,或者您可以使用例如更脏的方案静态类字段。
【讨论】:
以上是关于如何在 Java 中访问 HTTP 会话的主要内容,如果未能解决你的问题,请参考以下文章