手动部署 webSocket 相关 SpringMVC 服务 以及前端 webSocket 构建
通过本文,您将学习到如何手动创建和部署 WebSocket 相关的 SpringMVC服务。这些技能将帮助您在实际开发中更好地应用 ws 协议相关知识,提高 web 应用程序(网站 等)的实时性和交互性。
# 手动部署 webSocket 相关 SpringMVC 服务 以及前端 webSocket 构建
*web 技术栏*
通过本文,您将学习到如何手动创建和部署 WebSocket 相关的 SpringMVC服务。这些技能将帮助您在实际开发中更好地应用 ws 协议相关知识,提高 web 应用程序(网站 等)的实时性和交互性。
## 目录
[TOC]

## 什么是 WebSocket
WebSocket是一种网络通信协议,它提供了与TCP套接字类似的接口,使得客户端和服务器之间的全双工通信成为可能。WebSocket可以在HTTP协议的基础上升级使用,现称之为 WS 协议,使得它成为了一种高效、快速、实时的网络通信方式。在WebSocket的通信过程中,客户端和服务器需要建立连接,然后进行数据的传输和接收。与HTTP协议不同,WebSocket连接是持久化的,可以保持长时间的数据传输。因此,WebSocket被广泛应用于实时性要求较高的应用场景,如在线游戏、实时聊天、股票交易等。
### 什么是 ws 协议
我们知道在 web 中,如果想要使用软件,就要通过一个网站进行访问,在这个访问过程中通常会需要一个http网址,形如`http://xxx.xxx` 又或者是 `http://xxx.xxx`,当进行访问的时候,系统会自动的根据网址找到对应的web服务器,使用[**http协议**](https://baike.baidu.com/item/HTTP/243074?fr=ge_ala "**http协议**")获取到网站数据,这样的访问方式是短连接,每个请求返回一次回复,不能满足私聊这类功能,因此对http进行了一个升级,称之为[ **ws 协议**](https://baike.baidu.com/item/WebSocket/1953845?fr=ge_ala " **ws 协议**"),其url格式形如`ws://xxx.xxx` 接下来我们将会频繁的解除它。
## 后端 webSocket 构建
webSocket 的服务依赖一台服务器来进行,因此我们需要先准备一台具有webSocket服务的服务器,在这里我们将通过 SpringMVC 来实现这样的操作,因此我们需要先进行后端的构建,接下来,我们正式开始!
### 引入 maven 依赖
首先我们的 由于使用的是 SpringMVC,SpringMVC 已经实现了对于 webSocket 的支持,因此在这里需要导入 SpringMVC 的依赖。
```xml
<dependencies>
<!-- 导入 Java Servlet 的依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- 导入 Spring MVC 的依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
```
### 实现 SpringMVC 的 TextWebSocketHandler 处理类
TextWebSocketHandler是AbstractWebSocketHandler的子类,它会拒绝处理二进制消息。如果收到二进制消息的时候,将会关闭WebSocket连接。与之类似,BinaryWebSocketHandler也是AbstractWebSocketHandler的子类,它重载了handleTextMessage()方法,如果接收到文本消息的话,将会关闭连接。
**PS:如果有二进制数据只需要更改一个处理类的名字,其它的操作差不多,在这里使用文本处理类进行演示,便于进行数据观察
**
#### 查看 TextWebSocketHandler 中的可重写方法
下面就是一个文本处理类的基本框架,每个函数具有不同的意义,在这里进行了注释
```java
package top.lingyuzhao.SpringTest.controller;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
/**
* ws 后端处理类
* @author zhao
*/
public final class WsTest extends TextWebSocketHandler {
// 连接操作建立之后
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
super.afterConnectionEstablished(session);
// 在连接建立后,可以在此处进行一些初始化操作
}
// 接收到信息
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
super.handleMessage(session, message);
// 在接收到消息时调用,可以处理接收到的消息,根据消息的类型(文本、二进制等)进行相应的处理。
}
// 接收到文本信息
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
super.handleTextMessage(session, message);
// 在接收到文本消息时调用,可以在此处处理接收到的文本消息。
}
@Override
protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
super.handlePongMessage(session, message);
// 在接收到WebSocket的Pong消息时调用。Pong消息是WebSocket协议中的一种消息类型,它的作用主要是告诉服务器,客户端依然在线,并且可以接收服务器发送的消息。在某些情况下,如果服务器发送了消息给客户端,但是客户端没有及时响应,服务器就会发送一个Pong消息给客户端,以保持连接的活跃状态。在此方法中,可以处理接收到的Pong消息。
}
// 发生了错误信息
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
super.handleTransportError(session, exception);
// 当发生传输错误时调用,可以在此处处理传输错误的情况。
}
// 连接关闭之后
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
super.afterConnectionClosed(session, status);
// 在WebSocket连接关闭之后调用,可以在此处进行一些关闭连接后的清理操作。
}
@Override
public boolean supportsPartialMessages() {
return super.supportsPartialMessages();
// 返回是否支持部分消息。如果返回true,则表示支持部分消息;如果返回false,则表示不支持部分消息。
}
}
```
#### 开始重写方法
在这里我们并不需要将所有的方法都实现,仅仅使用 webSocket 进行一个简单的文本传输演示,更能达到很好的学习效果,降低学习门槛。
##### 重写 初始化函数 afterConnectionEstablished
在这里我们将在连接建立成功之后打印一些信息
```
// 连接操作建立之后
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
super.afterConnectionEstablished(session);
// 在连接建立后,可以在此处进行一些初始化操作
System.out.println("与 " + session.getId() + " 的连接已建立!");
}
```
##### 重写 文本消息处理函数 handleTextMessage
```
// 接收到文本信息
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
super.handleTextMessage(session, message);
// 在接收到文本消息时调用,可以在此处处理接收到的文本消息。
// TODO 在这里我们直接将数据稍加修改,然后回复给发送者 相当于是下面的样子
/*
前端 -> 你好 -> 后端
后端 -> 后端服务器接收到了:你好 -> 前端
*/
session.sendMessage(new TextMessage(
"后端服务器接收到了:" + message.getPayload()
));
}
```
##### 重写 连接关闭函数(相当于是连接的析构函数)afterConnectionClosed
```
// 连接即将关闭之后
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
super.afterConnectionClosed(session, status);
// 在WebSocket连接关闭之后调用,可以在此处进行一些关闭连接后的清理操作。
// TODO 在这里我们打印一些数据
System.out.println("与 " + session.getId() + " 的连接已关闭!");
}
```
##### 全类展示
```
package top.lingyuzhao.SpringTest.controller;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
/**
* ws 后端处理类
* @author zhao
*/
public final class WsTest extends TextWebSocketHandler {
// 连接操作建立之后
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
super.afterConnectionEstablished(session);
// 在连接建立后,可以在此处进行一些初始化操作
System.out.println("与 " + session.getId() + " 的连接已建立!");
}
// 接收到信息
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
super.handleMessage(session, message);
// 在接收到消息时调用,可以处理接收到的消息,根据消息的类型(文本、二进制等)进行相应的处理。
}
// 接收到文本信息
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
super.handleTextMessage(session, message);
// 在接收到文本消息时调用,可以在此处处理接收到的文本消息。
// TODO 在这里我们直接将数据稍加修改,然后回复给发送者 相当于是下面的样子
/*
前端 -> 你好 -> 后端
后端 -> 后端服务器接收到了:你好 -> 前端
*/
session.sendMessage(new TextMessage(
"后端服务器接收到了:" + message.getPayload()
));
}
@Override
protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
super.handlePongMessage(session, message);
// 在接收到WebSocket的Pong消息时调用。Pong消息是WebSocket协议中的一种消息类型,它的作用主要是告诉服务器,客户端依然在线,并且可以接收服务器发送的消息。在某些情况下,如果服务器发送了消息给客户端,但是客户端没有及时响应,服务器就会发送一个Pong消息给客户端,以保持连接的活跃状态。在此方法中,可以处理接收到的Pong消息。
}
// 发生了错误信息
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
super.handleTransportError(session, exception);
// 当发生传输错误时调用,可以在此处处理传输错误的情况。
}
// 连接即将关闭之后
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
super.afterConnectionClosed(session, status);
// 在WebSocket连接关闭之后调用,可以在此处进行一些关闭连接后的清理操作。
// TODO 在这里我们打印一些数据
System.out.println("与 " + session.getId() + " 的连接已关闭!");
}
@Override
public boolean supportsPartialMessages() {
return super.supportsPartialMessages();
// 返回是否支持部分消息。如果返回true,则表示支持部分消息;如果返回false,则表示不支持部分消息。
}
}
```
### 将处理类注册给 SpringMVC
首先我们需要创建一个 SpringMVC 的 WebSocket 配置类,其类型是 `WebSocketConfigurer` 我们需要拓展重写它的注册函数,并在注册函数中手动注册 我们写好的 webSocket 处理类。
相当于是我们手动干预了SpringMVC 的注册流程,在注册的流程中,我们注册了一个自己的处理类,下面就是代码以及对应的解释。
```
package top.lingyuzhao.SpringTest.conf;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import top.lingyuzhao.SpringTest.controller.WsTest;
/**
* Spring mvc 的配置类
* 这是一个Spring MVC的配置类,用于设置和配置Spring MVC和WebSocket的相关设置。
*
* @author zhao
* 作者:赵
*/
@Configuration // 标注这个类是一个配置类
@EnableWebMvc // 启用Spring MVC的功能
@EnableWebSocket // 启用WebSocket的功能
public class SpringConfig implements WebSocketConfigurer { // 这个类实现了一个WebSocket的配置接口
/**
* 注册WebSocket处理器
* 这个方法用于注册WebSocket处理器,并设置相应的处理路径和拦截器。
*/
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(new WsTest(), "/wsTest") // 添加一个WebSocket处理器,路径为/wsTest
.addInterceptors(new HttpSessionHandshakeInterceptor()) // 在WebSocket握手时添加一个拦截器,用于处理HTTP会话
.setAllowedOrigins("*"); // 设置允许跨域访问的来源,星号代表所有来源都允许。 // 允许跨域访问,设置允许的来源为所有来源。
}
}
```
### 打包并部署到服务器(不同服务器软件部署方式不同,在这里暂时略过)
## 前端 webSocket 构建
### webSocket 基础操作
#### 实例化 webSocket
```js
// 指定后端的ws 服务路径 就是在进行注册时候添加的 /wsTest
const p = "/wsTest";
// 指定后端程序的路径 根据不同服务器来进行设置 我这里打包的结果是 WebTest_war.war 路径是 WebTest_war
const p1 = "WebTest_war";
// 在这里实例化出 webSocket 需要注意 在实例化成功的一瞬间,就会开始向后端发送连接数据
const webSocket = new WebSocket(`ws://localhost:8080/${p1}/${p}`);
```
#### 设置 webSocket 的各种事件
这个操作就很像是在前面的后端中实现 ws 处理类一样,有很多的函数会在不同的时机调用,而我们在前端设置事件回调函数的操作就是 JS 中的回调一样,不过事件的名字有一些区别,下面就是一些 ws JS 中事件的汇总。
```
连接建立(opening):在 WebSocket 连接建立之前,浏览器会使用 HTTP 请求来询问服务器是否支持 WebSocket,如果支持,WebSocket 协议就会用于两者之间的通信。
连接关闭(closing):WebSocket 连接关闭时,会触发 closing 事件。
连接已建立(open):WebSocket 连接建立后,会触发 open 事件。
收到消息(message):当 WebSocket 连接接收到消息时,会触发 message 事件。
错误(error):当 WebSocket 连接出现错误时,会触发 error 事件。
```
下面就是设置的代码
```js
// 设置连接成功之后的回调函数
webSocket.onopen = () => {
console.info("连接建立成功!!!")
}
// 设置收到消息之后的回调函数
webSocket.onmessage = (message) => {
console.info(message.data)
}
// 设置连接被断开之后的回调函数
webSocket.onclose = () => {
console.info("连接被断开!!!")
}
```
#### 在 JS 中使用 webSocket 发送数据
下面是一个 webSocket 发送数据的调用示例
```
webSocket.send("你好")
```
当连接建立之后 通过调用 send 函数就可以实现数据发送,因此我们可以直接将发送动作绑定在连接完毕的回调中,下面就是代码
```js
// 设置连接成功之后的回调函数
webSocket.onopen = () => {
console.info("连接建立成功!!!")
webSocket.send("你好")
console.info("已发送数据 ”你好“")
}
```
#### 运行 HTML 文件
当我们运行文件之后 F12 终端 打印的执行结果如下所示。
```
连接建立成功!!!
已发送数据 ”你好“
后端服务器接收到了:你好
```
------
***操作记录***
作者:[root](http://www.lingyuzhao.top/index.html?search=1 "root")
操作时间:2023-12-09 21:40:58 星期六
事件描述备注:保存/发布
[](如果不需要此记录可以手动删除,每次保存都会自动的追加记录)