Java中Spring WebSocket详解
程序员文章站
2024-02-16 19:46:58
首先 pom.xml
org.springframework.boot
首先 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())); } /** * 处理二进制类的信息 * * @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 { } /** * 传出错误的处理 * * @param session * @param exception * @throws exception */ @override public void handletransporterror(websocketsession session, throwable exception) throws exception { } /** * 连接关闭的处理 * * @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 { // 此处可以做一些权限认证的事情或者其他 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(); } }
启动类 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
前端的测试页面 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 href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="external nofollow" rel="stylesheet"> <!--<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" 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="链接地址不能为空,请填写"> </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> 发送消息 </button> </div><br/> <textarea class="form-control" id="inmsg" rows="5" placeholder="在这里输入需要发送的信息..."></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; } //关闭websocket连接 function closewebsocket() { if (websocket) { websocket.close(); } return false; } //将消息显示在网页上 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">服务器: ' + msg + '</div>'; } document.getelementbyid('message').innerhtml = (document.getelementbyid('message').innerhtml + message); $("#message").scrollto('100%'); return false; } //发送消息 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); //连接发生错误的回调方法 websocket.onerror = function () { setmessageinnerhtml(0, "websocket连接发生错误 -> " + wsurl); $("#btnconnect").removeattr("disabled"); $("#btnclose").attr("disabled", "disabled"); $("#btnsend").attr("disabled", "disabled"); }; //连接成功建立的回调方法 websocket.onopen = function () { setmessageinnerhtml(0, "websocket连接成功 -> " + wsurl); $("#btnconnect").attr("disabled", "disabled"); $("#btnclose").removeattr("disabled"); $("#btnsend").removeattr("disabled"); }; //接收到消息的回调方法 websocket.onmessage = function (event) { setmessageinnerhtml(0, unzip(event.data)); }; //连接关闭的回调方法 websocket.onclose = function () { setmessageinnerhtml(0, "websocket连接关闭 -> " + wsurl); $("#btnconnect").removeattr("disabled"); $("#btnclose").attr("disabled", "disabled"); $("#btnsend").attr("disabled", "disabled"); }; //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function () { closewebsocket(); }; } else { alert('not support websocket'); } } return false; } window.onload = init(); </script> </body> </html>
到此就可以使用 websocket 进行前后端的通信了,如果大家还有不明白的或者有更好的方法,可以在下方的留言区讨论。