欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java中Spring WebSocket详解

程序员文章站 2024-02-16 19:47:10
首先 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 进行前后端的通信了,如果大家还有不明白的或者有更好的方法,可以在下方的留言区讨论。