Spring Boot中使用Websocket搭建即時聊天系統


1、首先在pom文件中引入Webscoekt的依賴

<!-- websocket依賴 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2、通過注解方式構建Websocket服務

package com.kk.server.chat.websocket;

import com.kk.server.chat.service.CheckTokenService;
import com.kk.server.chat.service.QueryService;
import com.kk.server.chat.service.SaveMongodbService;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
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.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by yxl on 2018-03-19.
 */
@ServerEndpoint("/chat/{userId}") //關鍵注解,將WebSocket服務端運行在 ws://[Server端IP或域名]:[Server端口]/websockets/chat/{userId} 的訪問端點,客戶端瀏覽器已經可以對 WebSocket客戶端API發起HTTP長連接了。
@Component
public class ChatWebsocket {

    private Logger logger = Logger.getLogger(ChatWebsocket.class);

    private static ApplicationContext applicationContext;

    private SaveMongodbService saveMongodbService;

    private CheckTokenService checkTokenService;

    private QueryService queryService;



    //靜態變量,用來記錄當前在線連接數。應該把它設計成線程安全的。
    private static int onlineCount = 0;
    //concurrent包的線程安全Set,用來存放每個客戶端對應的MyWebSocket對象。若要實現服務端與單一客戶端通信的話,可以使用Map來存放,其中Key可以為用戶標識
    private static Map<String, Session> webSocketSet = new ConcurrentHashMap<>(); //醫生web


    //解決Websocket不能注入bean的問題
    public static void setApplicationContext(ApplicationContext applicationContext) {
        ChatWebsocket.applicationContext = applicationContext;
    }

    /**
     * 連接建立成功調用的方法
     *
     * @param userId   用戶鏈接ID
     */
    @OnOpen  //建立連接的注解,當用戶建立連接時SpringBoot會監聽到,然后會調用該注解下的方法
    public void onOpen(@PathParam("userId") String userId, Session session) {
        webSocketSet.put(userId, session);
    }



    /**
     * 連接關閉調用的方法
     */
    @OnClose
    public void onClose(Session session) {
        logger.info("進入關閉方法!");
        if (session != null) {
            Map<String, String> pathParameters = session.getPathParameters();
            String userId = pathParameters.get("userId"); //從當前關閉session中獲取用戶ID,前提是建立websocket連接時帶有userId,即 @ServerEndpoint("/chat/{userId}")
            webSocketSet.remove(userId); //從map中移除用戶
        }
    }



    /**
     * 收到客戶端消息后調用的方法
     *
     * @param message 客戶端發送過來的消息
     * @param session 可選的參數
     */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {

        try {
            JSONObject jsonObject = JSONObject.parseObject(message);
            String receiver_id = jsonObject.getString("receiver_id") //接受者ID,通過該Id來獲取接受者的session
            Session session = webSocketSet.get("receiver_id")
            if (session != null) {
                session.getBasicRemote.sendText(message); //通過session發送消息
            }else {
                //TODO 接收方不在線,處理離線消息

            }
        }catch(IOException e) {
            e.printStackTrace;
        }

    }

    /**
     * 發生錯誤時調用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        //onClose();
        if (session != null) {
            Map<String, String> pathParameters = session.getPathParameters();
            String userId = pathParameters.get("userId"); //從當前關閉session中獲取用戶ID,前提是建立websocket連接時帶有userId,即 @ServerEndpoint("/chat/{userId}")
            webSocketSet.remove(userId); //從map中移除用戶
        }
        logger.info("webscoket發生錯誤!"+error.getMessage());
        error.printStackTrace();
    }
}

3、前台調用方法(js)

function WebSocketTest()
         {
            if ("WebSocket" in window)
            {
               alert("您的瀏覽器支持 WebSocket!");
               
               // 打開一個 web socket
            var ws = new WebSocket("ws://服務器IP:端口/chat/123");
               ws.onopen = function() {
                  // Web Socket 已連接上,使用 send() 方法發送數據
                  ws.send('{"userId":"1555855","message" : "test"}');
                  ws.close("666666");
                  alert("數據發送中...");
               };
           
               ws.onmessage = function (evt) { 
                  console.log(evt)
                  alert(evt.data);
                  alert("數據已接收...");
               };
                
               ws.onclose = function(){ 
                  // 關閉 websocket
                  alert("連接已關閉..."); 
               };
            }else {
               // 瀏覽器不支持 WebSocket
               alert("您的瀏覽器不支持 WebSocket!");
            }
         }        

 4、當然,在使用websocket聊天時,可能會遇到一些數據需要查詢數據庫或者Redis,但是在websocket中又不能直接注入相應的Bean實例,這個時候可以看我的另一篇博客https://www.cnblogs.com/Amaris-Lin/p/9038813.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM