SpringBoot、Vue3 整合 WebSocket

WebSocket

WebSocket 是一种计算机通信协议,用于在Web应用程序中实现双向通信。它允许服务器和客户端之间建立持久连接,并且可以通过单个网络套接字进行全双工通信。与传统的HTTP请求-响应模型不同,WebSocket 使用事件驱动的模式,可以实时地在服务器和客户端之间传输数据。

WebSocket 协议的特点包括:

  • • 建立持久连接:WebSocket 连接在创建后保持打开状态,而不需要每次通信都重新建立连接。这降低了通信的延迟和资源消耗。
  • • 全双工通信:服务器和客户端可以同时发送和接收数据,实现真正的双向通信。这使得服务器可以主动推送数据给客户端,而不仅仅是在请求时响应数据。
  • • 低延迟:由于 WebSocket 连接始终保持打开状态,消息的传输延迟较小。这对于实时应用程序(如聊天应用、股票市场数据等)非常重要。
  • • 跨域支持:WebSocket 协议支持跨域通信,即在不同域名或端口的服务器之间进行通信。

WebSocket 在 Web 应用程序中有广泛的应用,例如实时聊天应用、在线游戏、股票市场数据推送、在线协作等。它提供了一种更高效、实时的通信方式,同时减少了服务器和客户端之间的网络负载。

SpringBoot 整合 WebSocket

添加依赖

代码语言:javascript
复制
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
</dependencies>

WebSocketServer

代码语言:javascript
复制
package com.demo.websocket;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

/**

  • @ClassName: WebSocketServer.java

  • @ClassPath: com.demo.websocket.WebSocketServer.java

  • @Description: WebSocket

  • @Author: tanyp

  • @Date: 2023-09-05 10:35
    **/
    @Slf4j
    @ServerEndpoint("/ws/{id}")
    @Component
    public class WebSocketServer {

    public static CopyOnWriteArraySet<WebSocketServer> sessionSet = new CopyOnWriteArraySet<>();

    private Session session;

    @Getter
    private String id;

    @OnOpen
    public void onOpen(Session session, @PathParam("id") String id) {
    log.info("=======WebSocket 建立连接 id:{}==============", id);
    this.session = session;
    this.id = id;
    sessionSet.add(this);
    }

    @OnClose
    public void onClose() {
    sessionSet.remove(this);
    }

    @OnError
    public void onError(Session session, Throwable error, @PathParam("id") String id) {
    log.error("========websocket错误================");
    error.printStackTrace();
    if (StringUtils.isNotBlank(id)) {
    for (WebSocketServer ws : sessionSet) {
    if (ws.id.equals(id)) {
    sessionSet.remove(ws);
    }
    }
    }
    }

    public void sendMessage(String message) throws IOException {
    this.session.getBasicRemote().sendText(message);
    }

    public synchronized static void sendMessage(@PathParam("id") String id, String message) throws IOException {
    if (StringUtils.isNotBlank(id)) {
    for (WebSocketServer ws : sessionSet) {
    if (ws.id.equals(id)) {
    ws.sendMessage(message);
    }
    }
    }
    }

}

推送数据

代码语言:javascript
复制
// websocket 推送数据
String prefix = "test-"; // 前缀
String sequence = "u0001"; // 唯一序列,例如:用户ID
String json = JSON.toJSONString({}); // JSON 数据
try {
WebSocketServer.sendMessage(prefix + sequence, json);
} catch (Exception e) {
log.error("websocket 推送数据异常:{}", e);
}

Vue3 使用 WebSocket

代码语言:javascript
复制
<script setup lang="ts">
import { onMounted, reactive,toRefs } from 'vue'

const state = reactive({
    socket: null,
})

const {socket} = toRefs(state)

onMounted(()=&gt;{
    webSocket()
})

function webSocket(){
    if (&#39;WebSocket&#39; in window) {
        // 与后端配置保持一致(IP + 端口 + &#34;/ws/&#34; + 前缀 + 唯一序列)
        state.socket = new WebSocket(&#39;ws:&#39; + window.location.hostname+&#39;:8080/ws/test-u0001&#39;);

        state.socket.onmessage = function (event:any) {
            // 接收数据,更具业务自行处理
            console.log(event.data)
        }

        state.socket.onopen = function () {
            console.log(&#39;连接已建立&#39;)
        }

        state.socket.onclose = function () {
            console.log(&#39;连接已关闭&#39;)
        }

        state.socket.onerror = function () {
            console.log(&#39;连接异常,尝试重新连接&#39;)
            // webSocket();
        }

        window.onbeforeunload = function () {
            state.socket.onclose();
        }
    }
} 

</script>

注:一定确保 WebSocket 连接的地址与后端配置的地址相匹配(IP + 端口 + "/ws/" + 前缀 + 唯一序列)。例如:http://127.0.0.1/ws/test-u0001