WebSockets con STOMP y Spring Boot
Muchas veces en los proyectos necesitamos mantener una comunicación constante con el servidor (back end) para realizar peticiones o mostrar información en tiempo real, para eso nos pueden ayudar los WebSockets. En esta entrada vamos a ver mediante un ejemplo como implementar WebSockets con STOMP y Spring Boot.
¿Qué es un Socket?
Un WebSocket es un protocolo de comunicación sobre TCP y bidireccional, entre el navegador y el servidor. Esta comunicación puede durar tanto tiempo como el cliente o servidor decidan, hasta que uno de los dos la cierre.
El caso de uso más práctico suele ser el uso para chats, en el cual mantienes una comunicación abierta constante entre el navegador y el servidor.
Configuración WebSocket con Spring
Añadir dependencia en Maven
Para comenzar vamos a añadir la siguiente dependencia a nuestro proyecto de Spring Boot.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
Activar WebSocket en Spring Boot
En el siguiente fragmento de código vamos a activar WebSocket en nuestra aplicación de Spring Boot, a registrar los endpoints mediante el método registerStompEndpoints y realizar la configuración del message broker en el método configureMessageBroker.
En el método registerStompEndpoints, se ha dejado todos los orígenes activo por si se quiere hacer pruebas desde algún cliente de sockets.
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/chat"); registry.addEndpoint("/chat").withSockJS(); registry.addEndpoint("/chat").setAllowedOrigins("*"); } }
Crear el mensaje
A continuación vamos a crear el mensaje que vamos a recibir, el cual estará formado por dos campos:
@Getter @Setter public class Message { private String text; private String name; }
Crear el controlador de los mensajes
Una vez que hemos creado el mensaje vamos a crear el controlador que se encargará de recibir el mensaje, para ello vamos a usar dos anotaciones de Spring @MessageMapping y @SendTo
@MessageMapping("/status") @SendTo("/topic/messages") public MessageDto sendMessage(MessageDto message, @Header("simpSessionId") String sessionId) { //Do something return new MessageDto("Message with text : " + message.getText() + " received ", " from " + message.getName()); }
El método anterior se encontrará en una clase bajo la anotación @RestController o @Controller, y por un lado con la anotación @MessageMapping será el endpoint donde recibe los mensajes y por otro lado los enviará al topic mediante la anotación @SendTo.
Algo más que tener en cuenta, es que cuando recibimos un mensaje guardamos su sessionId para poder saber quién se desconecta, esto se hace mediante el atributo simpSessionId que llega en el Header
Crear Notificación de desconexión del Socket
Por lo general los sockets se van a utilizar para crear un canal de comunicación entre el navegador y el servidor, por lo que será necesario saber cuando el socket se desconecta porque, por ejemplo, cierra el navegador, para ello vamos a hacer uso de la anotación @EventListener de Spring. Esta anotación será invocada cuando reciba un evento de tipo SessionDisconnectEvent.
@EventListener public void onDisconnectEvent(SessionDisconnectEvent event) { log.debug("Client with session id {} disconnected", event.getSessionId()); String sessionId = event.getSessionId(); //Do something }
Conclusión
En este artículo hemos visto como configurar WebSockets con STOMP y Spring Boot. El enfoque de este artículo ha sido desde el lado servidor, para poder probar la aplicación se puede hacer uso de algún cliente como AdvancedRestClient.
Para ver el ejemplo completo lo puedes encontrar en Github.
Otros artículos que te pueden interesar:
Spring Boot con Prometheus y Grafana
SoftDelete con Spring Boot e Hibernate