萌新練習寫程式碼的每日一練:二叉搜尋樹中的插入操作
阿新 • • 發佈:2021-01-07
SpringBoot+WebSocket整合
-
- 什麼是WebSocket?
- 為什麼需要 WebSocket?
- 前言
- maven依賴
- WebSocketConfig
- WebSocketServer
- 訊息推送
- 頁面發起
- 執行效果
- 後續
- Websocker注入Bean問題
- netty-websocket-spring-boot-starter
- Springboot2+Netty+Websocket
- ServerEndpointExporter錯誤
- 正式專案的前端WebSocket框架 GoEasy
- `@Component`和`@ServerEndpoint`關於是否單例模式,能否使用static Map等一些問題的解答
- Vue版本的websocket連線
什麼是WebSocket?
WebSocket協議是基於TCP的一種新的網路協議。它實現了瀏覽器與伺服器全雙工(full-duplex)通訊——允許伺服器主動傳送資訊給客戶端。
為什麼需要 WebSocket?
初次接觸 WebSocket 的人,都會問同樣的問題:我們已經有了 HTTP 協議,為什麼還需要另一個協議?它能帶來什麼好處?
- 答案很簡單,因為 HTTP 協議有一個缺陷:通訊只能由客戶端發起,HTTP 協議做不到伺服器主動向客戶端推送資訊。
舉例來說,我們想要查詢當前的排隊情況,只能是頁面輪詢向伺服器發出請求,伺服器返回查詢結果。輪詢的效率低,非常浪費資源(因為必須不停連線,或者 HTTP 連線始終開啟)。因此WebSocket 就是這樣發明的。
前言
2020-10-20
教程補充:
- 補充關於
@Component
和@ServerEndpoint
關於是否單例模式等的解答,感謝大家熱心提問和研究。 Vue
版本的websocket連線方法
2020-01-05
教程補充:
- 整合了
IM相關的優化
- 優化
開啟/關閉連線的處理
- 上傳到
開源專案
spring-cloud-study-websocket,方便大家下載程式碼。
感謝
大家的支援和留言,14W訪問量是滿滿的動力!接下來還會有websocket+redis叢集優化篇
針對多ws伺服器做簡單優化處理,敬請期待!
話不多說,馬上進入乾貨時刻。
maven依賴
SpringBoot2.0對WebSocket的支援簡直太棒了,直接就有包可以引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
WebSocketConfig
啟用WebSocket的支援也是很簡單,幾句程式碼搞定
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* 開啟WebSocket支援
* @author zhengkai.blog.csdn.net
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
WebSocketServer
這就是重點了,核心都在這裡。
-
因為WebSocket是類似客戶端服務端的形式(採用ws協議),那麼這裡的WebSocketServer其實就相當於一個ws協議的Controller
-
直接
@ServerEndpoint("/imserver/{userId}")
、@Component
啟用即可,然後在裡面實現@OnOpen
開啟連線,@onClose
關閉連線,@onMessage
接收訊息等方法。 -
新建一個
ConcurrentHashMap
webSocketMap 用於接收當前userId的WebSocket,方便IM之間對userId進行推送訊息。單機版
實現到這裡就可以。 -
叢集版
(多個ws節點)還需要藉助mysql或者redis等進行處理,改造對應的sendMessage
方法即可。
package com.softdev.system.demo.config;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
/**
* @author zhengkai.blog.csdn.net
*/
@ServerEndpoint("/imserver/{userId}")
@Component
public class WebSocketServer {
static Log log=LogFactory.get(WebSocketServer.class);
/**靜態變數,用來記錄當前線上連線數。應該把它設計成執行緒安全的。*/
private static int onlineCount = 0;
/**concurrent包的執行緒安全Set,用來存放每個客戶端對應的MyWebSocket物件。*/
private static ConcurrentHashMap<String,WebSocketServer> 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.remove(userId);
webSocketMap.put(userId,this);
//加入set中
}else{
webSocketMap.put(userId,this);
//加入set中
addOnlineCount();
//線上數加1
}
log.info("使用者連線:"+userId+",當前線上人數為:" + getOnlineCount());
try {
sendMessage("連線成功");
} catch (IOException e) {
log.error("使用者:"+userId+",網路異常!!!!!!");
}
}
/**
* 連線關閉呼叫的方法
*/
@OnClose
public void onClose() {
if(webSocketMap.containsKey(userId)){
webSocketMap.remove(userId);
//從set中刪除
subOnlineCount(