springBootプロジェクト+websocket+vueで双方向通信を実現

目次

1. WebSocket プロトコルを理解する

WebSocketの機能

      リアルタイム通信:

       双方向コミュニケーション:

       長い接続:

        クロスドメイン通信:

2. バックエンドコードの実装

Maven の依存関係を導入する

WebSocketConfig

WebSocketConfig 関数:

WebSocketConfig.java コード

MyWebSocket

@アノテーションの説明

MyWebSocket 関数:

MyWebSocket.java コード

3. サーバーが正常に接続されているかどうかをテストします

1. WebSocket テスト ガジェットを開きます

2. 以下に示すように、テスト ガジェットにアクセス アドレスを入力し、[接続] をクリックします。

編集

4. フロントエンドコードの実装

5. エフェクト表示編集


1. WebSocket プロトコルを理解する

        WebSocket は、リアルタイム通信機能を提供するように設計された全二重の長時間接続通信プロトコルです。 WebSocket を使用する前に、WebSocket プロトコルの基本知識を学習することをお勧めします。

WebSocketの機能

      リアルタイム通信:

        WebSocket は、クライアントとサーバー間のリアルタイム通信のメカニズムを提供します。従来の HTTP リクエスト/レスポンス モデルとは異なり、WebSocket を使用すると、クライアントがリクエストを開始する必要がなく、サーバーがクライアントにメッセージをアクティブにプッシュできます。これにより、ライブ チャット、リアルタイム データ更新などのリアルタイム アプリケーションが可能になります。

       双方向コミュニケーション:

        WebSocket は双方向通信を実現でき、クライアントとサーバーは同時にメッセージを送受信できます。クライアント側でもサーバー側でも、リアルタイムの更新、通知、応答を目的としてメッセージを送信できます。これにより、開発者は対話型で応答性の高いアプリケーションを簡単に構築できるようになります。

       長い接続:

        従来の HTTP リクエスト/レスポンス モデルでは短い接続が使用されます。つまり、リクエストごとに新しい接続を確立し、接続を閉じる必要があります。対照的に、WebSocket は存続期間の長い接続を使用します。これは、単一の接続が有効なままであり、複数のメッセージを送信できることを意味します。これにより、接続の確立と終了のオーバーヘッドが軽減され、ネットワーク トラフィックと遅延が軽減されるため、アプリケーションの効率とパフォーマンスが向上します。

        クロスドメイン通信:

        WebSocket プロトコルは、クロスドメイン通信、つまり、異なるドメイン名または異なるポート間の通信をサポートします。これにより、開発者は分散システムを構築し、異なるモジュールやサービスを異なるホストに配置し、WebSocket を介してリアルタイム通信やデータ交換を実行できるようになります。

2. バックエンドコードの実装

Maven の依存関係を導入する

<!--  socket启动依赖         -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
    <version>2.7.0</version>
</dependency>

WebSocketConfig

WebSocketConfig 関数:

        WebSocket サポートを有効にし、このクラスを Spring コンテナーに挿入します。具体的には、Spring 構成ファイルに ServerEndpointExporter Bean を登録します。これは、@ServerEndpoint アノテーションを持つすべての WebSocket サービスをスキャンし、WebSocket コンテナに登録するために使用されます。これにより、Spring Boot アプリケーションで WebSocket を使用して、リアルタイムの通信とデータ送信を実現できるようになります。​​    

WebSocketConfig.java コード

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * 开启WebSocket的支持,并把该类注入到spring容器中
 * @description: WebSocket配置
 * @author: 戈壁老孙
 * @create: 2023/11/08 10:28
 */
@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

MyWebSocket

@アノテーションの説明

@ServerEndpoint("/websocket") 注釈は、このクラスが WebSocket サーバー エンドポイントとして識別され、クライアントがこのエンドポイントを通じて WebSocket 接続を確立できることを示します。 /websocket は、クライアント接続の URL パスです。

@EnableScheduling アノテーションは、Spring のスケジュールされたタスクのスケジューリング機能を有効にすることを示します。このクラスで使用される @Scheduled アノテーションは有効になります。

@Component このアノテーションは、クラスが Spring コンポーネントとして識別され、Spring によって自動的に管理および挿入されることを示します。

これらのアノテーションが付けられたクラスは、WebSocket サーバーの実装クラスであり、スケジュールされたタスクのスケジューリングもサポートしており、Spring によって自動的に管理および挿入されます。クライアントは、 /websocket パスにアクセスすることで、WebSocket サーバーとの接続を確立できます。

MyWebSocket 関数:

         @ServerEndpoint アノテーションは、WebSocket サーバーのアドレスを宣言するために使用されます。クライアントからメッセージを受信すると、onMessage メソッドに入り、メッセージを処理します。同時に、クライアントが接続するか接続を閉じると、対応する onOpen メソッドと onClose メソッドに入ります。さらに、静的変数 onlineCount は現在接続されている WebSocket の数を表すために使用され、CopyOnWriteArraySet タイプの webSocketSet は接続されているすべての WebSocket インスタンスを保存するために使用されます。接続に参加するときは、addOnlineCount() を呼び出してオンライン番号レコードを増やし、接続を終了するときは subOnlineCount() を呼び出してオンライン番号レコードを減らします。最後に、@Autowired アノテーションを使用して IProTriaxisDataService の Bean を注入し、ビジネス ロジックを処理します。

MyWebSocket.java コード


import com.alibaba.fastjson2.JSONObject;
import com.unis.common.utils.StringUtils;
import com.unis.web.domain.ProTriaxialData;
import com.unis.web.service.IProTriaxialDataService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

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

/**
 * socket 通信类
 * @description: WebSocket配置
 * @author: 戈壁老孙
 * @create: 2023/11/08 10:30
 */
@ServerEndpoint("/websocket")
@EnableScheduling
@Component
public class MyWebSocket {

    private static final Logger log = LoggerFactory.getLogger(MyWebSocket.class);


    private static int onlineCount = 0;

    private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<>();

    private Session session;

    private Boolean isReceive = true;

    //业务注入
    private static IProTriaxialDataService proTriaxialDataService;

    @Autowired
    public void proTriaxialDataService(IProTriaxialDataService proTriaxialDataService){
        //WebScoketController是该类的类名 需要换成自己的类名
        MyWebSocket.proTriaxialDataService = proTriaxialDataService;
    }


    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        webSocketSet.add(this);
        addOnlineCount();
        log.info("有新链接加入!当前在线人数:{}",getOnlineCount());
    }

    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
        subOnlineCount();
        log.info("有一链接关闭!当前在线人数:{}",getOnlineCount());
    }

    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        log.info("socket 接收到信息{}",message);
        //判断前端是否已消费上一条信息
        if (StringUtils.isNotEmpty(message) && message.equals("已消费")){
            isReceive = true;
        } else {
            // 连接已断开
            isReceive = false;
        }
    }

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

    @Scheduled(cron = "*/5 * * * * *")
    public void sendMessageScheduledTask()throws Exception{
        log.info("socket 执行三数据推送给前端");
        try{
            if (isReceive){
                //每五秒发送一次
                List<ProTriaxialData> proTriaxialData = proTriaxialDataService.selectProTriaxialDataByCreateTimeDesc();
                if (proTriaxialData!=null && proTriaxialData.size()>0){
                    String message = JSONObject.toJSONString(proTriaxialData.get(0));
                    for (MyWebSocket item : webSocketSet) {
                        item.sendMessage(message);

                    }
                }
            }
            log.info("socket 数据发送成功!");
        }catch (Exception e){
            log.info("socket 数据发送失败!");
            e.printStackTrace();
        }

    }


    public static synchronized int getOnlineCount() {
        return MyWebSocket.onlineCount;
    }

    public static synchronized void addOnlineCount() {
        MyWebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        MyWebSocket.onlineCount--;
    }

}

3. サーバーが正常に接続されているかどうかをテストします

1. WebSocket テスト ガジェットを開きます

        

2. 以下に示すように、テスト ガジェットにアクセス アドレスを入力し、[接続] をクリックします。

        ws://IP:PORT/websocket 

4. フロントエンドコードの実装

created() {
      var ws = new WebSocket("ws://IP:PORT/websocket");

      // 连接成功后的回调函数
      ws.onopen = function (params) {
        console.log('客户端连接成功')
        // 向服务器发送消息
        ws.send('认证成功!')
      };
      // 从服务器接受到信息时的回调函数
      ws.onmessage = function (e) {
        console.log('收到服务器响应', e.data)
        this.proTriaxialData = e.data;
        console.log( this.proTriaxialData);
      };
      // 连接关闭后的回调函数
      ws.onclose = function(evt) {
        console.log("关闭客户端连接");
      };
      // 连接失败后的回调函数
      ws.onerror = function (evt) {
        console.log("连接失败了");
      };
      // 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,这样服务端会抛异常。
      window.onbeforeunload = function() {
        ws.close();
      }

      console.log(ws)
    }

5.エフェクト表示

ここで終わりますよ~

おすすめ

転載: blog.csdn.net/weixin_44719880/article/details/134295842