servlets java-ee websocket httpsession java-websocket

servlets - Accediendo a ServletContext y HttpSession en @OnMessage de un JSR-356 @ServerEndpoint



java-ee websocket (3)

Código actualizado para la respuesta de BalusC, el método onOpen debe estar decorado con @OnOpen. Entonces ya no hay necesidad de extender la clase 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(); // ... } }

Necesito obtener el ServletContext desde un @ServerEndpoint para encontrar Spring ApplicationContext y buscar un Bean.

Por el momento, mi mejor enfoque es vincular ese bean en el contexto de nombres JNDI y buscarlo en el Endpoint . Cualquier mejor solución es bienvenida.

También estoy buscando una forma razonable de sincronizar HttpSession con la Session de websocket.


El servlet HttpSession está en JSR-356 disponible por HandshakeRequest#getHttpSession() que a su vez está disponible cuando se realiza una solicitud de handshake justo antes de @OnOpen de @ServerEndpoint . El ServletContext está a su vez solo disponible a través de HttpSession#getServletContext() . Son dos pájaros de un tiro.

Para capturar la solicitud de protocolo de enlace, implemente un ServerEndpointConfig.Configurator y anule el método modifyHandshake() . El HandshakeRequest está disponible aquí como argumento de método. Puede poner HttpSession en EndpointConfig#getUserProperties() . El EndpointConfig está a su vez disponible como argumento de método @OnOpen .

Aquí hay un ejemplo de inicio de la implementación de 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); } }

A continuación, le mostramos cómo puede usarlo, tenga en cuenta el atributo de configurator del @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(); // ... } }

Como sugerencia de diseño, es mejor mantener su @ServerEndpoint completamente libre de dependencias API servlet. En la implementación modifyHandshake() mejor extraer inmediatamente la información (generalmente Javabean mutable) que necesita de la sesión o contexto de servlet y colocarla en el mapa de propiedades del usuario. Si no lo hace, debe tener en cuenta que una sesión de websocket puede vivir más tiempo que la sesión HTTP. Entonces, cuando todavía llevas HttpSession al punto final, puedes encontrarte con IllegalStateException cuando tratas de acceder mientras está expirando.

En caso de que tenga CDI (y quizás JSF) en las manos, puede obtener inspiración del código fuente de OmniFaces <o:socket> (los enlaces están en la parte inferior de la vitrina).

Ver también:


Probé la respuesta de BalusC en Tomcat (Versiones 7.0.56 y 8.0.14). En ambos contenedores, el parámetro de solicitud modifyHandshake no contiene una HttpSession (y por lo tanto no servletContext). Como necesitaba el contexto del servlet solo para acceder a las variables "globales" (es decir, la aplicación web global), acabo de almacenar estas variables en un campo estático ordinario de una clase de titular. Esto es poco elegante, pero funcionó.

Eso se asemeja a un error en esta versión específica de Tomcat. ¿Alguien por ahí también ha visto esto?