Accessing ServletContext and HttpSession in @OnMessage of a JSR-356 @ServerEndpoint

前端 未结 4 2169
小鲜肉
小鲜肉 2020-12-05 04:29

I need to get the ServletContext from inside a @ServerEndpoint in order to find Spring ApplicationContext and lookup for a Bean.

4条回答
  •  一整个雨季
    2020-12-05 05:18

    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.

    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.

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

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

    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.

    In case you happen to have CDI (and perhaps JSF) at hands, you may get inspiration from the source code of OmniFaces (links are at very bottom of showcase).

    See also:

    • Real time updates from database using JSF/Java EE
    • Notify only specific user(s) through WebSockets, when something is modified in the database

提交回复
热议问题