Basic Websocket
This is going to build a STOMP based websocket on server site.
- Add dependency to POM.XML
- Add a EnableWebSocketMessageBroker configuration
- Add a controller to handle the web socket package.
Add dependency to POM.XML
Add the following in POM.XML
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
EnableWebSocketMessageBroker
Create a java class that @Configuration and @EnableWebSocketMessageBroker. Here we register an endpoint /my-websocket-endpoint
for frontend to connect to. We add the prefix /app
as application destination prefix so that when the client send their request, they need to add it in their destination. And we have add a channel topic
for client to subscribe.
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; @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("/my-websocket-endpoint").withSockJS(); } }
Controller to Send and Receive
We user @MessageMapping to get the client request, and @SendToUser to send respond back to the requested client, or @SendTo to respond to all clients that subscribe to the channel. The server can also send package to the client by using SimpMessagingTemplate.
@Controller public class GreetingController { private final SimpMessagingTemplate simpMessagingTemplate; public GreetingController(SimpMessagingTemplate simpMessagingTemplate) { this.simpMessagingTemplate = simpMessagingTemplate; } @MessageMapping("/hello") @SendToUser("/topic/greetings") public Greeting greeting(HelloMessage message) throws Exception { Thread.sleep(1000); // simulated delay return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!"); } @MessageMapping("/helloToAll") @SendTo("/topic/greetings") public Greeting greetingToAll(HelloMessage message) throws Exception { Thread.sleep(1000); // simulated delay return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!"); } public void broadcastNews() { this.simpMessagingTemplate.convertAndSend("/topic/news", new Greeting("This is a news broadcast")); } }
JavaScript client
First import sockjs, and stomp.js library.
Connect to server
function connect() { var socket = new SockJS('/my-websocket-endpoint'); stompClient = Stomp.over(socket); stompClient.connect({}, function (frame) { setConnected(true); console.log('Connected: ' + frame); stompClient.subscribe('/user/topic/greetings', function (greeting) { console.log(JSON.parse(greeting.body).content); }); stompClient.subscribe('/topic/greetings', function (greeting) { console.log(JSON.parse(greeting.body).content); }); stompClient.subscribe('/topic/news', function (greeting) { console.log(JSON.parse(greeting.body).content); }); }); }
To Disconnect
function disconnect() { if (stompClient !== null) { stompClient.disconnect(); } setConnected(false); console.log("Disconnected"); }
To Send
We have mapped /hello
to one of our method in the controller. Since we set /app
as prefix, we need to do the following:
stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()}));
To Receive
We have already setup those callback functions while we subscribe the channels during the connection.
Notes
- The websocket has a default 25 second keep-a-live package.
- The socket will auto disconnect when the browser/tab is closed.