springBoot整合webSocket並使用postMan進行測試

語言: CN / TW / HK

參考資料:

https://blog.csdn.net/qq_54773998/article/details/123863493

https://blog.csdn.net/weixin_56995925/article/details/120543965

簡單描述

簡單來講,webSocket是一種在http協議基礎上的另一種新協議,叫ws協議。

http協議是單工通訊,客戶端發起請求,服務端收到請求並處理,返回給客戶端,然後客戶端收到服務端的請求。

ws協議是全雙工通訊,客戶端發起請求後,相當於搭建了一個通道,在不斷開的情況下,在這期間,服務端可以把請求發給客戶端,客戶端也可以在這期間處理別的事情,不必等待服務端的響應。

如果不理解,可參考這篇文章:https://blog.csdn.net/qq_54773998/article/details/123863493

webSockt實現

此次webSocket實現不包含前端程式碼,將使用postMan來實現前端的功能。

依賴

xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>

配置類

```java @Configuration public class WebSocketConfig {

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

} ```

webSocketServer

```java package com.czf.study.wevSocket;

import lombok.extern.slf4j.Slf4j; import org.junit.platform.commons.util.StringUtils; import org.springframework.stereotype.Component;

import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.ConcurrentHashMap;

/ * @author zfChen * @create 2022/11/14 15:11 */ @ServerEndpoint("/websocket/{userId}") @Component @Slf4j public class WebSocketServer { /靜態變數,用來記錄當前線上連線數。應該把它設計成執行緒安全的。/ private static int onlineCount = 0; /concurrent包的執行緒安全集合,也可以map改成set,用來存放每個客戶端對應的MyWebSocket物件。/ private static ConcurrentHashMap webSocketMap = new ConcurrentHashMap<>(); /與某個客戶端的連線會話,需要通過它來給客戶端傳送資料*/ private Session session; /接收userId*/ private String userId="";

/**
 * 連線建立成功呼叫的方法*/
@OnOpen
public void onOpen(Session session,@PathParam("userId") String userId) {
    this.session = session;
    this.userId=userId;

    if(!webSocketMap.containsKey(userId)){
        //加入集合中
        webSocketMap.put(userId,this);
        //線上數加1
        addOnlineCount();
    }

    log.info("使用者連線:"+userId+",當前線上人數為:" + getOnlineCount());

    try {
        sendMessage("連線成功");
    } catch (IOException e) {
        log.error("使用者:"+userId+",網路異常!!!!!!");
    }
}

/**
 * 連線關閉呼叫的方法
 */
@OnClose
public void onClose() {
    if(webSocketMap.containsKey(userId)){
        webSocketMap.remove(userId);
        //從集合中刪除
        subOnlineCount();
    }
    log.info("使用者退出:"+userId+",當前線上人數為:" + getOnlineCount());
}

/**
 * 收到客戶端訊息後呼叫的方法
 *
 * @param message 客戶端傳送過來的訊息*/
@OnMessage
public void onMessage(String message, Session session) {
    log.info("【websocket訊息】收到客戶端發來的訊息:{}", message);
}

/**
 *
 * @param session
 * @param error
 */
@OnError
public void onError(Session session, Throwable error) {
    log.error("使用者錯誤:"+this.userId+",原因:"+error.getMessage());
    error.printStackTrace();
}
/**
 * 實現伺服器主動推送
 */
public void sendMessage(String message) throws IOException {
    this.session.getBasicRemote().sendText(message);
}


/**
 * 傳送自定義訊息
 * */
public static void sendInfo(String message,@PathParam("userId") String userId) throws IOException {
    log.info("傳送訊息到:"+userId+",報文:"+message);
    if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){
        webSocketMap.get(userId).sendMessage(message);
    }else{
        log.error("使用者"+userId+",不線上!");
    }
}

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

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

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

}

```

服務端發請求介面

外面建立一個介面,模擬服務端發請求給客戶端

```java @RestController public class DemoController {

@RequestMapping("/push/{toUserId}")
public ResponseEntity<String> pushToWeb(String message, @PathVariable String toUserId) throws IOException {
    WebSocketServer.sendInfo(message,toUserId);
    return ResponseEntity.ok("MSG SEND SUCCESS");
}

} ```

測試

使用postMan建立webSocket請求 在這裡插入圖片描述

輸入webSocket的地址,1表示userId=1 在這裡插入圖片描述

此時控制檯輸出

2022-11-15 11:51:43.009 INFO 28972 --- [nio-8787-exec-5] com.czf.study.wevSocket.WebSocketServer : 使用者連線:1,當前線上人數為:1

接下來,模擬服務端給客戶端傳送請求,建立一個http請求 在這裡插入圖片描述

控制檯輸出

2022-11-15 11:53:48.235 INFO 28972 --- [nio-8787-exec-4] com.czf.study.wevSocket.WebSocketServer : 傳送訊息到:1,報文:hello

客戶端收到請求 在這裡插入圖片描述

雙人聊天室

webSocket經常被用作聊天室,兩個客戶端,通過一個服務端分發請求,進行溝通。

在此案例中,通過/來區分,前一個是訊息,後一個是傳送的物件。

java /** * 收到客戶端訊息後呼叫的方法 * * @param message 客戶端傳送過來的訊息*/ @OnMessage public void onMessage(String message, Session session) { log.info("【websocket訊息】收到客戶端發來的訊息:{}", message); String[] split = message.split("/"); try { sendInfo(split[0],split[1]); } catch (IOException e) { e.printStackTrace(); } }

比如

在這裡插入圖片描述

2號使用者收到1號傳送的訊息

在這裡插入圖片描述

同樣的,2號也可以傳送訊息給1號。