本文章包括websocket面試相關問題以及spring boot如何整合webSocket。javascript
參考文檔 https://blog.csdn.net/prayallforyou/article/details/53737901 、https://www.cnblogs.com/bianzy/p/5822426.htmlcss
webSocket是HTML5的一種新協議,它實現了服務端與客戶端的全雙工通訊,創建在傳輸層,tcp協議之上,即瀏覽器與服務端須要先創建tcp協議,再發送webSocket鏈接創建請求。html
webSocket的鏈接:客戶端發送請求信息,服務端接受到請求並返回相應的信息。鏈接創建。客戶端發送http請求時,經過 Upgrade:webSocket Connection:Upgrade 告知服務器須要創建的是webSocket鏈接,而且還會傳遞webSocket版本號,協議的字版本號,原始地址,主機地址等等。前端
webSocket相互通訊的Header很小,大概只有2Bytes。java
如下是基於spring boot及支持webScoket的高版本瀏覽器的配置過程。git
1、pom.xml中引入webSocket組件github
</dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> </dependencies>
2、後臺引入webSocketweb
要想讓一個類處理webScoket的請求,須要兩個東西:面試
① 類名上加webScoket請求攔截註釋@ServerEndpoint(value="/***")spring
② 類須要繼承org.springframework.web.socket.server.standard.ServerEndpointExporter,重寫交互過程當中各類狀況下調用的方法(創建時、斷開時、出錯時、接收消息、發送消息)
針對②,一方面根據spring的IOC特性,須要反向代理,另外一方面由於webSocket是一個功能而不單單是屬於某個業務,因此應當在配置文件中聲明。配置文件能夠是xml文件,也能夠是註釋了@Configuration的類文件,根據我的喜愛使用~,這裏使用的是@Configuration。
@Configuration public class ProjectConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
使用@ServerEndpoint(value="/***") 時會自動注入返回類型爲ServerEndpointExporter的bean。等同於繼承了ServerEndpointExporter類。繼承類後再重寫onOpen、onClose、onMessage、onError方法,由於不是直接使用繼承,因此方法的重寫也須要使用註釋,代碼以下
package com.example.SpringBootTry.controller.webSocket; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import org.springframework.stereotype.Component; /** * 雙工通訊websocket工具類 * @author wwl * */ @ServerEndpoint(value="/webSocket") @Component public class WebSocketUtil{ //靜態變量,用來記錄當前在線鏈接數。應該把它設計成線程安全的。 private static int onlineCount = 0; //concurrent包的線程安全Set,用來存放每一個客戶端對應的MyWebSocket對象。 private static CopyOnWriteArraySet<WebSocketUtil> webSocketSet = new CopyOnWriteArraySet<WebSocketUtil>(); //與某個客戶端的鏈接會話,須要經過它來給客戶端發送數據 private Session session; /** * 鏈接創建成功調用的方法*/ @OnOpen public void onOpen(Session session) { this.session = session; webSocketSet.add(this); //加入set中 addOnlineCount(); //在線數加1 System.out.println("有新鏈接加入!當前在線人數爲" + getOnlineCount()); try { sendMessage("您是第" + getOnlineCount() + "個雙工通訊的用戶!"); } catch (IOException e) { System.out.println("IO異常"); } } /** * 鏈接關閉調用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); //從set中刪除 subOnlineCount(); //在線數減1 System.out.println("有一鏈接關閉!當前在線人數爲" + getOnlineCount()); } /** * 收到客戶端消息後調用的方法 * * @param message 客戶端發送過來的消息*/ @OnMessage public void onMessage(String message, Session session) { System.out.println("來自客戶端的消息:" + message); //發送消息 try { session.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } /** * 發生錯誤時調用 */ @OnError public void onError(Session session, Throwable error) { System.out.println("發生錯誤"); error.printStackTrace(); } /** * 發送消息 * @param message * @throws IOException */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); //this.session.getAsyncRemote().sendText(message); } /** * 羣發自定義消息 * */ public static void sendInfo(String message) throws IOException { for (WebSocketUtil item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { continue; } } } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketUtil.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketUtil.onlineCount--; } }
3、前端引入webSocket
使用 var websocket = new WebSocket("ws://localhost:8081/***") 創建webSocket鏈接,定義websocket的onerror、onopen、onmessage、onclose的屬性,跟後臺的四個方法相對應,完成合理的webSocket交互。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>websocket測試頁面</title> <meta http-equiv="keywords" content="websocket,例子"> <meta http-equiv="description" content="測試websocket"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!--<link rel="stylesheet" type="text/css" href="./styles.css">--> </head> <body> Welcome<br/> <input id="text" type="text" /><button onclick="send()">Send</button> <button onclick="closeWebSocket()">Close</button> <div id="message"> </div> </body> <script type="text/javascript"> var websocket = null; //判斷當前瀏覽器是否支持WebSocket if('WebSocket' in window){ websocket = new WebSocket("ws://localhost:8081/webSocket"); }else{ alert('Not support websocket') } //鏈接發生錯誤的回調方法 websocket.onerror = function(){ setMessageInnerHTML("error"); }; //鏈接成功創建的回調方法 websocket.onopen = function(event){ setMessageInnerHTML("open"); } //接收到消息的回調方法 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 closeWebSocket(){ websocket.close(); } //發送消息 function send(){ var message = document.getElementById('text').value; websocket.send(message); } </script> </html>
以上爲spring boot 整合webSocket的一些入門知識。有錯誤歡迎指正。
demo地址:https://github.com/ttjsndx/someDemo/blob/master/SpringBootTryDemo.rar