访问JSR-356 @ServerEndpoint的@OnMessage中的ServletContext和HttpSession

Som*_*iks 26 servlets java-ee httpsession websocket java-websocket

我需要ServletContext从内部获取@ServerEndpoint,以便找到Spring ApplicationContext并查找Bean.

目前我最好的方法是在JNDI命名上下文中绑定该bean并在其中查找它Endpoint.欢迎任何更好的解决方案.

我也在寻找一种合理的方法来将servlet HttpSession与websocket 同步Session.

Bal*_*usC 39

该servlet HttpSession是JSR-356可用通过HandshakeRequest#getHttpSession()其又可用时握手请求之前权利制成@OnOpen@ServerEndpoint.在ServletContext又只是通过提供HttpSession#getServletContext().那是一石二鸟.

为了捕获握手请求,请实现ServerEndpointConfig.Configurator并覆盖该modifyHandshake()方法.在HandshakeRequest这里可以作为方法参数.你可以把HttpSessionEndpointConfig#getUserProperties().在EndpointConfig又可以作为方法参数@OnOpen.

以下是实施的启动示例ServerEndpointConfig.Configurator:

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

以下是如何使用它,请注意以下configurator属性@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();
        // ...
    }

}
Run Code Online (Sandbox Code Playgroud)

作为设计提示,最好保持@ServerEndpoint完全不受servlet API依赖的影响.您的倒是modifyHandshake()实现更好立即准确提取你从servlet会话或上下文需要的信息(通常是一个可变的Javabean),并把它们在用户属性映射来代替.如果你不这样做,那么你应该记住,websocket会话可以比HTTP会话更长寿.因此,当您仍然随身携带HttpSession进入端点时,您可能会IllegalStateException在尝试访问它时遇到它.

如果您碰巧有CDI(也许还有JSF),您可以从OmniFaces<o:socket>的源代码中获得灵感(链接位于展示的最底层).

也可以看看:


hfm*_*son 5

更新了BalusC的答案代码,onOpen方法需要用@OnOpen进行修饰.然后就不再需要扩展Endpoint类了:

@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();
        // ...
    }

}
Run Code Online (Sandbox Code Playgroud)