【Springboot系列】SpringBoot整合WebSocket,既然如此简单(含源码)

本文主要是介绍【Springboot系列】SpringBoot整合WebSocket,既然如此简单(含源码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

      • 前言:
      • 什么是WebSocket?
      • Spring Boot中的WebSocket支持
      • WebSocket和HTTP优劣势
        • WebSocket的优势:
          • 1.实时性:
          • 2.较低的延迟:
          • 3.较小的数据传输量:
          • 4.更好的兼容性:
        • HTTP的优势:
          • 1.简单易用:
          • 2.更广泛的应用:
          • 3.更好的安全性:
      • 示例
        • 版本依赖
        • 代码
          • WebSocketConfig
          • WebSocketServer
          • WebSocketController
          • webSocket.html
        • 测试
          • 打开2个页面
          • 都点击开启socket
          • 都点击发送
      • 总结
      • 源码获取
      • 写在最后

579a429daf314744b995f37351b46548

前言:

在当今互联网时代,实时通信已经成为了许多应用程序的基本需求。

而WebSocket作为一种全双工通信协议,为开发者提供了一种简单、高效的实时通信解决方案。

本文将介绍如何使用Spring Boot框架来实现WebSocket的集成,快速搭建实时通信功能。


什么是WebSocket?

WebSocket是一种在单个TCP连接上进行全双工通信的协议。与传统的HTTP请求-响应模式不同,WebSocket允许服务器主动向客户端推送数据,实现了实时通信的功能。WebSocket协议基于HTTP协议,通过在握手阶段升级协议,使得服务器和客户端可以直接进行数据交换,而无需频繁的HTTP请求。


Spring Boot中的WebSocket支持

Spring Boot提供了对WebSocket的支持,通过集成Spring WebSocket模块,我们可以轻松地实现WebSocket功能。在Spring Boot中,我们可以使用注解来定义WebSocket的处理器和消息处理方法,从而实现实时通信。


WebSocket和HTTP优劣势

image-20231127012922773

WebSocket的优势:
1.实时性:

​ WebSocket是一种全双工通信协议,可以实现服务器主动向客户端推送数据,实现实时通信。相比之下,HTTP是一种请求-响应模式 的协议,需要客户端主动发起请求才能获取数据。

2.较低的延迟:

​ 由于WebSocket使用单个TCP连接进行通信,避免了HTTP的握手和头部信息的重复传输,因此具有较低的延迟。

3.较小的数据传输量:

​ WebSocket使用二进制数据帧进行传输,相比于HTTP的文本数据传输,可以减少数据传输量,提高传输效率。

4.更好的兼容性:

​ WebSocket协议可以在多种浏览器和平台上使用,具有较好的兼容性。

HTTP的优势:
1.简单易用:

​ HTTP是一种简单的请求-响应协议,易于理解和使用。相比之下,WebSocket需要进行握手和协议升级等复杂操作。

2.更广泛的应用:

​ HTTP协议广泛应用于Web开发中,支持各种类型的请求和响应,可以用于传输文本、图片、视频等多种数据格式。

3.更好的安全性:

​ HTTP协议支持HTTPS加密传输,可以保证数据的安全性。

综上,WebSocket适用于需要实时通信和较低延迟的场景,而HTTP适用于传输各种类型的数据和简单的请求-响应模式。在实际应用中,可以根据具体需求选择合适的协议。


示例

版本依赖
模块版本
SpringBoot3.1.0
JDK17
代码
WebSocketConfig
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}
WebSocketServer
@Component
@ServerEndpoint("/server/{uid}")
@Slf4j
public class WebSocketServer {/*** 记录当前在线连接数*/private static int onlineCount = 0;/*** 使用线程安全的ConcurrentHashMap来存放每个客户端对应的WebSocket对象*/private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();/*** 与某个客户端的连接会话,需要通过它来给客户端发送数据*/private Session session;/*** 接收客户端消息的uid*/private String uid = "";/*** 连接建立成功调用的方法* @param session* @param uid*/@OnOpenpublic void onOpen(Session session, @PathParam("uid") String uid) {this.session = session;this.uid = uid;if (webSocketMap.containsKey(uid)) {webSocketMap.remove(uid);//加入到set中webSocketMap.put(uid, this);} else {//加入set中webSocketMap.put(uid, this);//在线数加1addOnlineCount();}log.info("用户【" + uid + "】连接成功,当前在线人数为:" + getOnlineCount());try {sendMsg("连接成功");} catch (IOException e) {log.error("用户【" + uid + "】网络异常!", e);}}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {if (webSocketMap.containsKey(uid)) {webSocketMap.remove(uid);//从set中删除subOnlineCount();}log.info("用户【" + uid + "】退出,当前在线人数为:" + getOnlineCount());}/*** 收到客户端消息后调用的方法* @param message 客户端发送过来的消息* @param session 会话*/@OnMessagepublic void onMessage(String message, Session session) {log.info("用户【" + uid + "】发送报文:" + message);//群发消息//消息保存到数据库或者redisif (StringUtils.isNotBlank(message)) {try {//解析发送的报文ObjectMapper objectMapper = new ObjectMapper();Map<String, String> map = objectMapper.readValue(message, new TypeReference<Map<String, String>>(){});//追加发送人(防止串改)map.put("fromUID", this.uid);String toUID = map.get("toUID");//传送给对应的toUserId用户的WebSocketif (StringUtils.isNotBlank(toUID) && webSocketMap.containsKey(toUID)) {webSocketMap.get(toUID).sendMsg(objectMapper.writeValueAsString(map));} else {//若果不在这个服务器上,可以考虑发送到mysql或者redislog.error("请求目标用户【" + toUID + "】不在该服务器上");}} catch (Exception e) {log.error("用户【" + uid + "】发送消息异常!", e);}}}/*** 处理错误* @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("用户【" + this.uid + "】处理消息错误,原因:" + error.getMessage());error.printStackTrace();}/*** 实现服务器主动推送* @param msg* @throws IOException*/private void sendMsg(String msg) throws IOException {this.session.getBasicRemote().sendText(msg);}/*** 发送自定义消息* @param message* @param uid* @throws IOException*/public static void sendInfo(String message, @PathParam("uid") String uid) throws IOException {log.info("发送消息到用户【" + uid + "】发送的报文:" + message);if (!StringUtils.isEmpty(uid) && webSocketMap.containsKey(uid)) {webSocketMap.get(uid).sendMsg(message);} else {log.error("用户【" + uid + "】不在线!");}}private static synchronized int getOnlineCount() {return onlineCount;}private static synchronized void addOnlineCount() {WebSocketServer.onlineCount++;}private static synchronized void subOnlineCount() {WebSocketServer.onlineCount--;}}
WebSocketController
@RestController
public class WebSocketController {@GetMapping("/page")public ModelAndView page() {return new ModelAndView("webSocket");}@RequestMapping("/push/{toUID}")public ResponseEntity<String> pushToClient(String message, @PathVariable String toUID) throws Exception {WebSocketServer.sendInfo(message, toUID);return ResponseEntity.ok("Send Success!");}
}
webSocket.html
<!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>
<script>var socket;//打开WebSocketfunction openSocket() {if (typeof (WebSocket) === "undefined") {console.log("您的浏览器不支持WebSocket");} else {console.log("您的浏览器支持WebSocket");//实现化WebSocket对象,指定要连接的服务器地址与端口,建立连接.var socketUrl = "http://localhost:8080/socket/server/" + $("#uid").val();//将https与http协议替换为ws协议socketUrl = socketUrl.replace("https", "ws").replace("http", "ws");console.log(socketUrl);if (socket != null) {socket.close();socket = null;}socket = new WebSocket(socketUrl);//打开事件socket.onopen = function () {console.log("WebSocket已打开");//socket.send("这是来自客户端的消息" + location.href + new Date());};//获得消息事件socket.onmessage = function (msg) {console.log(msg.data);//发现消息进入,开始处理前端触发逻辑};//关闭事件socket.onclose = function () {console.log("WebSocket已关闭");};//发生了错误事件socket.onerror = function () {console.log("WebSocket发生了错误");}}}//发送消息function sendMessage() {if (typeof (WebSocket) === "undefined") {console.log("您的浏览器不支持WebSocket");} else {console.log("您的浏览器支持WebSocket");console.log('{"toUID":"' + $("#toUID").val() + '","Msg":"' + $("#msg").val() + '"}');socket.send('{"toUID":"' + $("#toUID").val() + '","Msg":"' + $("#msg").val() + '"}');}}
</script>
<body>
<p>【uid】:
<div><input id="uid" name="uid" type="text" value="1"></div>
<p>【toUID】:
<div><input id="toUID" name="toUID" type="text" value="2"></div>
<p>【Msg】:
<div><input id="msg" name="msg" type="text" value="hello WebSocket2"></div>
<p>【第一步操作:】:
<div><button onclick="openSocket()">开启socket</button>
</div>
<p>【第二步操作:】:
<div><button onclick="sendMessage()">发送消息</button>
</div>
</body></html>
测试
打开2个页面

第一个:

http://localhost:8080/socket/page

image-20231127013642997

第二个:

http://localhost:8080/socket/page

image-20231127013737748

都点击开启socket

image-20231127013910603

都点击发送

image-20231127014019027

至此示例发送完成


总结

通过本文的介绍,我们了解了Spring Boot中如何集成WebSocket,实现实时通信的功能。

WebSocket作为一种高效的实时通信协议,为开发者提供了更好的用户体验和交互性。

希望本文能够帮助快速掌握Spring Boot整合WebSocket的方法,为应用程序添加实时通信功能。


源码获取

如果需要完整源码请关注公众号"架构殿堂" ,回复 "SpringBoot+WebSocket"即可获得


写在最后

感谢您的支持和鼓励! 😊🙏

如果大家对相关文章感兴趣,可以关注公众号"架构殿堂",会持续更新AIGC,java基础面试题, netty, spring boot, spring cloud等系列文章,一系列干货随时送达!

csdn-end

这篇关于【Springboot系列】SpringBoot整合WebSocket,既然如此简单(含源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/427417

相关文章

springboot健康检查监控全过程

《springboot健康检查监控全过程》文章介绍了SpringBoot如何使用Actuator和Micrometer进行健康检查和监控,通过配置和自定义健康指示器,开发者可以实时监控应用组件的状态,... 目录1. 引言重要性2. 配置Spring Boot ActuatorSpring Boot Act

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

java如何分布式锁实现和选型

《java如何分布式锁实现和选型》文章介绍了分布式锁的重要性以及在分布式系统中常见的问题和需求,它详细阐述了如何使用分布式锁来确保数据的一致性和系统的高可用性,文章还提供了基于数据库、Redis和Zo... 目录引言:分布式锁的重要性与分布式系统中的常见问题和需求分布式锁的重要性分布式系统中常见的问题和需求

SpringBoot基于MyBatis-Plus实现Lambda Query查询的示例代码

《SpringBoot基于MyBatis-Plus实现LambdaQuery查询的示例代码》MyBatis-Plus是MyBatis的增强工具,简化了数据库操作,并提高了开发效率,它提供了多种查询方... 目录引言基础环境配置依赖配置(Maven)application.yml 配置表结构设计demo_st

在Ubuntu上部署SpringBoot应用的操作步骤

《在Ubuntu上部署SpringBoot应用的操作步骤》随着云计算和容器化技术的普及,Linux服务器已成为部署Web应用程序的主流平台之一,Java作为一种跨平台的编程语言,具有广泛的应用场景,本... 目录一、部署准备二、安装 Java 环境1. 安装 JDK2. 验证 Java 安装三、安装 mys

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.