问题描述
我需要从 @ServerEndpoint
内部获取 ServletContext
以便找到 Spring ApplicationContext
并查找 Bean.
I need to get the ServletContext
from inside a @ServerEndpoint
in order to find Spring ApplicationContext
and lookup for a Bean.
目前我最好的方法是在 JNDI 命名上下文中绑定那个 bean 并在 Endpoint
中查找它.欢迎任何更好的解决方案.
For the moment my best approach is to bind that bean in the JNDI naming context and lookup it in the Endpoint
. Any better solution is welcome.
我也在寻找一种合理的方法来同步 servlet 的 HttpSession
和 websocket 的 Session
.
I'm also looking for a reasonable way to sync servlet's HttpSession
with websocket's Session
.
推荐答案
servlet HttpSession
位于 JSR-356 中,HandshakeRequest#getHttpSession()
当握手请求在 @OnOpen
之前发出 的一个 @ServerEndpoint代码>
.ServletContext
反过来只能通过 HttpSession#getServletContext()
.一石二鸟.
The servlet HttpSession
is in JSR-356 available by HandshakeRequest#getHttpSession()
which is in turn available when a handshake request is made right before @OnOpen
of a @ServerEndpoint
. The ServletContext
is in turn just available via HttpSession#getServletContext()
. That's two birds with one stone.
为了捕获握手请求,实现一个ServerEndpointConfig.Configurator
并覆盖 modifyHandshake()
方法.HandshakeRequest
在这里可用作方法参数.您可以将 HttpSession
放入 EndpointConfig#getUserProperties()
.EndpointConfig
又可用作方法参数 @OnOpen
.
In order to capture the handshake request, implement a ServerEndpointConfig.Configurator
and override the modifyHandshake()
method. The HandshakeRequest
is here available as method argument. You can put the HttpSession
into EndpointConfig#getUserProperties()
. The EndpointConfig
is in turn available as method argument @OnOpen
.
以下是 ServerEndpointConfig.Configurator
实现的启动示例:
Here's a kickoff example of the ServerEndpointConfig.Configurator
implementation:
public class ServletAwareConfig extends ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
HttpSession httpSession = (HttpSession) request.getHttpSession();
config.getUserProperties().put("httpSession", httpSession);
}
}
以下是使用方法,请注意 configurator
@ServerEndpoint
的属性:
Here's how you can use it, note the configurator
attribute of the @ServerEndpoint
:
@ServerEndpoint(value="/your_socket", configurator=ServletAwareConfig.class)
public class YourSocket {
private EndpointConfig config;
@OnOpen
public void onOpen(Session websocketSession, EndpointConfig config) {
this.config = config;
}
@OnMessage
public void onMessage(String message) {
HttpSession httpSession = (HttpSession) config.getUserProperties().get("httpSession");
ServletContext servletContext = httpSession.getServletContext();
// ...
}
}
作为设计提示,最好让您的 @ServerEndpoint
完全摆脱 servlet API 依赖.您应该在 modifyHandshake()
实现中更好地立即从 servlet 会话或上下文中准确地提取那个您需要的信息(通常是可变的 Javabean),并将它们放入用户属性中地图代替.如果您不这样做,那么您应该记住,websocket 会话的寿命可能比 HTTP 会话长.因此,当您仍然将 HttpSession
带入端点时,当您尝试在它过期时访问它时,您可能会遇到 IllegalStateException
.
As a design hint, it's the best to keep your @ServerEndpoint
fully free of servlet API dependencies. You'd in the modifyHandshake()
implementation better immediately extract exactly that information (usually a mutable Javabean) you need from the servlet session or context and put them in the user properties map instead. If you don't do that, then you should keep in mind that a websocket session can live longer than the HTTP session. So when you still carry around HttpSession
into the endpoint, then you may run into IllegalStateException
when you try to access it while it's being expired.
如果您碰巧手头有 CDI(可能还有 JSF),您可能会从 OmniFaces (链接在展示的最底部).
In case you happen to have CDI (and perhaps JSF) at hands, you may get inspiration from the source code of OmniFaces <o:socket>
(links are at very bottom of showcase).
这篇关于在 JSR-356 @ServerEndpoint 的 @OnMessage 中访问 ServletContext 和 HttpSession的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!