SpringBoot actual combat (16) | integration of WebSocket to realize broadcast message based on STOMP protocol

  java-web, springboot, websocket

Preface

For example, today’s introduction is SpringBoot’s integration of WebSocket to realize broadcast messages.

What is WebSocket?

WebSocket provides a duplex asynchronous communication function for the browser and the server, that is, the browser can send information to the server, and vice versa.

Websocket realizes duplex asynchronous communication capability through a Socket. However, it is very tedious to directly use the WebSocket (or SOCKJS: simulation of the WebSocket protocol, adding compatible support that the current browser does not support using Web Socket) protocol development program, so it uses its sub-protocol STOMP.

Brief Introduction of STOMP Protocol

It is an advanced streaming text oriented message protocol and a simple text protocol designed for MOM (Message Oriented Middleware).

It provides an interoperable connection format that allows STOMP clients to interact with any STOMP message Broker, similar to OpenWire (a binary protocol).

Because of its simple design and easy development of clients, it is widely used in many languages and platforms. The most popular STOMP message broker is Apache ActiveMQ.

The STOMP protocol uses a frame-based format to define messages, similar to Http’s request and response.

Radio

Next, a demo of broadcast messages is implemented. That is, when the server has a message, it sends the message to all browsers connected to the current endpoint.

Preparatory work

  • SpringBoot 2.1.3
  • IDEA
  • JDK8

Pom dependent configuration

<dependencies>
        <!-- thymeleaf 模板引擎 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- web 启动类 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- WebSocket 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <!-- test 单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

The code comments are very detailed, not much said.

Configure WebSocket

Implement WebSocketMessageBrokerConfigurator interface, register a STOMP node and configure a broadcast message proxy

@Configuration
// @EnableWebSocketMessageBroker注解用于开启使用STOMP协议来传输基于代理(MessageBroker)的消息,这时候控制器(controller)
// 开始支持@MessageMapping,就像是使用@requestMapping一样。
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        //注册一个 Stomp 的节点(endpoint),并指定使用 SockJS 协议。
        registry.addEndpoint("/endpointNasus").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // 广播式配置名为 /nasus 消息代理 , 这个消息代理必须和 controller 中的 @SendTo 配置的地址前缀一样或者全匹配
        registry.enableSimpleBroker("/nasus");
    }
}

Message class

Client sends to server:

public class Client2ServerMessage {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

The server sends to the client:

public class Server2ClientMessage {

    private String responseMessage;

    public Server2ClientMessage(String responseMessage) {
        this.responseMessage = responseMessage;
    }

    public String getResponseMessage() {
        return responseMessage;
    }

    public void setResponseMessage(String responseMessage) {
        this.responseMessage = responseMessage;
    }
}

Demo controller code

@RestController
public class WebSocketController {

    @MessageMapping("/hello") // @MessageMapping 和 @RequestMapping 功能类似,浏览器向服务器发起消息,映射到该地址。
    @SendTo("/nasus/getResponse") // 如果服务器接受到了消息,就会对订阅了 @SendTo 括号中的地址的浏览器发送消息。
    public Server2ClientMessage say(Client2ServerMessage message) throws Exception {
        Thread.sleep(3000);
        return new Server2ClientMessage("Hello," + message.getName() + "!");
    }

}

Introducing STOMP scripts

Put stomp.min.js (STOMP client script) and sockJS.min.js (sockJS client script) and Jquery in the static directory of the resource folder.

Presentation page

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>Spring Boot+WebSocket+广播式</title>

</head>
<body onload="disconnect()">
<noscript><h2 style="color: #ff0000">貌似你的浏览器不支持websocket</h2></noscript>
<div>
    <div>
        <button id="connect" onclick="connect();">连接</button>
        <button id="disconnect" disabled="disabled" onclick="disconnect();">断开连接</button>
    </div>
    <div id="conversationDiv">
        <label>输入你的名字</label><input type="text" id="name" />
        <button id="sendName" onclick="sendName();">发送</button>
        <p id="response"></p>
    </div>
</div>
<script th:src="@{sockjs.min.js}"></script>
<script th:src="@{stomp.min.js}"></script>
<script th:src="@{jquery.js}"></script>
<script type="text/javascript">
    var stompClient = null;

    function setConnected(connected) {
        document.getElementById('connect').disabled = connected;
        document.getElementById('disconnect').disabled = !connected;
        document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';
        $('#response').html();
    }
    
    function connect() {
        // 连接 SockJs 的 endpoint 名称为 "/endpointNasus"
        var socket = new SockJS('/endpointNasus'); 
        // 使用 STOMP 子协议的 WebSocket 客户端
        stompClient = Stomp.over(socket); 
        stompClient.connect({}, function(frame) {
            setConnected(true);
            console.log('Connected: ' + frame);
            // 通过 stompClient.subscribe 订阅 /nasus/getResponse 目标发送的信息,对应控制器的 SendTo 定义
            stompClient.subscribe('/nasus/getResponse', function(respnose){
            // 展示返回的信息,只要订阅了 /nasus/getResponse 目标,都可以接收到服务端返回的信息
            showResponse(JSON.parse(respnose.body).responseMessage);
            });
        });
    }
    
    
    function disconnect() {
        // 断开连接
        if (stompClient != null) {
            stompClient.disconnect();
        }
        setConnected(false);
        console.log("Disconnected");
    }

    function sendName() {
        // 向服务端发送消息
        var name = $('#name').val();
        // 通过 stompClient.send 向 /hello (服务端)发送信息,对应控制器 @MessageMapping 中的定义
        stompClient.send("/hello", {}, JSON.stringify({ 'name': name }));
    }

    function showResponse(message) {
          // 接收返回的消息
          var response = $("#response");
          response.html(message);
    }
</script>
</body>
</html>

Page Controller

Note that the @Controller annotation is used here to match the html prefix and load the page.

@Controller
public class ViewController {

    @GetMapping("/nasus")
    public String getView(){
        return "nasus";
    }
}

test result

Open three windows to accesshttp://localhost: 8080/nasus, initial page length is as follows:

初始页面

All three pages are connected. Click Connect to subscribe to endpoint, as shown in the following figure:

点击连接订阅 endpoint

点击连接订阅 endpoint

点击连接订阅 endpoint

On the first page, enter the name and click Send, as shown in the following figure:

输入名字,点发送

Send a message on the first page and wait for 3 seconds. As a result, all 3 pages have received the information returned by the server and the broadcast was successful.

第一个页面结果

第二个页面结果

第三个页面结果

Source code download:

https://github.com/turoDog/De …

If you think it is helpful to you, please give a Star before you leave. thank you very much.

Postscript

If this article is of any help to you, please help me look good. Your good looks are my motivation to persist in writing.

In addition, after the attention is sent1024Free study materials are available.

For details, please refer to this old article:Python, C++, Java, Linux, Go, Front End, Algorithm Data Sharing

一个优秀的废人,给你讲几斤技术