首頁 > 軟體

SpringBoot實現WebSocket即時通訊的範例程式碼

2022-04-14 10:00:45

1、引入依賴

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
</dependency>
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.3</version>
</dependency>

2、WebSocketConfig 開啟WebSocket

package com.shucha.deveiface.web.config;
 
/**
 * @author tqf
 * @Description
 * @Version 1.0
 * @since 2022-04-12 15:35
 */
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
 
 
/**
 * 開啟WebSocket
 */
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}
 

3、WebSocketServer

package com.shucha.deveiface.web.ws;
 
/**
 * @author tqf
 * @Description
 * @Version 1.0
 * @since 2022-04-12 15:33
 */
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
 
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
 
@Component
@ServerEndpoint("/webSocket/{userId}")
@Slf4j
public class WebSocketServer {
    private Session session;
    private String userId;
    /**靜態變數,用來記錄當前線上連線數。應該把它設計成執行緒安全的。*/
    private static int onlineCount = 0;
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
 
    /**
     * concurrent包的執行緒安全set,用來存放每個使用者端對應的MyWebSocket物件
     */
    private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap();
 
    /**
     * 為了儲存線上使用者資訊,在方法中新建一個list儲存一下【實際專案依據複雜度,可以儲存到資料庫或者快取】
     */
    private final static List<Session> SESSIONS = Collections.synchronizedList(new ArrayList<>());
 
    /**
     * 建立連線
     * @param session
     * @param userId
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        webSocketSet.add(this);
        SESSIONS.add(session);
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            webSocketMap.put(userId,this);
        } else {
            webSocketMap.put(userId,this);
            addOnlineCount();
        }
        // log.info("【websocket訊息】有新的連線, 總數:{}", webSocketSet.size());
        log.info("[連線ID:{}] 建立連線, 當前連線數:{}", this.userId, webSocketMap.size());
    }
 
    /**
     * 斷開連線
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            subOnlineCount();
        }
        // log.info("【websocket訊息】連線斷開, 總數:{}", webSocketSet.size());
        log.info("[連線ID:{}] 斷開連線, 當前連線數:{}", userId, webSocketMap.size());
    }
 
    /**
     * 傳送錯誤
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.info("[連線ID:{}] 錯誤原因:{}", this.userId, error.getMessage());
        error.printStackTrace();
    }
 
    /**
     * 收到訊息
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
        // log.info("【websocket訊息】收到使用者端發來的訊息:{}", message);
        log.info("[連線ID:{}] 收到訊息:{}", this.userId, message);
    }
 
    /**
     * 傳送訊息
     * @param message
     * @param userId
     */
    public void sendMessage(String message,Long userId) {
        WebSocketServer webSocketServer = webSocketMap.get(String.valueOf(userId));
        if (webSocketServer!=null){
            log.info("【websocket訊息】推播訊息, message={}", message);
            try {
                webSocketServer.session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("[連線ID:{}] 傳送訊息失敗, 訊息:{}", this.userId, message, e);
            }
        }
    }
 
    /**
     * 群發訊息
     * @param message
     */
    public void sendMassMessage(String message) {
        try {
            for (Session session : SESSIONS) {
                if (session.isOpen()) {
                    session.getBasicRemote().sendText(message);
                    log.info("[連線ID:{}] 傳送訊息:{}",session.getRequestParameterMap().get("userId"),message);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 獲取當前連線數
     * @return
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
 
    /**
     * 當前連線數加一
     */
    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }
 
    /**
     * 當前連線數減一
     */
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }
 
}

4、測試連線傳送和接收訊息

package com.shucha.deveiface.web.controller;
 
import com.alibaba.fastjson.JSONObject;
import com.shucha.deveiface.web.ws.WebSocketServer;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
/**
 * @author tqf
 * @Description
 * @Version 1.0
 * @since 2022-04-12 15:44
 */
@RestController
@RequestMapping("/web")
public class TestWebSocket {
    @Autowired
    private WebSocketServer webSocketServer;
 
    /**
     * 訊息傳送測試
     */
    @GetMapping("/test")
    public void test(){
        for (int i=1;i<4;i++) {
            WebsocketResponse response = new WebsocketResponse();
            response.setUserId(String.valueOf(i));
            response.setUserName("姓名"+ i);
            response.setAge(i);
            webSocketServer.sendMessage(JSONObject.toJSONString(response), Long.valueOf(String.valueOf(i)));
        }
    }
 
    /**
     * 群發訊息測試(給當前連線使用者傳送)
     */
    @GetMapping("/sendMassMessage")
    public void sendMassMessage(){
        WebsocketResponse response = new WebsocketResponse();
        response.setUserName("群發訊息模板測試");
        webSocketServer.sendMassMessage(JSONObject.toJSONString(response));
    }
 
    @Data
    @Accessors(chain = true)
    public static class WebsocketResponse {
        private String userId;
        private String userName;
        private int age;
    }
}

5、線上測試地址

websocket 線上測試

6、測試截圖

存取測試傳送訊息:http://localhost:50041//web/test

測試存取地址:ws://192.168.0.115:50041/webSocket/1   wss://192.168.0.115:50041/webSocket/2

 到此這篇關於SpringBoot實現WebSocket即時通訊的範例程式碼的文章就介紹到這了,更多相關SpringBoot WebSocket即時通訊內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com