1.什么是WebSocket(選擇至菜鳥教程(點擊跳轉),觀察者模式)
WebSocket 是 HTML5 開始提供的一種在單個 TCP 連接上進行全雙工通訊的協議。
WebSocket 使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據。在 WebSocket API 中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接,並進行雙向數據傳輸。
在 WebSocket API 中,瀏覽器和服務器只需要做一個握手的動作,然后,瀏覽器和服務器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送。
現在,很多網站為了實現推送技術,所用的技術都是 Ajax 輪詢。輪詢是在特定的的時間間隔(如每1秒),由瀏覽器對服務器發出HTTP請求,然后由服務器返回最新的數據給客戶端的瀏覽器。這種傳統的模式帶來很明顯的缺點,即瀏覽器需要不斷的向服務器發出請求,然而HTTP請求可能包含較長的頭部,其中真正有效的數據可能只是很小的一部分,顯然這樣會浪費很多的帶寬等資源。
HTML5 定義的 WebSocket 協議,能更好的節省服務器資源和帶寬,並且能夠更實時地進行通訊。
2.創建WebSocket連接(被觀察者)
這里我們在前端頁面向后端頁面發出請求,JavaScript中定義了WebSocket
四個事件和兩個方法
<script> var websocket = null; if('WebSocket' in window) { websocket = new WebSocket('ws://localhost:8080/sell/webSocket'); }else { alert('該瀏覽器不支持websocket!'); } websocket.onopen = function (event) { console.log('建立連接'); } websocket.onclose = function (event) { console.log('連接關閉'); } websocket.onmessage = function (event) { console.log('收到消息:' + event.data) //彈窗提醒, $('#myModal').modal('show'); // 播放音樂 document.getElementById('notice').play(); } websocket.onerror = function () { alert('websocket通信發生錯誤!'); } window.onbeforeunload = function () { websocket.close(); } </script>
3.使用java創建WebSokect連接(觀察者)
3.1引入依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
3.2注入ServerEndpointExporter(注入環境)
package com.xiong.sell.config; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Component public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
3.3編寫WebSocket類
package com.xiong.sell.service; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import java.util.concurrent.CopyOnWriteArraySet; @Component @ServerEndpoint("/webSocket") @Slf4j public class WebSocket { private Session session; //concurrent包的線程安全Set,用來存放每個客戶端對應的MyWebSocket對象。若要實現服務端與單一客戶端通信的話,可以使用Map來存放,其中Key可以為用戶標識 private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<>(); /** * 連接建立成功調用的方法 * @param session 可選的參數。session為與某個客戶端的連接會話,需要通過它來給客戶端發送數據 */ @OnOpen public void onOpen(Session session) { this.session = session; webSocketSet.add(this); log.info("【websocket消息】有新的連接, 總數:{}", webSocketSet.size()); } /** * 關閉連接調用方法 */ @OnClose public void onClose() { webSocketSet.remove(this); log.info("【websocket消息】連接斷開, 總數:{}", webSocketSet.size()); } /** * 收到客戶端消息后調用的方法 * @param message 客戶端發送過來的消息 */ @OnMessage public void onMessage(String message) { log.info("【websocket消息】收到客戶端發來的消息:{}", message); } /** * 自定義的方法,群發參數 * @param message 群發的內容 */ public void sendMessage(String message) { for (WebSocket webSocket: webSocketSet) { log.info("【websocket消息】廣播消息, message={}", message); try { webSocket.session.getBasicRemote().sendText(message); } catch (Exception e) { e.printStackTrace(); } } } }
4.測試截圖