spring boot 项目 跟 JavaScript 简单 websocket 使用

news/2024/9/19 4:49:12/ 标签: javascript, vue.js, 前端, java, spring boot

文章目录

websocket 简绍

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

WebSocket 的优势包括:

全双工通信:允许服务器主动向客户端发送信息,同时也能够提供客户端到服务器的低延迟通信。
减少带宽消耗:一旦建立连接之后,通信开销很小,因为不需要HTTP头部。
创建更丰富的交互体验:实时更新数据的能力,使得应用能够更加流畅地响应用户的动作

可以通过 JavaScript 的 WebSocket 对象来创建一个 WebSocket 连接。

var ws = new WebSocket('ws://localhost:8080');

JavaScript 设置

处理事件

WebSocket 对象提供了几个事件处理器来处理连接的状态变化:
open:连接成功建立时触发。
message:接收到消息时触发。
error:发生错误时触发。
close:连接关闭时触发。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>WebSocket Example</title><script>javascript>javascript">document.addEventListener('DOMContentLoaded', function () {const socket = new WebSocket('ws://localhost:8080/websocket');socket.onopen = function (event) {console.log('WebSocket connection established.');};socket.onmessage = function (event) {console.log('Received from server:', event.data);};socket.onclose = function (event) {console.log('WebSocket connection closed.');};socket.onerror = function (error) {console.error('WebSocket error:', error);};function sendMessage() {let message = document.getElementById('message').value;socket.send(message);console.log('Sent message:', message);}});</script>
</head>
<body><input type="text" id="message" placeholder="Type your message here"><button onclick="javascript>javascript language-javascript>javascript">sendMessage()">Send Message</button>
</body>
</html>

确保你的服务器端已正确配置,并且能够接收来自客户端的连接请求。
使用HTTPS和WSS(加密的WebSocket)可以提高安全性,特别是在生产环境中。
如果你的服务器部署在不同的域上,请确保服务器配置允许跨域访问。

Java 服务端设置

导jar包

通过 maven 导入 spring boot 中 集成的 websocket jar 包

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
创建WebSocket端点
@EnableWebSocket

@EnableWebSocket 是 Spring 框架中的一个注解,用于启用 WebSocket 支持。当一个类被标记为此注解时,Spring 会自动配置必要的组件来处理 WebSocket 请求。这个注解通常应用在一个配置类上,该类负责设置 WebSocket 的处理逻辑。

registerWebSocketHandlers
  • registerWebSocketHandlers 是 Spring WebSocket 框架中的一个重要方法,它用来注册 WebSocket 处理器(WebSocketHandler)。这个方法是 WebSocketConfigurer 接口中定义的一个抽象方法,需要在你的配置类中实现。通过这个方法,你可以指定哪些路径映射到特定的 WebSocket 处理器,并可以配置其他相关选项。
  • addHandler 方法:接受两个参数,一个是 WebSocketHandler 的实例,另一个是 WebSocket 终结点的 URL 映射。
  • setAllowedOrigins 方法:指定哪些源(域名)可以访问你的 WebSocket 终结点。如果设置为 “*”,则表示任何源都可以访问。
  • withSockJS 方法:这是一个可选的配置项,用于启用 SockJS,它是一种兼容性更好的 WebSocket 实现,能够在不支持原生 WebSocket 的浏览器上使用其他传输方式(如长轮询)。

接下来,定义一个WebSocket处理器类,并配置一个端点来接受WebSocket连接:

java">import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {private final WebSocketHandler webSocketHandler;public WebSocketConfig(WebSocketHandler webSocketHandler) {this.webSocketHandler = webSocketHandler;}@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(webSocketHandler, "/websocket").setAllowedOrigins("*");}
}

这里我们定义了一个WebSocket配置类,并注册了WebSocket处理器。/websocket 是WebSocket的端点路径。

实现WebSocket处理器
afterConnectionEstablished
java">void afterConnectionEstablished(WebSocketSession session) throws Exception;
  • afterConnectionEstablished 是 WebSocketHandler 接口中定义的一个方法,它会在 WebSocket 连接成功建立之后被调用。这个方法为你提供了一个机会来执行一些初始化操作,例如记录连接信息、将连接加入到一个管理连接的集合中,或者发送初始消息给客户端。
  • WebSocketSession session —— 表示新建立的 WebSocket 会话。
  • Exception —— 如果处理过程中出现任何异常,可以抛出
afterConnectionClosed
java">void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception;
  • afterConnectionClosed 是 WebSocketHandler 接口中定义的一个方法,它会在 WebSocket 连接关闭时被调用。这个方法允许你在连接关闭后执行一些清理操作,例如从会话管理器中移除会话、记录关闭事件或者发送通知给其他客户端。
  • WebSocketSession session:表示已关闭的 WebSocket 会话。
  • CloseStatus status:表示关闭状态的原因。CloseStatus 是一个枚举类型,提供了标准的关闭码和关闭原因,例如 NORMAL_CLOSURE(正常关闭)、GOING_AWAY(离开)、PROTOCOL_ERROR(协议错误)等。
  • 抛出:Exception —— 如果处理过程中出现任何异常,可以抛出。
handleTextMessage
java">void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception;
  • handleTextMessage 是 WebSocketHandler 接口中定义的一个方法,用于处理从客户端接收到的文本消息。当客户端发送文本消息时,这个方法会被调用。对于二进制消息,则会调用 handleBinaryMessage 方法。
  • WebSocketSession session:表示当前的 WebSocket 会话。
  • TextMessage message:包含从客户端接收到的文本消息。
  • 抛出:Exception —— 如果处理过程中出现任何异常,可以抛出
    现在我们需要实现一个WebSocket处理器类来处理连接事件:
java">import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;import java.util.concurrent.ConcurrentHashMap;import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.concurrent.ConcurrentHashMap;public class WebSocketHandler extends TextWebSocketHandler {private static final ConcurrentHashMap<String, WebSocketSession> sessions = new ConcurrentHashMap<>();@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {super.afterConnectionEstablished(session);String id = session.getId();sessions.put(id, session);System.out.println("WebSocket connection established with session ID: " + id);}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {super.afterConnectionClosed(session, status);String id = session.getId();sessions.remove(id);System.out.println("WebSocket connection closed with session ID: " + id);}public void sendMessageToSession(String sessionId, String message) {WebSocketSession session = sessions.get(sessionId);if (session != null && session.isOpen()) {try {session.sendMessage(new TextMessage(message));} catch (Exception e) {e.printStackTrace();}}}public void broadcastMessage(String message) {for (WebSocketSession session : sessions.values()) {if (session.isOpen()) {try {session.sendMessage(new TextMessage(message));} catch (Exception e) {e.printStackTrace();}}}}
}

现在我们可以使用WebSocketHandler类中的sendMessageToSession或broadcastMessage方法来发送数据给前端
发送给特定会话:如果想要向特定的客户端发送消息,可以使用sendMessageToSession方法。你需要知道客户端的会话ID。

webSocketHandler.sendMessageToSession(sessionId, "Hello, client!");

广播消息:如果你想向所有已连接的客户端广播消息,可以使用broadcastMessage方法

webSocketHandler.broadcastMessage("Hello, everyone!")
注销WebSocket连接

要在Java后端注销WebSocket连接,可以通过调用 WebSocketHandler 类中的 removeSession 方法来实现。例如,你可以从HTTP请求或其他服务中调用此方法:

@GetMapping("/logout/{sessionId}")
public ResponseEntity<String> logout(@PathVariable String sessionId) {WebSocketHandler handler = new WebSocketHandler(); // 或者通过依赖注入获取handler.removeSession(sessionId);return ResponseEntity.ok("Session " + sessionId + " has been closed.");
}

自己定义一个 固定id 方便使用

  • 前端 JavaScript 代码
    • 创建WebSocket连接:在DOM加载完成后,创建一个WebSocket连接。
    • 发送握手消息:在连接建立后,发送一个包含固定ID的握手消息。
    • 处理接收到的消息:设置消息接收处理函数,用于接收后端发送的数据。
  • 后端 Java 代码
    • 配置WebSocket处理器:配置WebSocket处理器,注册WebSocket路径。
    • 处理握手消息:接收前端发送的握手消息,并根据消息内容保存客户端ID与WebSocket会话的映射。
    • 发送消息:提供方法根据客户端ID发送消息。

前端 javascript>javascript

<!DOCTYPE html>
<html l	ang="en">
<head><meta charset="UTF-8"><title>WebSocket Client Example</title>
</head>
<body><input type="text" id="messageInput" placeholder="Enter your message here"><button id="sendButton">Send Message</button><div id="log"></div><script>javascript>javascript">document.addEventListener('DOMContentLoaded', function () {const socket = new WebSocket('ws://example.com/websocket');socket.onopen = function (event) {console.log('WebSocket connection established.');// 固定的客户端IDconst clientId = 'client-123';// 发送握手消息socket.send(JSON.stringify({type: 'handshake',clientId: clientId,message: 'Hello, server!'}));};socket.onmessage = function (event) {console.log('Received from server:', event.data);document.getElementById('log').textContent += 'Received from server: ' + event.data + '\n';};socket.onclose = function (event) {console.log('WebSocket connection closed.');document.getElementById('log').textContent += 'WebSocket connection closed.\n';};socket.onerror = function (error) {console.error('WebSocket error:', error);document.getElementById('log').textContent += 'WebSocket error: ' + error + '\n';};document.getElementById('sendButton').addEventListener('click', function () {let message = document.getElementById('messageInput').value;if (socket.readyState === WebSocket.OPEN) {socket.send(message);document.getElementById('log').textContent += 'Sent message: ' + message + '\n';} else {alert('WebSocket connection is not open.');}});});</script>
</body>
</html>

java 服务器端配置

java">import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;public class WebSocketHandler extends TextWebSocketHandler {private static final Map<String, WebSocketSession> clientSessions = new ConcurrentHashMap<>();private static final ObjectMapper objectMapper = new ObjectMapper();@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {super.afterConnectionEstablished(session);String sessionId = session.getId();System.out.println("WebSocket connection established with session ID: " + sessionId);}@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {String payload = message.getPayload();HandshakeMessage handshakeMessage = objectMapper.readValue(payload, HandshakeMessage.class);if ("handshake".equals(handshakeMessage.getType())) {String clientId = handshakeMessage.getClientId();String sessionId = session.getId();// 存储clientId与sessionId的映射关系clientSessions.put(clientId, session);// 可以选择回复客户端确认握手成功的消息session.sendMessage(new TextMessage("Handshake successful"));}}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {super.afterConnectionClosed(session, status);String sessionId = session.getId();System.out.println("WebSocket connection closed with session ID: " + sessionId);// 移除会话clientSessions.values().removeIf(s -> s.getId().equals(sessionId));}public void sendMessageToClient(String clientId, String message) {WebSocketSession session = clientSessions.get(clientId);if (session != null && session.isOpen()) {try {session.sendMessage(new TextMessage(message));} catch (Exception e) {e.printStackTrace();}}}// 定义握手消息模型private static class HandshakeMessage {private String type;private String clientId;private String message;// Getters and setters}
}

http://www.ppmy.cn/news/1520536.html

相关文章

C# 使用微软OFFICE库操作excel

C# 使用微软OFFICE库操作excel写入数据 using System; using Excel Microsoft.Office.Interop.Excel;namespace ExcelExample {class Program{static void Main(string[] args){// 创建Excel应用程序实例Excel.Application excelApp new Excel.Application();// 让Excel应用…

Python 读写 Excel 文件:创建、遍历、更新与样式处理

Excel 是广泛使用的电子表格软件&#xff0c;用于数据存储、分析和可视化。Python 通过第三方库如 openpyxl 和 pandas 提供了丰富的功能来读写 Excel 文件。本文将详细介绍如何使用 Python 进行 Excel 文件的创建、遍历、更新、删除以及样式处理等操作。 1. 安装必要的库 首…

【计算机网络】socket编程 --- 实现简易TCP网络程序

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 如果文章对…

【Pytorch实用教程】tqdm的作用:在循环中显示进度条

tqdm 是一个 Python 库,用于在循环中显示进度条。它能够为任何可迭代对象(例如列表、生成器、数据加载器等)添加一个可视化的进度条,使用户可以实时查看程序的执行进度。 在数据科学和机器学习领域,tqdm 经常用于显示训练和验证过程中的进度。例如,在训练神经网络时,由…

编译 ffmpeg 以支持AVS格式视频解码与解码

前言 当前文章介绍如何在Linux下使用FFmpeg转码其他视频格式到AVS格式的指南&#xff0c;包括编译FFmpeg以支持XAVS编码和如何使用FFmpeg进行转码。 AVS (Audio Video Coding Standard) 格式是一种由中国主导制定的视频编码标准&#xff0c;全称为“中国数字音视频编解码技术…

装饰器模式及应用【理论+代码】

装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其结构。这种设计模式通过创建一个包装对象&#xff0c;即装饰器&#xff0c;来封装实际对象。 装饰器模式的主要组成&#…

图像处理之透视变换

透视变换 什么是透视变换透视变换有什么用 什么是透视变换 透视变换&#xff08;把斜的图变正&#xff0c;也就是一种坐标系到另外一种坐标系&#xff09;是一种图像处理技术&#xff0c;它利用透视中心、像点、目标点三点共线的条件&#xff0c;按透视旋转定律使承影面&#…

python读取excel数据

在处理Excel数据时&#xff0c;Python 提供了多种强大的库来读取、处理以及分析这些数据。最常用的库之一是 pandas&#xff0c;它建立在 numpy、matplotlib 和 scipy 等库之上&#xff0c;为数据分析和操作提供了高级的、易于使用的数据结构和数据分析工具。另一个流行的库是 …

Java设计模式—策略模式(Strategy)

模式动机 完成一项任务&#xff0c;往往可以有多种不同的方式&#xff0c;每一种方式称为一个策略&#xff0c;我们可以根据环境或者条件的不同选择不同的策略来完成该项任务。在软件开发中也常常遇到类似的情况&#xff0c;实现某一个功能有多个途径&#xff0c;此时可以使用…

【运维监控】prometheus+node exporter+grafana 监控linux机器运行情况(2)

本示例是通过prometheus的node exporter收集主机的信息&#xff0c;然后在grafana的dashborad进行展示。本示例使用到的组件均是最新的&#xff0c;下文中会有具体版本说明&#xff0c;linux环境是centos。本示例分为四个部分&#xff0c;即prometheus、grafana、node exporter…

【MySQL】如何优化 SQL UPDATE 语句以提升性能

如何优化 SQL UPDATE 语句以提升性能 在日常开发中&#xff0c;优化 SQL 查询是非常关键的一项任务&#xff0c;尤其是在处理大量数据时。本文将通过一个 UPDATE 语句的优化过程&#xff0c;探讨如何提升 SQL 性能。 示例场景 假设我们有以下两张表&#xff1a; 表 table_a…

打造一流的研发型企业--- 金发科技研发驱动力初探

2006年3月29日&#xff0c;国家发改委副主任欧新黔亲自为金发科技颁发了“中国改性塑料行业第一位”、“中国合成材料制造业十强”、“中国石油化工全行业百强”三块铜牌证书&#xff0c;金发科技终于成为名符其实的行业“老大”。公司产品销售额增长迅速&#xff0c; 2006年完…

开发基础软件安装地址(持续更新中)

开发基础软件安装地址&#xff08;持续更新中&#xff09; 如果需要新增下载工具可以在评论中留言 欢迎广大开发人员在评论区讨论关于环境安装遇到的问题 正文会持续更新。。。 java常用的jdk1.8版本安装包 链接&#xff1a;jdk-8u421-windows-x64.exe idea java常用的开发工具…

提交保存,要做重复请求拦截,避免出现重复保存的问题

**问题&#xff1a;**前端ajax提交数据的时候&#xff0c;当频繁点击的时候&#xff0c;或者两个账号以相同数据创建的时候&#xff0c;会出现问题。 **处理办法&#xff1a;**前端拦截&#xff0c;防止重复提交数据&#xff0c;在上一次请求返回结果之后才允许提交第二次&…

在 Debian 8 上安装 Nginx 的方法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 介绍 Nginx 是一个流行的 HTTP 服务器&#xff0c;是 Apache2 的一个替代品。它可以用作反向代理、邮件服务器或 Web 服务器。根据 Net…

[某度信息流]SQL164,2021年11月每天新用户的次日留存率

牛客网在线编程 思路&#xff1a; 首先找出用户的注册日期&#xff0c;即date(min(in_time)) 转成date形式 建立两个辅助表&#xff0c;我先放代码&#xff0c;然后进行解释 withuser_reg as (selectuid,date(min(in_time)) as first_datefromtb_user_loggroup by1),…

抖音视频如何下载保存到相册:详细教程

随着抖音的风靡&#xff0c;越来越多的人沉浸在短视频的世界中&#xff0c;观看各种搞笑、有趣、甚至感人的视频。很多用户都希望能够将喜欢的抖音视频保存到自己的手机相册中&#xff0c;方便随时观看或分享给朋友。本文将详细介绍如何下载抖音视频并保存到相册的方法。 一、…

记录Jmeter 通过view result tree配置保存响应信息的方法以及命令行运行时的一个坑

大家在使用Jmeter进行调试时有没有考虑过这个问题&#xff0c;如何查看具体的响应信息&#xff0c;特别是通过命令行执行脚本的时候&#xff0c;如何看到具体请求的响应信息呢&#xff1f; 看到上面这个问题&#xff0c;首先想到的就是我们平时在jmeter中debug问题&#xff0c…

基于FPGA实现SD NAND FLASH的SPI协议读写

基于FPGA&#xff08;现场可编程门阵列&#xff09;实现SD NAND FLASH的SPI&#xff08;串行外设接口&#xff09;协议读写是一个涉及硬件设计与编程的复杂过程。以下将详细介绍该过程的背景、关键步骤、电路设计、SPI协议详解、FPGA实现以及代码示例等方面&#xff0c;内容不少…

Spark-ShuffleManager

一、上下文 《Spark-Task启动流程》中我们讲到了ShuffleMapTask中会对这个Stage的结果进行磁盘的写入&#xff0c;并且从SparkEnv中得到了ShuffleManager&#xff0c;且调用了它的getWriter方法并在这个Stage的入口处&#xff08;也就是RDD的迭代器数据源处&#xff09;调用了…