一、前言
WebSocket是一种新型的通信协议,它可以在客户端和服务端之间实现双向通信,具有低延迟、高效性等特点,适用于实时通信场景。它是一种基于TCP协议实现的全双工通信协议,使用它可以实现实时通信,不必担心HTTP协议的短连接问题。SpringBoot可以很方便的集成WebSocket实现高效实时的消息推送。
二、特点
1.WebSocket是HTML5的一种新的协议,本质上它是独立的、创建在TCP上的一种协议。
2.通过HTTP/1.1协议的101状态码进行握手。
3.为了达成WebSocket连接,需要浏览器发出请求后服务器进行回应,这个过程也称为握手。
4.WebSocket是一种持久化的协议。
5.WebSocket实现了浏览器和服务器之间全双工通信,能够更好的节省服务器资源和带宽,以此达到实时通讯的目的。
三、前端相关API
1.建立连接
使用new WebSocket(url)创建WebSocket连接。
var url = "ws://mywebsocket";
var websocket = new WebSocket(url);
2.推送消息
通过send方法向服务器发送消息。
websocket.send("hello");
3.接收服务器传过来的数据
websocket.onmessage = function (resp) {
var data = resp.data;
}
4.监听WebSocket打开事件
websocket.onopen = function (event){
// 开始通信事件
}
5.监听WebSocket关闭事件
websocket.onclose = function (event){
// 监听关闭事件
}
6.监听WebSocket关闭事件
websocket.onclose = function (event){
// 监听关闭事件
}
7.WebSocket状态
我们可以通过readyState属性来获取WebSocket对象的状态。
CONNECTION(0):表示正在连接。
OPEN(1):表示已建立连接。
CLOSING(2):表示正在关闭连接。
CLOSED(3):表示已关闭连接。
四、SpringBoot集成WebSocket
1.添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.添加WebSocket配置类
package com.example.nettydemo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @author qx
* @date 2023/12/25
* @des WebSocket配置
*/
@Configuration
public class WebSocketConfig {
/**
* 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3.创建WebSocketServer类,用来进行服务端和客户端之间的交互
package com.example.nettydemo.websocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @author qx
* @date 2023/12/25
* @des WebSocket核心处理类
*/
@Component
@ServerEndpoint("/myWebsocket")
@Slf4j
public class WebSocketServer {
private static List<Session> sessionList;
@OnOpen
public void onOpen(Session session) {
sessionList = new ArrayList<>();
sessionList.add(session);
log.info("websocket建立连接成功");
}
@OnMessage
public void onMessage(String message) {
log.info("接收到客户端的数据:{}", message);
}
@OnError
public void one rror(Throwable error) {
log.info("连接客户端失败:{}", error.getMessage());
}
@OnClose
public void onClose() {
log.info("websocket断开连接");
}
/**
* 实现服务端发送消息
*
* @param msg 消息内容
* @throws IOException
*/
public void sendMsg(String msg) throws IOException {
sessionList.get(0).getBasicRemote().sendText(msg);
}
}
我们用到了几个注解,分别解释一下它们的含义。
注解 | 作用 |
@ServerEndpoint | 创建一个服务端的URL,客户端通过这个URL来连接服务端 |
@OnOpen | 打开连接触发事件 |
@OnMessage | 收到接收消息事件 |
@OnClose | 关闭连接触发事件 |
@OnError | 处理发生错误的事件 |
4.创建控制层
package com.example.nettydemo.controller;
import com.example.nettydemo.websocket.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import java.io.IOException;
/**
* @author qx
* @date 2023/12/25
* @des
*/
@RestController
@RequestMapping("/websocket")
public class WebSocketController {
@Autowired
private WebSocketServer webSocketServer;
/**
* 跳转WebSocket通信页面
*/
@GetMapping("/page")
public ModelAndView toPage() {
return new ModelAndView("webSocket");
}
/**
* 服务端发送消息
*
* @param msg 消息内容
* @throws IOException
*/
@GetMapping("/send")
public void sendData(String msg) throws IOException {
webSocketServer.sendMsg(msg);
}
}
5.创建前端页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebSocket测试</title>
</head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<body>
<input type="text" id="msg" placeholder="请填写数据"/>
<button onclick="sendData()">发送数据</button>
<script>
var websocket;
if (typeof (WebSocket) === 'undefined') {
alert("您的浏览器不支持WebSocket");
} else {
// 8090是服务器的端口
websocket = new WebSocket("ws://localhost:8090/myWebsocket");
websocket.onopen = function () {
console.log("webSocket已连接")
}
websocket.onmessage = function (event) {
console.log("接收到服务器的消息:" + event.data)
}
websocket.onclose = function () {
console.log("WebSocket已关闭")
}
websocket.onerror = function () {
console.log("WebSocket发生错误")
}
}
function sendData() {
if (websocket != null) {
websocket.send($("#msg").val());
} else {
alert("您的浏览器不支持WebSocket");
}
}
</script>
</body>
</html>
6.测试
我们打开WebSocket测试页面,控制台显示已成功连接的日志。
接着我们发送数据给服务端,点击发送按钮后,服务端控制台日志显示收到来自客户端的数据。
2023-12-25 10:48:50.735 INFO 4660 --- [nio-8090-exec-4] c.e.nettydemo.websocket.WebSocketServer : 接收到客户端的数据:我是客户端数据
最后我们调用服务端发送消息给客户端的方法。
在客户端的控制台日志上我们看到了来自服务端的消息。