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  and its child tags. The tag websocket:simple-brokerindicates we are using an in-memory message broker.

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

  1. As you see, you can get the session of WebSocket in authorizationAction with SimpMessageHeaderAccessor.
  2. The @SendToUser annotation allows you to send messages to a specific subscriber. And you must set up user-destination-prefix in the configuration file.
  3. 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);
  }
);

Reference

The Disqus comment system is loading ...
If the message does not appear, please check your Disqus configuration.