51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Spring WebSocket 简介

1、概览 {#1概览}

本文将带你学习如何使用 Spring 4 中引入的 WebSocket 功能来实现一个简单的聊天应用。

WebSockets 是 Web 浏览器和服务器之间的一种双向、全双工、持久连接。一旦建立了 WebSocket 连接,该连接就会一直打开,直到客户端或服务器关闭该连接。

2、Maven 依赖 {#2maven-依赖}

pom.xml 中添加所需的依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>5.2.2.RELEASE</version> </dependency>

此外,还需要添加 Jackson 依赖,用于序列化/反序列化 JSON 格式的消息。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.10.2</version>
</dependency>

<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.10.2</version> </dependency>

3、启用 WebSocket {#3启用-websocket}

首先,在配置类上通过 @EnableWebSocketMessageBroker 注解来启用 WebSocket 功能。

配置类需要继承 AbstractWebSocketMessageBrokerConfigurer

顾名思义,它能在 Message Broker 的支持下处理 WebSocket 消息:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
    config.enableSimpleBroker(&quot;/topic&quot;);
    config.setApplicationDestinationPrefixes(&quot;/app&quot;);
}

@Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint(&quot;/chat&quot;); registry.addEndpoint(&quot;/chat&quot;).withSockJS(); }

}

如上,通过 configureMessageBroker 方法配置 Message Broker。

首先,启用了一个基于内存的 Message Broker,用于将消息返回给以 /topic 为前缀的客户端目标。

设置应用目标(通过 @MessageMapping 注解的方法)的前缀为 /app

registerStompEndpoints 方法注册了/chat 端点,从而启用了 Spring 的 STOMP 支持。这里为了提高灵活性,还添加了 SockJS 的支持,但是本文不会使用。

该端点(前缀为 /app 时)是 ChatController.send() 方法映射处理的端点。

启用 SockJS 回退选项,以便在无法使用 WebSockets 时使用其他消息传递选项。这一点非常有用,因为 WebSocket 在某些浏览器中尚未得到支持,并且可能受到限制性网络代理的阻止。

当需要时,回退功能允许应用在运行时优雅地降级到非 WebSocket 的替代方案,同时仍然可以使用 WebSocket API。

4、创建 Message Model {#4创建-message-model}

配置好 WebSocket 后,创建要发送的消息。

端点接受包含发送人和文本的 STOMP 消息,该消息是一个 JSON 对象。

{
    "from": "John",
    "text": "Hello!"
}

其对应的 Model 类如下:

public class Message {
private String from;
private String text;

// get、set 省略

}

默认情况下,Spring 使用 Jackson 将 Model 对象转换为 JSON 或从 JSON 转换为 Model 对象。

5、创建消息处理 Controller {#5创建消息处理-controller}

如你所见,Spring 处理 STOMP 消息的方法是将 Controller 方法与配置的端点关联起来。

可以通过 @MessageMapping 注解来做到这一点。

@MessageMapping("/chat")
@SendTo("/topic/messages")
public OutputMessage send(Message message) throws Exception {
    String time = new SimpleDateFormat("HH:mm").format(new Date());
    return new OutputMessage(message.getFrom(), message.getText(), time);
}

在本例中,创建了另一个名为 OutputMessage 的 Model 对象来表示发送到配置目的地的输出消息,并在对象中填充发件人(sender)和从传入消息中提取的消息内容,以及一个时间戳。

处理完消息后,会将其发送到使用 @SendTo 注解定义的适当目的地。/topic/messages 目标的所有订阅者都将收到该消息。

6、创建浏览器客户端 {#6创建浏览器客户端}

服务器配置完毕后,使用 sockjs-client 库构建一个与消息系统交互的简单 HTML 页面。

首先,需要导入 sockjsstomp JavaScript 客户端库。

接下来,创建一个 connect() 函数来打开与端点的通信,创建一个 sendMessage() 函数来发送 STOMP 消息,创建一个 disconnect() 函数来关闭通信:

<html>
    <head>
        <title>Chat WebSocket</title>
        <script src="resources/js/sockjs-0.3.4.js"></script>
        <script src="resources/js/stomp.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';
            document.getElementById('response').innerHTML = '';
        }
    function connect() {
        var socket = new SockJS('/chat');
        stompClient = Stomp.over(socket);  
        stompClient.connect({}, function(frame) {
            setConnected(true);
            console.log('Connected: ' + frame);
            stompClient.subscribe('/topic/messages', function(messageOutput) {
                showMessageOutput(JSON.parse(messageOutput.body));
            });
        });
    }
    
    function disconnect() {
        if(stompClient != null) {
            stompClient.disconnect();
        }
        setConnected(false);
        console.log(&amp;quot;Disconnected&amp;quot;);
    }
    
    function sendMessage() {
        var from = document.getElementById('from').value;
        var text = document.getElementById('text').value;
        stompClient.send(&amp;quot;/app/chat&amp;quot;, {}, 
          JSON.stringify({'from':from, 'text':text}));
    }
    
    function showMessageOutput(messageOutput) {
        var response = document.getElementById('response');
        var p = document.createElement('p');
        p.style.wordWrap = 'break-word';
        p.appendChild(document.createTextNode(messageOutput.from + &amp;quot;: &amp;quot; 
          + messageOutput.text + &amp;quot; (&amp;quot; + messageOutput.time + &amp;quot;)&amp;quot;));
        response.appendChild(p);
    }
&amp;lt;/script&amp;gt;

&lt;/head&gt; &lt;body onload=&quot;disconnect()&quot;&gt; &lt;div&gt; &lt;div&gt; &lt;input type=&quot;text&quot; id=&quot;from&quot; placeholder=&quot;Choose a nickname&quot;/&gt; &lt;/div&gt; &lt;br /&gt; &lt;div&gt; &lt;button id=&quot;connect&quot; onclick=&quot;connect();&quot;&gt;Connect&lt;/button&gt; &lt;button id=&quot;disconnect&quot; disabled=&quot;disabled&quot; onclick=&quot;disconnect();&quot;&gt; Disconnect &lt;/button&gt; &lt;/div&gt; &lt;br /&gt; &lt;div id=&quot;conversationDiv&quot;&gt; &lt;input type=&quot;text&quot; id=&quot;text&quot; placeholder=&quot;Write a message...&quot;/&gt; &lt;button id=&quot;sendMessage&quot; onclick=&quot;sendMessage();&quot;&gt;Send&lt;/button&gt; &lt;p id=&quot;response&quot;&gt;&lt;/p&gt; &lt;/div&gt; &lt;/div&gt;

&lt;/body&gt;

</html>

7、测试 {#7测试}

为了测试,可以多打开几个浏览器窗口并访问聊天页面:

http://localhost:8080

输入昵称并点击连接按钮后,就可以加入聊天了。此时撰写并发送一条消息,就可以在所有已加入聊天的浏览器会话中看到它。

效果如下:

websockets 聊天客户端

8、总结 {#8总结}

本文介绍了 Spring 的 WebSocket 支持,以及如何使用 sockjs 和 stomp JavaScript 库构建了一个简单的客户端应用。


Ref:https://www.baeldung.com/websockets-spring

赞(7)
未经允许不得转载:工具盒子 » Spring WebSocket 简介