使用 Spring 介绍 WebSockets


转载内容 如有侵权 或 不希望被转载 可以留言或私发告诉我,我会及时处理,尊重你的权利。
原文地址:[https://www.baeldung.com/websockets-spring]

*通过参考Learn Spring*课程开始使用 Spring 5 和 Spring Boot 2 :

>> 学习春天

一、概述

在本文中,我们将创建一个简单的 Web 应用程序,该应用程序使用Spring Framework 4.0 引入的新 WebSocket 功能实现消息传递。

WebSockets 是Web 浏览器和服务器之间的双向全双工持久连接。建立 WebSocket 连接后,连接将保持打开状态,直到客户端或服务器决定关闭此连接。

一个典型的用例可能是当应用程序涉及多个用户相互通信时,例如在聊天中。我们将在示例中构建一个简单的聊天客户端。

2.Maven依赖

由于这是一个基于 Maven 的项目,我们首先将所需的依赖项添加到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>

此外,由于我们将使用JSON来构建消息正文,因此我们需要添加Jackson依赖项。这允许 Spring 将我们的 Java 对象转换为 JSON 或从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>

如果您想获得上述库的最新版本,请在Maven Central上查找它们。

3. 在 Spring 中启用 WebSocket

首先要做的是启用 WebSocket 功能。为此,我们需要向应用程序添加配置并使用*@EnableWebSocketMessageBroker*注释此类。

顾名思义,它启用了由消息代理支持的 WebSocket 消息处理:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

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

在这里,我们可以看到configureMessageBroker方法用于配置消息代理。首先,我们启用内存中的消息代理将消息传送回客户端,目的地为前缀为“/topic”。

我们通过指定“ / app”前缀来完成我们的 简单配置,以过滤针对应用程序注释方法的目标(通过@MessageMapping)。

registerStompEndpoints方法注册“ /chat”端点,启用Spring 的STOMP支持。请记住,为了弹性,我们还在此处添加了一个无需 SockJS 即可工作的端点。

此端点以“/app”为前缀,是*ChatController.send()*方法映射到处理的端点。

它还启用了SockJS回退选项,因此如果 WebSocket 不可用,则可以使用替代消息传递选项。这很有用,因为并非所有浏览器都支持 WebSocket,并且可能会被限制性网络代理排除。

回退让应用程序使用 WebSocket API,但在运行时必要时优雅地降级为非 WebSocket 替代方案。

4. 创建消息模型

现在我们已经设置了项目并配置了 WebSocket 功能,我们需要创建要发送的消息。

端点将接受包含发件人姓名和正文为JSON对象的 STOMP 消息中的文本的消息。

消息可能如下所示:

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

为了对携带文本的消息进行建模,我们可以创建一个带有fromtext属性的简单 Java 对象:

public class Message {

    private String from;
    private String text;

    // getters and setters
}

默认情况下,Spring 将使用Jackson库将我们的模型对象与 JSON 进行转换。

5. 创建一个消息处理控制器

正如我们所见,Spring 使用 STOMP 消息传递的方法是将控制器方法与配置的端点相关联。这是通过*@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);
}

F或我们示例的目的 ,我们将创建另一个名为OutputMessage的模型对象来表示发送到配置的目标的输出消息。我们使用发送者和从传入消息中获取的消息文本填充我们的对象,并使用时间戳来丰富它。

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

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("Disconnected");
            }
            
            function sendMessage() {
                var from = document.getElementById('from').value;
                var text = document.getElementById('text').value;
                stompClient.send("/app/chat", {}, 
                  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 + ": " 
                  + messageOutput.text + " (" + messageOutput.time + ")"));
                response.appendChild(p);
            }
        </script>
    </head>
    <body onload="disconnect()">
        <div>
            <div>
                <input type="text" id="from" placeholder="Choose a nickname"/>
            </div>
            <br />
            <div>
                <button id="connect" onclick="connect();">Connect</button>
                <button id="disconnect" disabled="disabled" onclick="disconnect();">
                    Disconnect
                </button>
            </div>
            <br />
            <div id="conversationDiv">
                <input type="text" id="text" placeholder="Write a message..."/>
                <button id="sendMessage" onclick="sendMessage();">Send</button>
                <p id="response"></p>
            </div>
        </div>

    </body>
</html>

7. 测试示例

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

http://localhost:8080

完成后,我们可以通过输入昵称并点击连接按钮来加入聊天。如果我们撰写并发送消息,我们可以在所有加入聊天的浏览器会话中看到它。

查看屏幕截图以查看示例:

img

8. 结论

在本教程中,我们探索了Spring 的 WebSocket 支持。我们已经看到了它的服务器端配置,并使用sockjsstomp Javascript 库构建了一个简单的客户端对应物。

示例代码可以在GitHub 项目中找到。


文章作者: Kevin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Kevin !
评论
  目录