websocket在springboot+vue中的使用


1、websocket在springboot中的一種實現

  在java后台中,websocket是作為一種服務端配置,其配置如下

@Configuration
public class WebSocketConfig {
  
    @Bean(name="serverEndpointExporter")
    public ServerEndpointExporter getServerEndpointExporterBean(){
        return new ServerEndpointExporter();
    }
}

  加入上面的配置之后就可以編輯自己的websocket實現類了,如下

@Component
@ServerEndpoint(value = "/messageSocket/{userId}")
public class MessageWebSocket {

    private static final Logger logger = LoggerFactory.getLogger(MessageWebSocket.class);

    /**
     * 靜態變量,用來記錄當前在線連接數。應該把它設計成線程安全的。
     */
    private static int onlineCount = 0;

    /**
     * key: userId value: sessionIds
     */
    private static ConcurrentHashMap<Integer, ConcurrentLinkedQueue<String>> userSessionMap =  new ConcurrentHashMap<>();

    /**
     * concurrent包的線程安全Map,用來存放每個客戶端對應的MyWebSocket對象。
     */
    private static ConcurrentHashMap<String, MessageWebSocket> websocketMap = new ConcurrentHashMap<>();

    /**
     * key: sessionId value: userId
     */
    private static ConcurrentHashMap<String, Integer> sessionUserMap = new ConcurrentHashMap<>();

    /**
     * 當前連接會話,需要通過它來給客戶端發送數據
     */
    private Session session;

    /**
     * 連接建立成功調用的方法
     * */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") Integer userId) {
        System.out.println(applicationContext);
        try {
            this.session = session;
            String sessionId = session.getId();
            //建立userId和sessionId的關系
            if(userSessionMap.containsKey(userId)) {
                userSessionMap.get(userId).add(sessionId);
            }else{
                ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
                queue.add(sessionId);
                userSessionMap.put(userId, queue);
            }
            sessionUserMap.put(sessionId, userId);
            //建立sessionId和websocket引用的關系
            if(!websocketMap.containsKey(sessionId)){
                websocketMap.put(sessionId, this);
                addOnlineCount();           //在線數加1
            }
        }catch (Exception e){
            logger.error("連接失敗");
            String es = ExceptionUtils.getFullStackTrace(e);
            logger.error(es);
        }
    }

    /**
     * 連接關閉調用的方法
     */
    @OnClose
    public void onClose() {
        String sessionId = this.session.getId();
        //移除userId和sessionId的關系
        Integer userId = sessionUserMap.get(sessionId);
        sessionUserMap.remove(sessionId);
        if(userId != null) {
            ConcurrentLinkedQueue<String> sessionIds = userSessionMap.get(userId);
            if(sessionIds != null) {
                sessionIds.remove(sessionId);
                if (sessionIds.size() == 0) {
                    userSessionMap.remove(userId);
                }
            }
        }
        //移除sessionId和websocket的關系
        if (websocketMap.containsKey(sessionId)) {
            websocketMap.remove(sessionId);
            subOnlineCount();           //在線數減1
        }
    }

    /**
     * 收到客戶端消息后調用的方法
     *
     * @param messageStr 客戶端發送過來的消息
     **/
    @OnMessage
    public void onMessage(String messageStr, Session session, @PathParam("userId") Integer userId) throws IOException {
   
    }

    /**
     *
     * @param session
     * @param error 當連接發生錯誤時的回調
     */
    @OnError
    public void onError(Session session, Throwable error) {
        String es = ExceptionUtils.getFullStackTrace(error);
        logger.error(es);
    }


    /**
     * 實現服務器主動推送
     */
    public void sendMessage(String message, Integer toUserId) throws IOException {
        if(toUserId != null && !StringUtil.isEmpty(message.trim())){
            ConcurrentLinkedQueue<String> sessionIds = userSessionMap.get(toUserId);
            if(sessionIds != null) {
                for (String sessionId : sessionIds) {
                    MessageWebSocket socket = websocketMap.get(sessionId);
                    socket.session.getBasicRemote().sendText(message);
                }
            }
        }else{
            logger.error("未找到接收用戶連接,該用戶未連接或已斷開");
        }
    }

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

     /**
    *獲取在線人數
    */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
     /**
    *在線人數加一
    */
    public static synchronized void addOnlineCount() {
        MessageWebSocket.onlineCount++;
    }
    /**
    *在線人數減一
    */
    public static synchronized void subOnlineCount() {
        MessageWebSocket.onlineCount--;
    }
}

到此后台服務端的工作已經做好了,前端如何作為客戶端進行連接呢,請繼續往下看。。

為了實現斷開自動重連,我們使用的reconnecting-websocket.js組件

//websocket連接實例
let websocket = null;

//初始話websocket實例
function initWebSocket(userId) {
    // ws地址 -->這里是你的請求路徑
    let host = urlConfig.wsUrl +  'messageSocket/' + userId;
    if ('WebSocket' in window) {
        websocket = new ReconnectingWebSocket(host);
        // 連接錯誤
        websocket.onerror = function () {
        }

        // 連接成功
        websocket.onopen = function () {
        }

        // 收到消息的回調,e.data為收到的信息
        websocket.onmessage = function (e) {
        }

        // 連接關閉的回調
        websocket.onclose = function () {
        }
        
        //監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。
        window.onbeforeunload = function () {
            closeWebSocket();
        }
    } else {
        alert('當前瀏覽器不支持websocket')
        return;
    }
}

//關閉WebSocket連接
function closeWebSocket() {
    websocket.close();
}

//發送消息
function sendMessage(message){
   websocket.send(message);
}

至此一個簡易的完整的websocket已經完成了,具體功能可以依此為基本進行擴展。

 

  


免責聲明!

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



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