本文介绍了在 JSR-356 @ServerEndpoint 的 @OnMessage 中访问 ServletContext 和 HttpSession的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要从 @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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-16 19:23