Java中Spring WebSocket詳解
首先 pom.xml
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.8.RELEASE</version> </parent> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> </dependency> <dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-api</artifactId> <version>1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency>
接收消息后的處理類 GameHandler :
import java.net.URI; import org.springframework.web.socket.BinaryMessage; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.PongMessage; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.AbstractWebSocketHandler; public class GameHandler extends AbstractWebSocketHandler { /** * 處理字符串類的信息 * * @param session * @param message * @throws Exception */ @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { session.sendMessage(new TextMessage(message.asBytes())); } /** * 處理二進(jìn)制類的信息 * * @param session * @param message * @throws Exception */ @Override protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception { session.sendMessage(new BinaryMessage(message.getPayload())); } /** * ping-pong * * @param session * @param message * @throws Exception */ @Override protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception { } /** * 傳出錯(cuò)誤的處理 * * @param session * @param exception * @throws Exception */ @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { } /** * 連接關(guān)閉的處理 * * @param session * @param status * @throws Exception */ @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { } /** * 連接建立后的處理 * * @param session * @throws Exception */ @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { } }
握手信息攔截器 WebSocketHandshakeInterceptor :
import java.util.Map; import javax.servlet.http.Cookie; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.HandshakeInterceptor; public class WebSocketHandshakeInterceptor implements HandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse shr1, WebSocketHandler wsh, Map<String, Object> attributes) throws Exception { // 此處可以做一些權(quán)限認(rèn)證的事情或者其他 return true; } @Override public void afterHandshake(ServerHttpRequest shr, ServerHttpResponse shr1, WebSocketHandler wsh, Exception excptn) { } }
使用WebSocket的配置類 WebSocketConfig :
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; @Configuration @EnableWebSocket public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { // 允許連接的域,只能以http或https開頭 String[] allowsOrigins = {"http://127.0.0.1:1213", "http://localhost:1213"}; registry.addHandler(gameHandler(),"/game").addInterceptors(handshakeInterceptor()).setAllowedOrigins(allowsOrigins); } @Bean public GameHandler gameHandler() { return new GameHandler(); } @Bean public WebSocketHandshakeInterceptor handshakeInterceptor() { return new WebSocketHandshakeInterceptor(); } }
啟動(dòng)類 Launcher :
@SpringBootApplication public class Launcher { public static void main(String[] params) { SpringApplication.run(Launcher.class, params); } }
配置文件 main/resources/application.properties:
server.port=1213 server.session-timeout=1800 server.undertow.io-threads=4 server.undertow.worker-threads=20 server.undertow.buffer-size=1024 server.undertow.buffers-per-region=1024 server.undertow.direct-buffers=true
前端的測(cè)試頁(yè)面 main\resources\static\index.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Platform Gateway</title> <link rel="external nofollow" rel="stylesheet"> <!--<link rel="external nofollow" rel="stylesheet">--> <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/jquery-scrollTo/2.1.2/jquery.scrollTo.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/pako/1.0.6/pako.min.js"></script> <!--[if lt IE 9]> <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script> <![endif]--> <style> #message{ height: 600px; overflow-y:auto; } </style> </head> <body> <div class="container"> <h1>WebSocket Test Page</h1> <hr/> <div class="form-inline"> <div class="form-group"> <label for="wsAddr">WebSocket Address: </label> <div class="input-group"> <span class="input-group-addon" id="basic-ws">ws://127.0.0.1:1213/</span> <input type="text" class="form-control" id="basic-ws-addr" aria-describedby="basic-ws" placeholder="game" data-container="body" data-placement="top" data-content="鏈接地址不能為空,請(qǐng)?zhí)顚?> </div> </div> <button type="button" id="btnConnect" class="btn btn-primary" onclick="connect();"> <span class="glyphicon glyphicon-resize-small" aria-hidden="true"></span> 連接 </button> <button type="button" id="btnClose" class="btn btn-danger" disabled="disabled" onclick="closeWebSocket();"> <span class="glyphicon glyphicon-remove" aria-hidden="true"></span> 斷開 </button> <button type="button" id="btnSend" class="btn btn-info" disabled="disabled" style="margin-left: 50px;" onclick="send();"> <span class="glyphicon glyphicon-transfer" aria-hidden="true"></span> 發(fā)送消息 </button> </div><br/> <textarea class="form-control" id="inMsg" rows="5" placeholder="在這里輸入需要發(fā)送的信息..."></textarea> <hr/> <div id="message"></div> </div> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <script type="text/javascript"> function zip(str) { var binaryString = pako.gzip(str, {to: 'string'}); return btoa(binaryString); } function unzip(b64Data) { var strData = atob(b64Data); var charData = strData.split('').map(function (x) { return x.charCodeAt(0); }); var binData = new Uint8Array(charData); var data = pako.inflate(binData); strData = String.fromCharCode.apply(null, new Uint16Array(data)); return strData; } var websocket = null; var wsBaseUrl = null; var wsUrl = null; function init() { wsBaseUrl = "ws://" + window.location.host + "/"; $("#basic-ws").text(wsBaseUrl); $(function () { $('[data-toggle="popover"]').popover(); }); return false; } //關(guān)閉WebSocket連接 function closeWebSocket() { if (websocket) { websocket.close(); } return false; } //將消息顯示在網(wǎng)頁(yè)上 function setMessageInnerHTML(who, msg) { var message = null; if (who === 1) { message = '<div class="alert alert-success" role="alert">本地: ' + msg + '</div>'; } else { message = '<div class="alert alert-info" role="alert">服務(wù)器: ' + msg + '</div>'; } document.getElementById('message').innerHTML = (document.getElementById('message').innerHTML + message); $("#message").scrollTo('100%'); return false; } //發(fā)送消息 function send() { if (websocket) { var message = $("#inMsg").val(); websocket.send(zip(message)); setMessageInnerHTML(1, message); } return false; } function connect() { var url = $("#basic-ws-addr").val(); if (url.length <= 0) { $('#basic-ws-addr').popover('show'); setTimeout(function () { $('#basic-ws-addr').popover('hide'); }, 3000); } else { wsUrl = wsBaseUrl + url; if ('WebSocket' in window) { websocket = new WebSocket(wsUrl); //連接發(fā)生錯(cuò)誤的回調(diào)方法 websocket.onerror = function () { setMessageInnerHTML(0, "WebSocket連接發(fā)生錯(cuò)誤 -> " + wsUrl); $("#btnConnect").removeAttr("disabled"); $("#btnClose").attr("disabled", "disabled"); $("#btnSend").attr("disabled", "disabled"); }; //連接成功建立的回調(diào)方法 websocket.onopen = function () { setMessageInnerHTML(0, "WebSocket連接成功 -> " + wsUrl); $("#btnConnect").attr("disabled", "disabled"); $("#btnClose").removeAttr("disabled"); $("#btnSend").removeAttr("disabled"); }; //接收到消息的回調(diào)方法 websocket.onmessage = function (event) { setMessageInnerHTML(0, unzip(event.data)); }; //連接關(guān)閉的回調(diào)方法 websocket.onclose = function () { setMessageInnerHTML(0, "WebSocket連接關(guān)閉 -> " + wsUrl); $("#btnConnect").removeAttr("disabled"); $("#btnClose").attr("disabled", "disabled"); $("#btnSend").attr("disabled", "disabled"); }; //監(jiān)聽窗口關(guān)閉事件,當(dāng)窗口關(guān)閉時(shí),主動(dòng)去關(guān)閉websocket連接,防止連接還沒斷開就關(guān)閉窗口,server端會(huì)拋異常。 window.onbeforeunload = function () { closeWebSocket(); }; } else { alert('Not support websocket'); } } return false; } window.onload = init(); </script> </body> </html>
到此就可以使用 WebSocket 進(jìn)行前后端的通信了,如果大家還有不明白的或者有更好的方法,可以在下方的留言區(qū)討論。
- 基于java實(shí)現(xiàn)websocket代碼示例
- Vue+Java 通過(guò)websocket實(shí)現(xiàn)服務(wù)器與客戶端雙向通信操作
- 基于java實(shí)現(xiàn)websocket協(xié)議過(guò)程詳解
- Java開發(fā)中常用的 Websocket 技術(shù)參考
- java與微信小程序?qū)崿F(xiàn)websocket長(zhǎng)連接
- java 實(shí)現(xiàn)websocket的兩種方式實(shí)例詳解
- Java后端WebSocket的Tomcat實(shí)現(xiàn)
- Java中使用websocket實(shí)現(xiàn)在線聊天功能
- java使用websocket,并且獲取HttpSession 源碼分析(推薦)
- Java中websocket消息推送的實(shí)現(xiàn)代碼
- 基于Tomcat7、Java、WebSocket的服務(wù)器推送聊天室實(shí)例
- 用java WebSocket做一個(gè)聊天室
- 使用Java和WebSocket實(shí)現(xiàn)網(wǎng)頁(yè)聊天室實(shí)例代碼
- 使用JavaWeb webSocket實(shí)現(xiàn)簡(jiǎn)易的點(diǎn)對(duì)點(diǎn)聊天功能實(shí)例代碼
- 教你怎么使用Java實(shí)現(xiàn)WebSocket
相關(guān)文章
SpringBoot2.1.4中的錯(cuò)誤處理機(jī)制
這篇文章主要介紹了SpringBoot2.1.4中的錯(cuò)誤處理機(jī)制,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10如何調(diào)用chatGPT實(shí)現(xiàn)代碼機(jī)器人
最近c(diǎn)hatGPT也是非常的火爆,相信大家都看到了,現(xiàn)在提供一種Java調(diào)用chatGPT的方法,我們主要通過(guò)兩個(gè)工具來(lái)實(shí)現(xiàn),一就是httpclient,二就是hutool,你覺得那種好理解你就用那種即可,今天通過(guò)本文給大家分享調(diào)用chatGPT實(shí)現(xiàn)代碼機(jī)器人,感興趣的朋友一起看看吧2022-12-12java基本教程之java線程等待與java喚醒線程 java多線程教程
這篇文章主要介紹了對(duì)線程等待/喚醒方法,文中使用了多個(gè)示例,大家參考使用吧2014-01-01Java實(shí)現(xiàn)的文件過(guò)濾代碼分享(按后輟過(guò)濾)
這篇文章主要介紹了Java實(shí)現(xiàn)的文件過(guò)濾代碼分享,本文通過(guò)后輟名過(guò)濾,代碼寫簡(jiǎn)潔,容易看懂,需要的朋友可以參考下2014-07-07springboot 集成cas5.3 實(shí)現(xiàn)sso單點(diǎn)登錄詳細(xì)流程
SSO的定義是在多個(gè)應(yīng)用系統(tǒng)中,用戶只需要登錄一次就可以訪問(wèn)所有相互信任的應(yīng)用系統(tǒng)。單點(diǎn)登錄是目前比較流行的企業(yè)業(yè)務(wù)整合的解決方案之一,本文給大家介紹springboot 集成cas5.3 實(shí)現(xiàn)sso單點(diǎn)登錄功能,感興趣的朋友一起看看吧2021-10-10使用Java實(shí)現(xiàn)2048小游戲代碼實(shí)例
這篇文章主要介紹了使用Java實(shí)現(xiàn)2048小游戲代碼實(shí)例,2048 游戲是一款益智類游戲,玩家需要通過(guò)合并相同數(shù)字的方塊,不斷合成更大的數(shù)字,最終達(dá)到2048,游戲規(guī)則簡(jiǎn)單,但挑戰(zhàn)性很高,需要玩家靈活運(yùn)用策略和計(jì)算能力,本文將使用Java代碼實(shí)現(xiàn),需要的朋友可以參考下2023-10-10java中實(shí)體類和JSON對(duì)象之間相互轉(zhuǎn)化
Java中關(guān)于Json格式轉(zhuǎn)化Object,Map,Collection類型和String類型之間的轉(zhuǎn)化在我們實(shí)際項(xiàng)目中應(yīng)用的很是普遍和廣泛。最近工作的過(guò)程中也是經(jīng)常有,因此,自己封裝了一個(gè)類分享給大家。2015-05-05