SpringBoot 全家桶 | WebSocket服务端与客户端实例

本文源码:Gitee·点这里

介绍

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

参考

  1. Spring Framework 中文文档

  2. WebSocket 在线测试 v13

  3. HTML5 WebSocket

Server端

Server端我们使用SpringBoot的一个包spring-boot-starter-websocket,我们来引入它


 org.springframework.boot
 spring-boot-starter-websocket

WebSocket处理器

WebSocket处理器用来处理客户端发送的消息,Spring中常用的是两个TextWebSocketHandlerBinaryWebSocketHandler,我们使用TextWebSocketHandler

import org.springframework.web.socket.handler.TextWebSocketHandler;
​
public class ChatWebSocketHandler extends TextWebSocketHandler {
​
 @Override
 public void afterConnectionEstablished(WebSocketSession session) throws Exception {

 }
​
 @Override
 protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
 String msg = message.getPayload();
 }

 @Override
 public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {

 }

 @Override
 public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

 }
}

重写TextWebSocketHandler的四个方法:

  • afterConnectionEstablished 成功创建连接后调用

  • handleTextMessage 收到客户端消息后调用

  • handleTransportError 连接异常时调用

  • afterConnectionClosed 连接关闭后调用

WebSocketSession是客户端与服务端建立的回话,可以通过close()方法主动关闭连接

TextMessage为收到的消息,可以通过getPayload()方法获取消息内容

WebSocket配置

有了处理器了,就可以将此处理器映射到指定path上了,这需要增加一些配置,Spring提供一个配置接口WebSocketConfigurer,我们来实现它,并启用@EnableWebSocket

import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
​
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
​
 /**
 * 用于将WebSocket处理程序映射到特定URL
 *
 * @param registry
 */
 @Override
 public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
 registry.addHandler(chatWebSocketHandler(), "chat") // 添加消息处理器
 .setAllowedOrigins("*"); // 设置跨域
 }

 /**
 * 自定义消息处理器
 *
 * @return
 */
 @Bean
 public ChatWebSocketHandler chatWebSocketHandler() {
 return new ChatWebSocketHandler();
 }
​
}

重写registerWebSocketHandlers方法,通过registry.addHandler()将消息处理器添加,并指定映射的path,服务端WebSocket地址为 ws://host:port/path

注:需要注意的一点,这里要设置跨域,使用setAllowedOrigins方法即可。

至此WebSocket的服务端就可以使用了,还有一些其他骚操作继续往下看

WebSocket握手拦截器

在建立连接前,我们可以通过握手拦截器来拦截非法请求,需要实现SpringHandshakeInterceptor接口

import org.springframework.web.socket.server.HandshakeInterceptor;
​
public class ChatHandshakeInterceptor implements HandshakeInterceptor {
​
 private final Logger log = LoggerFactory.getLogger(this.getClass());
​
 @Override
 public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map attributes) throws Exception {
 log.info("--------------握手前拦截");
 return true;
 }
​
 @Override
 public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
 log.info("--------------完成握手");
 }
}

实现两个方法:

  • beforeHandshake握手前,该方法返回true表示继续建立连接,返回false则终止

  • afterHandshake握手后

WebSocketConfig配置文件增加

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
 registry.addHandler(chatWebSocketHandler(), "chat") // 添加消息处理器
 .addInterceptors(chatHandshakeInterceptor()) // 添加握手拦截器
 .setAllowedOrigins("*"); // 设置跨域
}
/**
 * 自定义消息拦截器
 *
 * @return
 */
@Bean
public ChatHandshakeInterceptor chatHandshakeInterceptor() {
 return new ChatHandshakeInterceptor();
}
Session空闲失效时间配置

一个会话连接后不可能一直不断开,这需要增加一些配置来约束超时时间;还可以设置消息缓冲区大小等(如果Nginx中配置了超时时间,此处可以忽略),上代码

WebSocketConfig配置文件增加

/**
 * 其他配置,如session空闲失效时间,消息缓冲区大小
 *
 * @return
 */
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
 ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
 container.setMaxTextMessageBufferSize(8192);
 container.setMaxSessionIdleTimeout(10 * 60 * 1000L);
 return container;
}
Nginx配置

大部分服务器都使用了Nginx代理,那么需要增加一些配置来支持WS协议

# 支持WS协议
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
​
# 会话超时时间
proxy_connect_timeout 620;
proxy_send_timeout 620;
proxy_read_timeout 620;

Client端

浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。

创建WebSocket连接

连接协议使用wspath为服务端消息处理器映射的path

var ws = new WebSocket("ws://127.0.0.1:8080/chat");
WebSocket事件与方法
if (typeof (WebSocket) == "undefined") {
    alert("您的浏览器不支持WebSocket")
    return
}

// 打开一个 web socket
var ws = new WebSocket("ws://127.0.0.1:8080/chat");

ws.onopen = function()
{
    // Web Socket 已连接上,使用 send() 方法发送数据
    ws.send("发送数据");
    alert("数据发送中...");
};

ws.onmessage = function (evt) 
{ 
    var received_msg = evt.data;
    alert("数据已接收...");
};

ws.onclose = function()
{ 
    // 关闭 websocket
    alert("连接已关闭..."); 
};

ws.onerror = function () {
    // 连接错误
    alert("连接错误..."); 
    ws.close();
}

四个监听事件

  • onopen 与服务端连接成功

  • onmessage 接收服务端发送的消息

  • onclose 连接关闭

  • onerror 连接异常

两个方法

  • send() 向服务端发送消息

  • close()关闭与服务端的连接

聊天Demo演示

本demo简单实现用户A向用户B发送消息,用户B也可以回复消息,具体内容请移步我的码云!

demo.png

完整代码

springboot-websocket

timg (2).jpg

你可能感兴趣的:(SpringBoot 全家桶 | WebSocket服务端与客户端实例)