1. 什么是WebSocket?

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它允许在浏览器和服务器之间进行实时的、双向的通信。相对于传统的基于请求和响应的 HTTP 协议,WebSocket 提供了一种更有效、更实时的通信方式,适用于需要实时更新、实时通知和实时交互的应用。

WebSocket 的一些关键特点包括:

  1. 全双工通信: WebSocket 允许服务器和客户端在同一连接上同时进行双向通信。这意味着服务器可以随时向客户端推送数据,而不必等待客户端发送请求。
  2. 持久连接: WebSocket 连接一旦建立,会一直保持打开状态,不会像传统的 HTTP 连接那样在每次请求和响应之后关闭。这减少了每次连接建立和关闭的开销,使通信更加高效。
  3. 低延迟: 由于连接保持打开状态,WebSocket 通信具有较低的延迟,适用于实时性要求较高的应用,如实时聊天、实时数据更新等。
  4. 少量的数据交换: 与 HTTP 请求和响应相比,WebSocket 数据交换的开销较小。WebSocket 的帧头相对较小,因此有效载荷的比例更高。
  5. 兼容性: 现代浏览器和大多数服务器支持 WebSocket。此外,WebSocket 协议还定义了一个子协议 STOMP(Streaming Text Oriented Messaging Protocol),用于更高级的消息传递和订阅功能。
  6. 安全性: 与其他网络通信协议一样,WebSocket 通信也需要一些安全性的考虑。可以使用加密协议(如 TLS)来保护数据在网络传输中的安全性。

2. 代码实战

2.1 SpringBoot导入依赖

在pom.xml中导入以下依赖,版本由SpringBoot管理

<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2.2 创建配置类

创建WebSocketConfig配置类,并将其注入到Bean容器中

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

2.3 创建WebSocketServer类

创建WebSocketServer类,并将其注入到Bean容器中

注意:@ServerEndpoint("/WebSocket"),该注解用于配置建立WebSocket连接的路径,可以按需修改。

该类一般拥有以下功能:

  1. WebSocket 端点注册: WebSocket 服务器需要注册一个或多个 WebSocket 端点(Endpoints)。每个端点对应一种处理逻辑,可以处理客户端发送过来的消息,以及向客户端发送消息。这些端点通过注解或配置来定义。
  2. 建立和维护连接: WebSocket 服务器负责监听客户端的连接请求,一旦有客户端连接,服务器会创建一个 WebSocket 会话(Session)来管理这个连接。服务器需要能够维护这些连接,包括打开、关闭、保持心跳等操作。
  3. 消息处理: 一旦客户端连接成功,WebSocket 服务器需要处理客户端发送过来的消息。这可以在 WebSocket 端点中的方法上定义处理逻辑。服务器可以根据不同的业务需求处理不同类型的消息。
  4. 处理异常: 与任何网络通信一样,WebSocket 连接可能会面临各种异常情况,如断开连接、网络问题等。WebSocket 服务器需要能够处理这些异常情况,进行适当的清理和处理。

可以将该类理解为WebSocket生命周期中会调用的方法。

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import javax.websocket.*;
import javax.websocket.server.ServerEndpoint; @Slf4j
@Component
@ServerEndpoint("/WebSocket")
public class WebSocketServer { private Session session; @OnOpen
public void onOpen(Session session) {
this.session = session;
WebSocketManager.sentToUser(session, "WebSocket is connected!");
WebSocketManager.addWebSocketServer(this);
log.info("与SessionId:{}建立连接", session.getId());
} @OnClose
public void onClose() {
WebSocketManager.removeWebSocketServer(this);
log.info("WebSocket连接关闭");
} @OnMessage
public void onMessage(String message, Session session) {
log.info("来自SessionId:{}的消息:{}", session.getId(), message);
} @OnError
public void onError(Session session, Throwable error) {
log.error("Session:{}的WebSocket发生错误", session.getId(), error);
} public Session getSession() {
return session;
} public String getSessionId() {
return session.getId();
}
}

2.4 创建WebSocketServer管理类

该类用于管理WebSocketServer(其实主要是管理Session),如果不需要发送消息给特定用户,那么无需创建该类,在WebSocketServer类中维护一个类变量即可。

import lombok.extern.slf4j.Slf4j;

import javax.websocket.Session;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet; @Slf4j
public class WebSocketManager { private final static CopyOnWriteArraySet<WebSocketServer> webSocketServerSet = new CopyOnWriteArraySet<>(); private final static ConcurrentHashMap<String, WebSocketServer> webSocketServerMap = new ConcurrentHashMap<>(); public static void addWebSocketServer(WebSocketServer webSocketServer){
if (webSocketServer != null){
webSocketServerSet.add(webSocketServer);
webSocketServerMap.put(webSocketServer.getSessionId(), webSocketServer);
}
} public static void removeWebSocketServer(WebSocketServer webSocketServer){
webSocketServerSet.remove(webSocketServer);
webSocketServerMap.remove(webSocketServer.getSessionId());
} /**
* 通过SessionId发送消息给特定用户
* @param
* @param msg
*/
public static void sentToUser(String sessionId, String msg){
Session session = webSocketServerMap.get(sessionId).getSession();
sentToUser(session, msg);
} /**
* 通过Session发送消息给特定用户
* @param session
* @param msg
*/
public static void sentToUser(Session session, String msg){
if (session == null){
log.error("不存在该Session,无法发送消息");
return;
}
session.getAsyncRemote().sendText(msg);
} /**
* 发送消息给所有用户
* @param msg
*/
public static void sentToAllUser(String msg){
for (WebSocketServer webSocketServer : webSocketServerSet) {
sentToUser(webSocketServer.getSession(), msg);
}
log.info("向所有用户发送WebSocket消息完毕,消息:{}", msg);
}
}

3. 测试

使用Postman等工具进行WebSocket连接,连接路径为WebSocket(与前文的@ServerEndpoint内容一致)。建立连接后会收到"WebSocket is connected!"

4. 后续完善

如果你的项目中有登录功能,那么应该在你的登录时将用户的Session记录下来。你可以将Session记录在本地缓存、Redis和Grava缓存等能够建立关联关系的地方。

[超详细]SpringBoot整合WebSocket的更多相关文章

  1. Springboot整合Websocket遇到的坑

    Springboot整合Websocket遇到的坑 一.使用Springboot内嵌的tomcat启动websocket 1.添加ServerEndpointExporter配置bean @Confi ...

  2. SpringBoot 整合 WebSocket

    SpringBoot 整合 WebSocket(topic广播) 1.什么是WebSocket WebSocket为游览器和服务器提供了双工异步通信的功能,即游览器可以向服务器发送消息,服务器也可以向 ...

  3. springboot整合websocket原生版

    目录 HTTP缺点 HTTP websocket区别 websocket原理 使用场景 springboot整合websocket 环境准备 客户端连接 加入战队 微信公众号 主题 HTTP请求用于我 ...

  4. SpringBoot整合websocket简单示例

    依赖 <!-- springboot整合websocket --> <dependency> <groupId>org.springframework.boot&l ...

  5. springboot整合websocket高级版

    目录 sockjs介绍 产生的原因 环境搭建 springboot整合sockjs 使用场景 聊天室开发 点对点通信 群聊 效果 总结 加入战队 微信公众号 上一章节我们说了websocket的优缺点 ...

  6. WebSocket的简单认识&SpringBoot整合websocket

    1. 什么是WebSocket?菜鸟对websocket的解释如下 WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议. WebSocket 使得客户端和服务 ...

  7. springboot整合websocket实现客户端与服务端通信

    定义  WebSocket是通过单个TCP连接提供全双工(双向通信)通信信道的计算机通信协议.此WebSocket API可在用户的浏览器和服务器之间进行双向通信.用户可以向服务器发送消息并接收事件驱 ...

  8. 【Java分享客栈】SpringBoot整合WebSocket+Stomp搭建群聊项目

    前言 前两周经常有大学生小伙伴私信给我,问我可否有偿提供毕设帮助,我说暂时没有这个打算,因为工作实在太忙,现阶段无法投入到这样的领域内,其中有两个小伙伴又问到我websocket该怎么使用,想给自己的 ...

  9. Springboot整合WebSocket实现网页版聊天,快来围观!

  10. springboot整合websocket后运行测试类报错:javax.websocket.server.ServerContainer not available

    springboot项目添加websocket依赖后运行测试类报如下错误: org.springframework.beans.factory.BeanCreationException: Error ...

随机推荐

  1. Django-5:前端模板路径设定TEMPLATES DIRS和调用

    前端模板路径设定:'DIRS': [BASE_DIR / 'templates'] TEMPLATES = [ { 'BACKEND': 'django.template.backends.djang ...

  2. Netty实战(一)

    目录 第一章 Java网络编程 1.1 Java NIO 1.2 选择器 第二章 Netty是什么 2.1 Netty简介 2.2 Netty的特性 2.2.1 设计 2.2.2 易于使用 2.2.3 ...

  3. 基于.NetCore开源的Windows的GIF录屏工具

    推荐一个Github上Start超过20K的超火.好用的屏幕截图转换为 GIF 动图开源项目. 项目简介 这是基于.Net Core + WPF 开发的.开源项目,可将屏幕截图转为 GIF 动画.它的 ...

  4. java中接口,抽象类,具体类之间的关系

    抽象类实现接口,具体类继承于抽象类

  5. .Net7矢量化的性能优化

    前言 矢量化是性能优化的重要技术,也是寄托硬件层面的优化技术.本篇来看下. 概括 一:矢量化支持的问题: 矢量化的System.Runtime.Intrinsics.X86.Sse2.MoveMask ...

  6. Go语言中的结构体:灵活性与可扩展性的重要角色

    1. 引言 结构体是Go语言中重要且灵活的概念之一.结构体的使用使得我们可以定义自己的数据类型,并将不同类型的字段组合在一起,实现更灵活的数据结构.本文旨在深入介绍Go语言中的结构体,揭示其重要性和灵 ...

  7. ClickHouse技术研究及语法简介

    本文对Clickhouse架构原理.语法.性能特点做一定研究,同时将其与mysql.elasticsearch.tidb做横向对比,并重点分析与mysql的语法差异,为有mysql迁移clickhou ...

  8. 论文翻译:2021_Real-Time Denoising and Dereverberation wtih Tiny Recurrent U-Net

    论文地址:微型循环U-Net实时降噪和去混响 论文代码: https://github.com/YangangCao/TRUNet https://github.com/amirpashamobini ...

  9. 温故知新,signalR、RSA加密、ConcurrentQueue队列

    这是一个用户密码异步加解密的Demo,包含了RSA非对称加密,ConcurrentQueue线程安全队列使用,signalR实时推送加解密信息等内容. 说在前面的话 距离上次更新已然快过去一年了,这中 ...

  10. MySQL 存储引擎 InnoDB 内存结构之更改缓冲区

    更改缓冲区(Change Buffer)是一种特殊的数据结构,用于缓存不在缓冲池中的二级索引(secondary index)页的更改.可能来自于INSERT.UPDATE或DELETE操作(数据操作 ...