An overview of the

This article is the second in a five-part WebSocket story series that aims to provide a step-by-step introduction to WebSocket and how to quickly build and use the capabilities WebSocket provides in Springboot. This series is planned to include the following articles:

Part 1: What WebSocket is and what it Does Part 2: How to Use STOMP to Quickly Build WebSocket broadcast message Patterns in Spring In Springboot, how to use WebSocket and STOMP to quickly build point-to-point messaging mode (2) in Springboot, how to implement custom WebSocket message proxy in web chat rooms

The main line of this article

Continuing the introduction of WebSocket above, starting with the sending and receiving information of WebSocket, STOMP protocol is briefly introduced. Finally, a WebSocket example is actually written by Springboot and JS to realize broadcast message sending.

This article is suitable for readers

Students who want to learn about STOMP and how to build WebSocket services using Springboot.


The essential

In the last article, we looked at the WebSocket handshake process. We didn’t go into the details of sending messages, but we mentioned that WebSocket sending is done in frames. The WebSocket protocol does not specify the detailed format for sending messages. That means that every developer using WebSocket needs to define their own set of rules on the server and client side to transfer information. So, are there any wheels that have been built? The answer must be yes. This is STOMP.

Introduction to STOMP(Simple Text Oriented Messaging Protocol)

STOMP is a Simple Text Protocol (Simple Text Oriented Messaging Protocol) for asynchronous message transfer between C/S.

STOMP official website

STOMP was not designed for WS, but is a protocol for message queues, parallel to AMQP and JMS. It just happens to be simple enough to define the message physique of WS. Many server message queues already support STOMP, such as RabbitMQ, Apache ActiveMQ, etc. Many languages also have client parsing libraries for STOMP, such as Gozirra for JAVA, libstomp for C, PyActivemQ for Python, stomp.js for JavaScript, and so on.

STOMP deals

STOMP is a frame-based protocol where a frame consists of a command, an optional set of headers, and an optional Body. STOMP is text-based, but also allows the transfer of binary data. Its default encoding is UTF-8, but its message body also supports other encoding methods, such as compression encoding.

STOMP the service side

The STOMP server is designed as a set of destination addresses to which clients can send messages. STOMP does not specify the format of the destination address. It is defined by the application that uses the protocol. For example, /topic/a, /queue/a, and queue-a are all correct for STOMP. The application can specify its own format to indicate what the format represents. For example, the application itself can define a publish-subscribe mode starting with /topic, where messages are received by all consumer clients, and a peer-to-peer mode starting with /user, where messages are received by only one consumer client.

STOMP client

For STOMP, clients play either of the following two roles:

  • As a producer, a message is sent to the specified address through an SEND frame
  • A consumer subscribes to a MESSAGE by sending a SUBSCRIBE frame to a known address, and when a producer sends a MESSAGE to that address, other consumers subscribing to that address receive the MESSAGE through a MESSAGE frame

In effect, WebSocket in combination with STOMP builds a message distribution queue where clients can switch between the two roles. A subscription mechanism ensures that a client message can be broadcast from the server to multiple other clients, and that the server can be used as a producer to send peer-to-peer messages.

STOMP frame structure

COMMAND

header1:value1

header2:value2

Body^@

^@ represents the end-of-line character

A STOMP frame consists of three parts: command, Header(Header information), and Body (message Body).

  • The commands are in UTF-8 format and include SEND, SUBSCRIBE, MESSAGE, CONNECT, and CONNECTED.
  • Header also uses UTF-8 encoding format, which is similar to HTTP Header, including content-Length and content-type.
  • The Body can be binary or text. Notice that the Body and Header are separated by a blank line (EOL).

Let’s look at an example of a frame in action:

SEND destination: / broker/roomId / 1 content – length: 57 {” type “:” ENTER “, “content” : “o7jD64gNifq wq – C13Q5CRisJx5E}”

  • Line 1: Indicates that this frame is an SEND frame and is the COMMAND field.
  • Line 2: Header field, the destination address to which the message is sent, is the relative address.
  • Line 3: Header field, message body character length.
  • Line 4: Empty line, separating Header and Body.
  • Line 5: The message body, which is a custom JSON structure.

For more details on STOMP, if you are interested, please refer to the above official web page for more detailed frame structure. Next, we will mainly introduce the implementation of Springboot and JS back-end and front-end, building a small application scenario of WebSocket.


Use Springboot to build STOMP – based WebSocket broadcast communication

WebSocket architecture in Spring

Architecture diagram

Each component in the figure is introduced:

  • Producer client (upper left component) : a client that sends a SEND command to a destination.
  • Consumer client (lower left component) : A client that subscribes to a destination address and receives messages pushed from that destination address.
  • Request Channel: A pool of threads used to receive messages pushed by producer clients.
  • Response Channel: A pool of threads used to push messages to consumer clients.
  • Broker: A message queue manager that can also be a message broker. It has its own address (for example, “/topic”) to which the client can send subscriptions, and it keeps track of which subscriptions to that destination.
  • Application destination address (” /app “in the figure): Messages sent to such destination addresses are routed to a method written by the application before reaching the broker. This acts as an interception of messages entering the broker in order to do some business on the message.
  • Non-application destination address (” /topic “in the figure, which is also a message broker address): Messages sent to these destination addresses are forwarded directly to the broker. Will not be blocked by the application.
  • SimpAnnotatonMethod: Method by which messages sent to the application destination address are routed before reaching the broker. This part of the code is controlled by the application.

The flow of messages from producers to consumers for consumption

First, the producer sends an SEND command message to a destination address. The server request channel receives the SEND command message. If the destination address is the destination address of the application, it is processed by the corresponding business method written by the application (corresponding to SimpAnnotationMethod in the figure) and then transferred to the SimpleBroker (SimpleBroker). If the destination address is not the application destination address, go directly to the broker. The broker constructs MESSAGE command messages using SEND command messages, and pushes MESSAGE command messages through response Channels to all consumers subscribed to the destination address. Without further ado, let’s go straight to the code.

Spring uses WebSocket for simple broadcast messages

Scene description

Let’s implement the first step of a simple chat room. Each time a user joins a chat room, the user sends a message to the server to join the chat room, and the server sends a welcome message to all users in the current chat room.

Create a Message – handling for the Controller

In Spring, STOMP messages are routed to classes identified with Controller annotations. That is, we need to define a Controller class, identify it with the Controller annotation, and implement the specific message handling methods in it. We create a class called GreetingController:

package com.xnpe.club.wbs.controller; import com.xnpe.club.wbs.data.Greeting; import com.xnpe.club.wbs.data.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; Public class GreetingController {@messagemapping ("/hello") // Use MessageMapping to indicate that all messages sent to the destination "/hello" will be routed to this method for processing. @sendto ("/topic/greetings") // Use the SendTo annotation to indicate that the result returned by this method will be sent to its destination, "/topic/greetings". public Greeting greeting(HelloMessage message) throws Exception { Thread.sleep(1000); // Simulate processing delayreturn new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!"); // Based on the incoming information, a welcome message is returned.Copy the code

Overall, the greeting() method processes all messages sent to the/Hello destination and sends the results to all clients subscribed to the /topic/greetings destination. The essence of the simulated delay is to demonstrate that in WebSocket, we do not need to consider the problem of timeout. That is, as mentioned in the previous article, after the connection between the client and the server is established, the server can “push” the message to the client “whenever necessary” according to the actual situation, until the connection is released.

Configure STOMP messages for Spring

We have just created the message processing controller, which is our business processing logic. Now we need to configure the WebSocket and STOMP message Settings for Spring. Create a class called WebSocketController:

package com.xnpe.club.wbs.config; 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 / / using the Configuration identifier - this is a commentary Springboot Configuration class. @ EnableWebSocketMessageBroker / / use this annotation to identify can make WebSocket broker. Which USES the broker to process the message. The public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {@ Override / / implementation WebSocketMessageBrokerConfigurer in this method, Configure the message broker (broker) public void configureMessageBroker (MessageBrokerRegistry config) {config. EnableSimpleBroker ("/topic"); // Enable SimpleBroker to subscribe to this"topic"Prefix the client can receive the greeting message. Config. SetApplicationDestinationPrefixes ("/app"); / / will be"app"The prefix is bound to the method specified by the MessageMapping annotation. Such as"app/hello"Override // registers the Endpoint, where "/gs-guide-websocket" is the address the client is trying to establish a connection to. public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/gs-guide-websocket").withSockJS(); }}Copy the code

The configuration consists of two parts, one is the message broker and the other is the Endpoint. The message broker specifies the client subscription address and the routing address for sending messages. The Endpoint specifies the address that the client requests when establishing a connection.

At this point, the server configuration is complete and very simple. Now, let’s implement a front end page to verify that the service works.

Create the front-end implementation page

For STOMP, we use the JavaScript STOMP client to implement stomp.js and WebSocket to implement SockJS on the front end. Only the core code is shown here.

// Use SockJS and stomp.js to open the connection to the "gs-guide-webSocket" address, which is the SockJS service we built with Spring.function connect() {
    var socket = new SockJS('/gs-guide-websocket');
    stompClient = Stomp.over(socket);
    stompClient.connect({}, function(frame) {// Callback method after successful connectionsetConnected(true);
        console.log('Connected: '+ frame); // Subscribe /topic/greetings address to which the client receives messages when the server sends them. stompClient.subscribe('/topic/greetings'.function(greeting) {// A callback method to display a welcome message when a message is received. showGreeting(JSON.parse(greeting.body).content); }); }); } // The method of disconnectingfunction disconnect() {
    if(stompClient ! == null) { stompClient.disconnect(); }setConnected(false);
    console.log("Disconnected"); } // Send the name information entered by the user to the "/app/hello" address using STOMP client. This is the address that the greeting() method we defined in the GreetingController handles.function sendName() {
    stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()}));
}

Copy the code

demo


Reference code

This example implementation code link address: SpringWebSocket Github


conclusion

So far, we have implemented the simplest WebSocket example using Spring, STOMP based. In the next article, we will continue to improve the chat room function based on this example, and implement the point-to-point communication function. That is, how two users chat point-to-point, stay tuned.


Xiaoming produced, must be a boutique

Welcome to pay attention to xNPE technology forum, more original dry goods daily push.