SpringBoot整合WebSocket教程
Websocket
概述
WebSocket 是基于 TCP 的一種新的網絡協議。它實現了瀏覽器與服務器全雙工通信——瀏覽器和服務器只需要完成一次握手,兩者之間就可以創建持久性的連接, 并進行雙向數據傳輸。
HTTP協議和WebSocket協議對比:
- HTTP是短連接
- WebSocket是長連接
- HTTP通信是單向的,基于請求響應模式
- WebSocket支持雙向通信
- HTTP和WebSocket底層都是TCP連接

思考:既然WebSocket支持雙向通信,功能看似比HTTP強大,那么我們是不是可以基于WebSocket開發所有的業務功能?
WebSocket缺點:
服務器長期維護長連接需要一定的成本
各個瀏覽器支持程度不一
WebSocket 是長連接,受網絡限制比較大,需要處理好重連
結論:WebSocket并不能完全取代HTTP,它只適合在特定的場景下使用
使用場景
1). 視頻彈幕
2). 網頁聊天
3). 體育實況更新
入門案例
(1)需求說明
實現瀏覽器與服務器全雙工通信。瀏覽器既可以向服務器發送消息,服務器也可主動向瀏覽器推送消息。

(2)流程如下

- 需要準備客戶端,可以在瀏覽器上編寫客戶端
- 服務端,使用java代碼實現,啟動一個服務
- 客戶端與服務端連接成功以后
- 客戶端可以發送數據到服務器端
- 服務器端也可以發送數據到客戶端(瀏覽器)
(3)功能實現
客戶端
定義websocket.html頁面充當客戶端
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Demo</title>
</head>
<body>
<input id="text" type="text" />
<button onclick="send()">發送消息</button>
<button onclick="closeWebSocket()">關閉連接</button>
<div id="message">
</div>
</body>
<script type="text/javascript">
var websocket = null;
var clientId = Math.random().toString(36).substr(2);
//判斷當前瀏覽器是否支持WebSocket
if('WebSocket' in window){
//連接WebSocket節點
websocket = new WebSocket("ws://localhost:8080/ws/"+clientId);
}
else{
alert('Not support websocket')
}
//連接發生錯誤的回調方法
websocket.onerror = function(){
setMessageInnerHTML("error");
};
//連接成功建立的回調方法
websocket.onopen = function(){
setMessageInnerHTML("連接成功");
}
//接收到消息的回調方法
websocket.onmessage = function(event){
setMessageInnerHTML(event.data);
}
//連接關閉的回調方法
websocket.onclose = function(){
setMessageInnerHTML("close");
}
//監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。
window.onbeforeunload = function(){
websocket.close();
}
//將消息顯示在網頁上
function setMessageInnerHTML(innerHTML){
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//發送消息
function send(){
var message = document.getElementById('text').value;
websocket.send(message);
}
//關閉連接
function closeWebSocket() {
websocket.close();
}
</script>
</html>
服務端
然后導入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
定義WebSocket服務端組件
@Slf4j
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {
private static Map<String,Session> sessionMap = new HashMap<>();
/**
* 連接建立時觸發
* @param session
* @param sid
*/
@OnOpen
public void onOpen(Session session , @PathParam("sid") String sid){
log.info("有客戶端連接到了服務器 , {}", sid);
sessionMap.put(sid, session);
}
/**
* 服務端接收到消息時觸發
* @param session
* @param message
* @param sid
*/
@OnMessage
public void onMessage(Session session , String message, @PathParam("sid") String sid){
log.info("接收到了客戶端 {} 發來的消息 : {}", sid ,message);
}
/**
* 連接關閉時觸發
* @param session
* @param sid
*/
@OnClose
public void onClose(Session session , @PathParam("sid") String sid){
System.out.println("連接斷開:" + sid);
sessionMap.remove(sid);
}
/**
* 通信發生錯誤時觸發
* @param session
* @param sid
* @param throwable
*/
@OnError
public void onError(Session session , @PathParam("sid") String sid , Throwable throwable){
System.out.println("出現錯誤:" + sid);
throwable.printStackTrace();
}
/**
* 廣播消息
* @param message
* @throws IOException
*/
public void sendMessageToAll(String message) throws IOException {
Collection<Session> sessions = sessionMap.values();
if(!CollectionUtils.isEmpty(sessions)){
for (Session session : sessions) {
//服務器向客戶端發送消息
session.getBasicRemote().sendText(message);
}
}
}
}
定義配置類,注冊WebSocket的服務端組件
@Configuration
public class WebSocketConfig {
/**
* 注冊基于@ServerEndpoint聲明的Websocket Endpoint
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
定義定時任務類,定時向客戶端推送數據
@Component
public class MessageTask {
@Autowired
private WebSocketServer webSocketServer;
@Scheduled(cron = "0/5 * * * * ?")
public void sendMessageToAllClient() throws IOException {
webSocketServer.sendMessageToAll("Hello Client , Current Server Time : " + LocalDateTime.now());
}
}
測試
啟動后端服務,打開瀏覽器即可成功,在瀏覽器中可以看到服務器端推送的數據,瀏覽器也可以發送數據到服務器端
客戶端的效果:

服務端接收到的數據,在控制臺打印


浙公網安備 33010602011771號