Escenario
Un usuario se conecta con el móvil a su aplicación de empresa. Si es la primera vez que lo hace ésta le pide autorización para recabar su localización. La aplicación manda la localización al servidor y desde el servidor se informa a una página de monitorización. Dicha página está conectada por websocket con el servidor y no necesita recargarse para refrescar las localizaciones de los usuarios en un mapa. La aplicación usa Spring Boot v2.5.4.Problema
En el tutorial oficial y otros encontrados gracias a Google, dan por hecho usar un cliente de sockjs para conectarse al servicio. En una página oficial de stompjs, sin embargo, sostienen lo contrario:For Spring STOMP users: There are few tutorials/guides that implicitly suggest that you need SockJS to use STOMP. That is incorrect, you only need SockJS if you need to support old browsers.Osea que solo es necesario si queremos dar soporte a navegadores anticuados. Dado que la aplicación corre en un entorno empresarial con la versión de navegadores controlada, decido prescindir de él.
Solución
De la parte del servidor vamos a necesitar cuatro ficheros: Un DTO para envolver los mensajes de ida:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class HelloMessage { private String name; public HelloMessage() { } public HelloMessage(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class GreetingMessage { private String content; public GreetingMessage() { } public GreetingMessage(String content) { this.content = content; } public String getContent() { return content; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; /** * * @author marcos */ @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/ws/"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/stomp"); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import es.marcospena.blog.data.domain.message.GreetingMessage; import es.marcospena.blog.data.domain.message.HelloMessage; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.stereotype.Controller; import org.springframework.web.util.HtmlUtils; /** * * @author marcos */ @Controller public class MessageController { @MessageMapping("/hello") @SendTo("/topic/greetings") public GreetingMessage greeting(HelloMessage message) throws Exception { return new GreetingMessage("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!"); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
const StompJs = require('@stomp/stompjs'); initSocketConnection = () => { const client = new StompJs.Client({ brokerURL: 'ws://localhost:8080/stomp', debug: function (str) { console.log(str); }, reconnectDelay: 5000, heartbeatIncoming: 4000, heartbeatOutgoing: 4000, onConnect: () => { client.subscribe('/topic/greetings', message => { console.log('message body', message.body); }) } }); client.onStompError = function (frame) { // Will be invoked in case of error encountered at Broker // Bad login/passcode typically will cause an error // Complaint brokers will set `message` header with a brief message. Body may contain details. // Compliant brokers will terminate the connection after any error console.log('Broker reported error: ' + frame.headers['message']); console.log('Additional details: ' + frame.body); }; client.activate(); } |