SpringBoot : ch07 整合websocket

前言

当涉及到在Spring Boot应用程序中整合WebSocket时,我们可以使用Spring框架提供的功能来实现实时双向通信。WebSocket是一种在Web浏览器和服务器之间进行全双工通信的协议,它允许服务器主动向客户端发送消息,而不需要客户端发起请求。

在本博客中,我们将探讨如何在Spring Boot应用程序中使用WebSocket来建立实时通信。我们将通过一个简单的示例来演示如何配置和使用WebSocket,以及如何处理客户端与服务器之间的消息传递。

首先,我们将介绍WebSocket的基本概念和工作原理,然后引入Spring WebSocket模块,并展示如何配置和启用WebSocket支持。接下来,我们将创建一个WebSocket控制器,处理客户端连接和消息的收发。最后,我们将创建一个前端页面来展示实时通信的效果。

一、WebSocket的基本概念和工作原理

WebSocket是一种在Web浏览器和服务器之间进行全双工通信的协议,它允许服务器主动向客户端发送消息,而不需要客户端发起请求。相比于传统的基于HTTP的轮询技术,WebSocket可以实现更加高效、实时的双向通信。

WebSocket的基本概念和工作原理如下:

1.握手阶段

在WebSocket连接建立之前,需要进行一次握手过程。客户端向服务器发送一个HTTP请求,请求头中包含了Upgrade和Connection字段,表明客户端希望将当前的HTTP连接升级为WebSocket连接。服务器收到请求后,验证请求头信息并响应一个HTTP 101 Switching Protocols响应,表示升级成功,此时WebSocket连接建立完成。

2.数据传输阶段

WebSocket连接建立后,客户端和服务器之间可以进行双向通信。客户端和服务器都可以随时向对方发送消息,并且不需要进行额外的请求和响应。通信过程中,数据以二进制或文本的形式进行传输。

3.断开连接阶段

当客户端或服务器想要关闭WebSocket连接时,可以发送一个特殊的关闭帧,表示结束通信。接收到关闭帧后,对方也会发送一个关闭帧进行确认。之后,WebSocket连接会被断开,通信终止。

总的来说,WebSocket的工作原理可以概括为以下几个步骤:握手阶段建立连接、数据传输阶段双向通信、断开连接阶段结束通信。WebSocket的优点在于它可以实现低延迟、高效的实时双向通信,适用于需要及时响应和交互的应用场景,如在线游戏、在线聊天等。

 

 二、前期准备

1、新建项目,结构如下

2、导入依赖
  <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><image><builder>paketobuildpacks/builder-jammy-base:latest</builder></image><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build>

 这是一个典型的Spring Boot项目的pom.xml文件示例,其中包含了与WebSocket相关的依赖项以及其他常见的依赖项。让我为您解释一下这些依赖项的作用:

  1. spring-boot-starter-websocket: 这个依赖项提供了Spring WebSocket模块的基本功能,包括WebSocket协议的支持和相关的类库。

  2. org.projectlombok:lombok: 这是一个可选的依赖项,用于简化Java代码的编写。它可以通过注解自动生成getter、setter和其他常见的方法,减少样板代码的编写量。

  3. spring-boot-starter-test: 这个依赖项提供了Spring Boot应用程序的测试支持,包括自动化单元测试和集成测试等。

接下来是<build>部分,其中包含了用于构建和打包应用程序的插件配置。具体来说:

  1. spring-boot-maven-plugin: 这个插件可以将Spring Boot应用程序打包为可执行的JAR文件,并提供了其他与构建和运行相关的配置选项。

在这个示例中,还对插件进行了特定的配置。<image>元素指定了用于构建容器镜像的基础镜像,<excludes>元素指定了在镜像构建过程中排除的依赖项,这里排除了lombok。

这是一个基本的pom.xml文件示例,用于构建一个使用WebSocket的Spring Boot应用程序。您可以根据自己的需求进行修改和扩展。

三、配置 WebSocketConfig 配置类

@Configuration
public class WebsocketConfig {/*** 装配 ServerEndpointExporter* 会自动注册带有 @ServerEndpoint 注解的类* @return*/@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}}

这段代码展示了一个典型的WebSocket配置类,通常用于将WebSocket端点暴露给Spring容器。让我为您解释一下这段代码的作用:

  1. @Configuration: 这个注解表明这是一个配置类,它会在Spring应用程序启动时被加载,并且可以包含用@Bean注解标记的方法用于定义bean。

  2. WebsocketConfig: 这是配置类的类名,用于定义WebSocket相关的配置。

  3. @Bean: 这个注解用于将方法返回的对象注册为Spring应用程序上下文中的bean,使其可以被其他组件自动注入和使用。

  4. serverEndpointExporter(): 这是一个@Bean方法,用于创建并返回一个ServerEndpointExporter对象。ServerEndpointExporter是Spring提供的用于扫描带有@ServerEndpoint注解的类并注册其实例的类,从而将其暴露为WebSocket端点。

总的来说,这段代码的作用是创建一个配置类,并在其中定义了一个@Bean方法用于注册ServerEndpointExporter,以便自动注册带有@ServerEndpoint注解的类作为WebSocket端点。这样做可以使得WebSocket端点能够被Spring容器正确管理并且与WebSocket通信进行交互。

四、编写实体类

1、User 实体类
@Data
public class User {private String userName;}

 用于登录,保存登录的用户名称。

 2、Message 实体类
@Data
public class Message {/*** 发送人*/private String sendUser;/*** 发送消息*/private String message;}

封装发送消息的内容和发送人。

五、完成登录及页面

1、登录后台代码

@Controller
public class LoginController {/*** 登录并将用户保存到会话中,重定向到聊天页面* @param user* @param session* @return*/@PostMapping("/user/login")public String login(User user, HttpSession session){session.setAttribute("user",user);return "redirect:/chat.html";}}

 这段代码展示了一个简单的Spring MVC控制器,用于处理用户登录请求并将用户保存到会话中。让我为您解释一下这段代码的作用:

  1. @Controller: 这个注解标识了这个类是一个Spring MVC控制器,它可以处理来自客户端的HTTP请求并返回相应的视图或数据。

  2. LoginController: 这是控制器类的类名,用于处理用户登录请求。

  3. @PostMapping("/user/login"): 这个注解指定了处理POST类型的"/user/login"请求的方法,即当用户提交登录表单时,将调用这个方法进行处理。

  4. public String login(User user, HttpSession session): 这个方法接收一个User对象和HttpSession对象作为参数,表示从用户提交的表单中获取用户信息,并将用户信息保存到会话中。

  5. session.setAttribute("user",user);: 这行代码将用户对象保存到会话中,以便在后续的WebSocket通信中可以使用用户信息进行身份验证和授权等操作。

  6. return "redirect:/chat.html";: 这行代码将HTTP响应重定向到聊天页面(chat.html),即当用户登录成功后,将跳转到聊天页面进行实时通信。

2、登录页面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>用户登录</h1><form method="post" action="user/login">Name:<input type="text" name="userName" /><input type="submit" value="登录">
</form></body>
</html>
  1. <form method="post" action="user/login">: 这个标签定义了一个HTML表单,并指定了提交方法为POST,提交地址为"user/login",即当用户点击登录按钮时,将向"/user/login"地址发送POST请求。

  2. Name:<input type="text" name="userName" />: 这行代码创建了一个输入框,用于用户输入用户名。

  3. <input type="submit" value="登录">: 这行代码创建了一个提交按钮,用于用户提交登录表单。

3、 聊天页面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="js/JQuery文件.txt.js"></script>
</head>
<body>
<h2>聊天室</h2>
<div id="content"></div>
<form id="f1"><input type="text" id="message"/><input type="button" value="发送"/>
</form></body>
</html>
4、效果
 

六、实现聊天功能

1、服务器端

@Slf4j
@Component
@ServerEndpoint(value = "/connect",configurator = HttpSessionConfigutator.class)
public class ChatServer {/*** 用户列表*/private static Map<String, Session> users = new HashMap<>();@OnOpenpublic void onOpen(Session session){// 获取登录的用户User user = (User) session.getUserProperties().get("user");// 保存到用户列表中users.put(user.getUserName(),session);}/*** 接收消息并群发* @param message* @param session*/@OnMessagepublic void onMessage(String message,Session session) throws JsonProcessingException {// 获取发送人User sendUser = (User) session.getUserProperties().get("user");// 封装消息对象Message message1 = new Message();message1.setSendUser(sendUser.getUserName());message1.setMessage(message);// 序列化成 JSON 字符串String json = new ObjectMapper().writeValueAsString(message1);// 群发users.forEach((userName,sess) -> {try {sess.getBasicRemote().sendText(json);} catch (IOException e) {throw new RuntimeException("发送失败",e);}});}/*** 用户离线移除在线用户* @param session*/@OnClosepublic void onClose(Session session){User user = (User) session.getUserProperties().get("user");log.info(user.getUserName() + ":已离线");// 从用户列表移除这个用户users.remove(user.getUserName());}}

这段代码是一个基于Java的WebSocket服务器端实现,用于创建一个聊天服务器。让我为您解释一下这段代码的作用:

  1. @Slf4j:这是一个Lombok注解,用于自动生成日志记录器。

  2. @Component:这是一个Spring注解,将该类声明为一个可被Spring容器管理的组件。

  3. @ServerEndpoint(value = "/connect",configurator = HttpSessionConfigutator.class):这是一个Java WebSocket注解,它将这个类声明为一个WebSocket端点,指定了连接的URL路径为"/connect",并且配置了一个HttpSessionConfigutator来支持获取HttpSession。

  4. private static Map<String, Session> users = new HashMap<>():这是一个静态变量,用于存储用户列表。它使用用户名作为键,WebSocket会话对象Session作为值。

  5. @OnOpen:这是一个Java WebSocket注解,它表示当有新的WebSocket连接打开时,会调用这个方法。在这个方法中,通过从会话的UserProperties中获取登录的用户,然后将用户保存到用户列表中。

  6. @OnMessage:这是一个Java WebSocket注解,它表示当接收到WebSocket消息时,会调用这个方法。在这个方法中,首先获取发送人的用户对象,然后封装成消息对象Message。接着使用ObjectMapper将消息对象序列化为JSON字符串,然后通过遍历用户列表,将消息发送给每个在线用户。

  7. @OnClose:这是一个Java WebSocket注解,它表示当WebSocket连接关闭时,会调用这个方法。在这个方法中,首先获取离线用户的用户对象,然后从用户列表中移除该用户。

总体来说,这段代码实现了一个简单的聊天服务器,通过WebSocket协议实现实时的消息传递功能。当有用户连接到服务器时,将其加入用户列表;当接收到用户发送的消息时,将消息群发给所有在线用户;当用户离线时,将其从用户列表中移除。

2、握手连接处理类 

public class HttpSessionConfigutator extends Configurator {@Overridepublic void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {//获取HttpSessionHttpSession session = (HttpSession) request.getHttpSession();//获取登录用户的信息User user = (User) session.getAttribute("user");//再将用户信息保存到websocket的session的属性中sec.getUserProperties().put("user", user);}}

这个类是一个自定义的WebSocket配置器,它实现了javax.websocket.server.ServerEndpointConfig.Configurator接口。它的作用是在WebSocket握手期间修改握手请求和响应,以便将用户信息从HttpSession传递到WebSocket的会话中。

具体来说,这个类重写了modifyHandshake方法,在WebSocket握手期间被调用。在这个方法中,它首先通过request.getHttpSession()方法获取到当前的HttpSession对象,然后从HttpSession中获取登录用户的信息。接着,它将用户信息保存到WebSocket会话的属性中,使用sec.getUserProperties().put("user", user)语句将用户信息存储在user键下。

通过这样的操作,WebSocket会话就可以在握手成功后获取到用户信息,并且可以在后续的处理过程中使用该信息。这种方式可以实现将用户身份信息从HttpSession传递到WebSocket会话的目的,方便在WebSocket处理逻辑中使用用户信息。

3、客户端代码实现
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="js/JQuery文件.txt.js"></script>
</head>
<body>
<h2>聊天室</h2>
<div id="content"></div>
<form id="f1"><input type="text" id="message"/><input type="button" value="发送"/>
</form>
<script>//实例化ws对象let ws = new WebSocket('ws://localhost:8080/connect');//接收服务端的消息ws.onmessage = function(event) {//先将json字符串转换为json对象let data = $.parseJSON(event.data);//将消息追加到内容区$('#content').append(data.sendUser + ' : ' + data.message + '<br>')}//发送消息$(function(){$(':button').on('click', function(){let msg = $('#message').val();//通过ws发送ws.send(msg);//清空发送框$('#message').val('');});})
</script></body>
</html>
  1. <div id="content"></div>:用于显示聊天内容的区域。
  2. <form id="f1">:定义一个表单,用于输入消息内容。
  3. <input type="text" id="message"/>:文本输入框,用于输入消息。
  4. <input type="button" value="发送"/>:按钮,用于发送消息。
  5. let ws = new WebSocket('ws://localhost:8080/connect');:创建WebSocket对象,连接到服务器的WebSocket地址。
  6. ws.onmessage = function(event) { ... }:当接收到服务端的消息时,执行其中的代码。
  7. let data = $.parseJSON(event.data);:将接收到的消息数据解析为JSON对象。
  8. $('#content').append(data.sendUser + ' : ' + data.message + '<br>'):将发送者和消息内容追加到聊天内容区域。
  9. $(function(){ ... }):当页面加载完成后执行其中的代码。
  10. $(':button').on('click', function(){ ... }):当按钮被点击时执行其中的代码。
  11. let msg = $('#message').val();:获取输入框中的消息内容。
  12. ws.send(msg);:通过WebSocket发送消息给服务器。
  13. $('#message').val('');:清空输入框的内容。

这段代码实现了一个简单的前端聊天室界面,通过WebSocket与后端服务器进行通信,实现了即时的消息收发功能。用户可以在输入框中输入消息,点击发送按钮后,消息会发送给服务器,并显示在聊天内容区域中。同时,页面会接收到其他用户发送的消息,并将其展示在聊天内容区域中。

4、运行效果

七、springboot整合WebSocket的好处

将Spring Boot与WebSocket整合的好处如下:

  1. 实时性:WebSocket提供了双向通信的能力,使得服务器能够主动推送消息给客户端,而不需要客户端不断地发送请求。这样可以实现实时的消息传递,适用于聊天室、即时通讯等场景。

  2. 减少网络开销:相比传统的轮询方式,WebSocket减少了不必要的网络开销。客户端只需要与服务器建立一次连接,之后就可以保持长连接,避免了频繁的请求和响应。

  3. 提高性能:通过减少网络开销和降低服务器负载,WebSocket可以提高系统的整体性能。相比使用HTTP协议进行轮询的方式,WebSocket在消息传输过程中的开销更小,更高效。

  4. 简化开发:Spring Boot框架提供了对WebSocket的良好支持,简化了WebSocket的开发流程。开发者可以通过注解和配置快速实现WebSocket功能,减少了繁琐的手动配置和编码工作。

  5. 跨平台支持:WebSocket是一种基于标准的通信协议,得到了广泛的支持。无论是Web端还是移动端,都可以方便地使用WebSocket进行通信,实现跨平台的即时通讯。

综上所述,Spring Boot整合WebSocket可以提供实时性、性能优化和开发简化等好处,适用于需要实时通信的应用场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/173998.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

387. 字符串中的第一个唯一字符

387. 字符串中的第一个唯一字符 描述 : 给定一个字符串 s &#xff0c;找到 它的第一个不重复的字符&#xff0c;并返回它的索引 。如果不存在&#xff0c;则返回 -1 。 题目 : 387. 字符串中的第一个唯一字符 分析 : 我们可以对字符串进行两次遍历&#xff0c;在第一次遍…

Redis原理之五种数据类型笔记

目录 String List Set ZSet ​ Hash String List Set ZSet Hash

Shell脚本:Linux Shell脚本学习指南(第二部分Shell编程)四

第二部分&#xff1a;Shell编程&#xff08;四&#xff09; 三十一、Shell test命令&#xff08;Shell []&#xff09;详解&#xff0c;附带所有选项及说明 test 是 Shell 内置命令&#xff0c;用来检测某个条件是否成立。test 通常和 if 语句一起使用&#xff0c;并且大部分…

RHEL开发者授权注册

$ sudo subscription-manager register --usernameusername --passwordpassword$ sudo subscription-manager attach --auto查看是否注册 Red Hat 订阅管理&#xff0c;请运行以下命令&#xff1a; $ sudo subscription-manager list --installed

【数据库】执行计划中的两趟算法机制原理,基于排序算法来分析,算法的限制,执行代价以及优化

基于排序的两趟算法 ​专栏内容&#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发&#xff0c;开发的步骤&#xff0c;以及开发过程中的涉及的原理&#xff0c;遇到的问题等&#xff0c;让大家能跟上并且可以一起开发&#xff0c;让每个需要的人成为参与者。 本专栏会定…

Java计算二叉树从根节点到叶子结点的最大路径和

要求从根节点到叶子结点的最大路径和&#xff0c;可以通过递归遍历二叉树来实现。对于二叉树中的每个节点&#xff0c;我们都可以考虑包含该节点的最大路径和。在递归的过程中&#xff0c;我们需要不断更新全局最大路径和。 具体的思路如下&#xff1a; 递归函数设计&#xff1…

服务化通信OPC实操

实操也是基于视频进行一些笔记&#xff0c;没得写就少写了 准备 Nuget包准备&#xff1a;OPCfoundation 一般都是使用Ua&#xff0c;当然也是有&#xff1a; 客户端链接服务器参数&#xff1a;IP Port 认证 登录用户名 Session 的实例化创建 进行使用&#xff1a; 因为Ses…

数据中台具体是怎么解决数据孤岛的?_光点科技

在数字化时代&#xff0c;数据已成为企业的核心资产。然而&#xff0c;由于历史遗留问题、部门壁垒等因素&#xff0c;很多企业面临着“数据孤岛”的问题。数据孤岛是指在一个组织内&#xff0c;数据被分散在不同的系统中&#xff0c;彼此隔离&#xff0c;不能有效整合和利用。…

【版本管理 | Git 】Git最佳实践系列(一) —— LFS .gitignore 最佳实践,确定不来看看?

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

python subprocess

查看python官方文档&#xff1a;最全 p subprocess.Popen([rpng2bdf.exe,[r-o .\tst\myfont.bdf -f myfont -e 65 tst\*.png]],stdoutsubprocess.PIPE,stderr subprocess.PIPE) out,err p.communicate() print(out) 注意&#xff0c;如何将shell命令分解为参数序列可能并…

【文末送书】程序员如何化解35岁危机?

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

报表生成器Stimulsoft用户手册:深入报告

Stimulsoft Reports 是一款报告编写器&#xff0c;主要用于在桌面和Web上从头开始创建任何复杂的报告。可以在大多数平台上轻松实现部署&#xff0c;如ASP.NET, WinForms, .NET Core, JavaScript, WPF, Angular, Blazor, PHP, Java等&#xff0c;在你的应用程序中嵌入报告设计器…

canvas基础:绘制线段,绘制多边形

canvas实例应用100 专栏提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。 canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重要的帮助。 文章目录 使用…

【Linux】第二十一站:文件(一)

文章目录 一、共识原理二、C系列文件接口三、从C过渡到系统&#xff1a;文件系统调用四、访问文件的本质 一、共识原理 文件 内容 属性 文件分为打开的文件 和 没打开的文件 打开的文件&#xff1a;是谁打开的&#xff1f;是进程&#xff01;----所以研究打开的文件本质是研…

使用群晖Synology Office提升生产力:如何多人同时编辑一个文件

使用群晖Synology Office提升生产力&#xff1a;多人同时编辑一个文件 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 文章目录 使用群晖Synol…

【腾讯云云上实验室】探索向量数据库背后的安全监控机制

当今数字化时代&#xff0c;数据安全成为了企业和个人最为关注的重要议题之一。随着数据规模的不断增长和数据应用的广泛普及&#xff0c;如何保护数据的安全性和隐私性成为了迫切的需求。 今天&#xff0c;我将带领大家一起探索腾讯云云上实验室所推出的向量数据库&#xff0c…

《微信小程序开发从入门到实战》学习三十二

3.5 开发我的投票页面与使用tab栏切换页面 实现很简单&#xff0c;简单的列表页面&#xff0c;但是需要加在tabBar那里&#xff0c;加油。 3.5.1 开发我的投票页面 在app.js里的pages的数组里加上"pages/myVote/myVote"&#xff0c;保存了后出现了myVote文件夹。 …

Apache Doris 整合 FLINK 、 Hudi 构建湖仓一体的联邦查询入门

1.概览 多源数据目录&#xff08;Multi-Catalog&#xff09;功能&#xff0c;旨在能够更方便对接外部数据目录&#xff0c;以增强Doris的数据湖分析和联邦数据查询能力。 在之前的 Doris 版本中&#xff0c;用户数据只有两个层级&#xff1a;Database 和 Table。当我们需要连…

新能源钠离子电池污废水如何处理

钠离子电池作为一种新能源电池&#xff0c;已经展示出了广阔的应用前景。然而&#xff0c;随着其生产和使用规模的不断扩大&#xff0c;对其产生的污废水问题也变得越来越重要。如何处理新能源钠离子电池的污废水&#xff0c;已经成为一个必须解决的问题。 首先&#xff0c;我…

数字图像处理(实践篇)八 Harris角点检测

目录 1 涉及的OpenCV函数 2 实践 在图像中每个方向变化都很大的区域就是角点&#xff0c;一个早期的尝试是由 Chris Harris & Mike Stephens 在1998年的论文 A Combined Corner and Edge Detector 完成的。所以现在称之为 Harris角点检测。 1 涉及的OpenCV函数 cornerHa…