This guide walks you through the process of creating a “hello world” application that sends messages back and forth, between a browser and the server. WebSocket is a very thin, lightweight layer above TCP. It makes it very suitable to use “subprotocols” to embed messages. In this guide, we’ll dive in and use STOMP messaging with Spring to create an interactive web application.
Maven Dependencies
First, we need to add the Spring messaging modules in the POM file:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
Spring MVC Configuration
Next, we need to add the message broker config to the Spring MVC config XML file.
<beans
...
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
...
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket-4.1.xsd">
<websocket:message-broker
application-destination-prefix="/app"
user-destination-prefix="/user">
<websocket:stomp-endpoint path="/websocket">
<websocket:handshake-interceptors>
<bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
</websocket:handshake-interceptors>
<websocket:sockjs session-cookie-needed="true" />
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic, /message" />
</websocket:message-broker>
<!-- Other MVC config omitted here-->
</beans>
The main thing here is the setup of the message broker for handling the message exchange between the server and its clients. This is done via the
The HttpSessionHandshakeInterceptor is used to get sessions in the WebSocket. By default, the session will not bring to the WebSocket request.
It is easy to understand together with the server and client codes so I will include them below first before attempting to give a bit more explanations by cross-referencing the client and server codes.
Spring MVC Controller
@Controller
public class WebSocketController {
@MessageMapping("/authorization.action")
@SendToUser("/message/authorization")
public Message authorizationAction(
SimpMessageHeaderAccessor headerAccessor, Message message) {
String csrfToken = message.getValue();
Map <String, Object> sessionAttributes = headerAccessor.getSessionAttributes();
Boolean isCsrfTokenValid = CsrfProtector.isCsrfTokenValid(csrfToken, sessionAttributes);
return new Message("isCsrfTokenValid", isCsrfTokenValid.toString());
}
@SubscribeMapping("/getRealTimeJudgeResult.action/{submissionId}")
public Message getRealTimeJudgeResultAction(
@DestinationVariable long submissionId) {
return new Message("Key", "Value # " + submissionId);
}
/* Inner Class for Messaging */
private static class Message implements Serializable {
public Message() {}
public Message(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
private String key;
private String value;
private static final long serialVersionUID = -3430525797548136557 L;
}
}
Some explanation
- As you see, you can get the session of WebSocket in
authorizationAction
withSimpMessageHeaderAccessor
. - The
@SendToUser
annotation allows you to send messages to a specific subscriber. And you must set upuser-destination-prefix
in the configuration file. - The
@DestinationVariable
annotation allows you to pass a parameter to a method, and you can return something relative to the subscriber.
Client sockJS and STOMP codes
var socket = new SockJS('<c:url value="/websocket" />'),
stompClient = Stomp.over(socket);
stompClient.connect(
{},
function (frame) {
hasConntected = true;
displayWebSocketConnectionStatus(true, hasConntected);
stompClient.send(
"/app/authorization.action",
{},
JSON.stringify({
key: "csrfToken",
value: "${csrfToken}"
})
);
stompClient.subscribe("/user/message/authorization", function (message) {
console.log(message);
});
stompClient.subscribe(
"/app/getRealTimeJudgeResult.action/${submissionId}",
function (message) {
console.log(message);
}
);
},
function () {
return displayWebSocketConnectionStatus(false, hasConntected);
}
);
The Disqus comment system is loading ...
If the message does not appear, please check your Disqus configuration.