当前位置: 首页 > news >正文

SpringBoot集成WebSocket

SpringBoot集成WebSocket

项目结构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PRd8ZkqJ-1693291730114)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20230829143057984.png)]

项目架构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Dz61vLO-1693291730115)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20230829143146449.png)]

前端项目

socket.js 注意前端这里的端口是9000, 路劲是ws开头

function createScoket(token){var socket;if(typeof(WebSocket) == "undefined") {console.log("您的浏览器不支持WebSocket");}else{var host = window.location.origin.replace("http:","ws:")//实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接socket = new WebSocket(host+":9000/ws/"+token);//打开事件socket.onopen = function() {console.log("Socket 已打开");//socket.send("这是来自客户端的消息" + location.href + new Date());};//获得消息事件socket.onmessage = function(result) {console.log("客户端收到服务端发送的消息: " + result);console.log("result.data: " + result.data);};//关闭事件socket.onclose = function() {console.log("Socket已关闭");};//发生了错误事件socket.onerror = function() {console.log("Socket发生了错误");}//窗口关闭$(window).unload(function(event){socket.close();});}return socket;
}

index1.html 创建socket唯一标识就是, 后端会把它当做key

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>客户端A</title><script src="jquery.js"></script><script src="socket.js"></script><script>var socket;function connect() {if (!socket) {// 建立socket链接的唯一标识socket = createScoket("123");}}function sendMessage() {var content = $("#content").val();socket.send(content);}</script>
</head>
<body>
<input type="button" value="链接服务器" onclick="connect()" /> <br>
<input type="text" id="content"> <input type="button" value="发送消息" onclick="sendMessage()" />
</body>
</html>

index2.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>客户端B</title><script src="jquery.js"></script><script src="socket.js"></script><script>var socket;function connect() {if (!socket) {// 建立socket链接的唯一标识socket = createScoket("234");}}function sendMessage() {var content = $("#content").val();socket.send(content);}</script>
</head>
<body>
<input type="button" value="链接服务器" onclick="connect()" /> <br>
<input type="text" id="content"> <input type="button" value="发送消息" onclick="sendMessage()" />
</body>
</html>

后端项目

  1. 需要引入websocket的依赖

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    
  2. WebSocketServer.class 这里编写websocket根据前端做长连接的接口地址

    • @OnOpen 建立socket链接
    • @OnMessage 接收客户端发送的消息
    • @OnClose 关闭socket链接
    • @OnError socket异常信息
    package com.xiaoge;import org.springframework.stereotype.Component;import javax.websocket.*;
    import javax.websocket.server.PathParam;
    import javax.websocket.server.ServerEndpoint;
    import java.util.concurrent.ConcurrentHashMap;/*** todo 类里面这几个方法注解事件, 对应着前端相同的事件*/
    @ServerEndpoint("/ws/{token}")  // 这个注解相当于RequestMapping, 写路径, 这个路径跟前端约定好的, 可以看前端项目的socket.js文件里面的createScoket方法
    @Component
    public class WebSocketServer {private Session session;public static ConcurrentHashMap<String,Session> clients = new ConcurrentHashMap<>();/*** 建立socket链接* @param session* @param token*/@OnOpenpublic void onOpen(Session session, @PathParam( "token") String token){// 建立和浏览器的会话映射关系System.out.println("浏览器和服务器建立连接");clients.put(token,session);}/*** 接收客户端发送的消息* @param msg*/@OnMessagepublic void onMessage(@PathParam( "token") String token, String msg) {System.out.println("收到客户端标识为: "+ token +"发送的消息: " + msg);}/*** 关闭socket链接* @param token*/@OnClosepublic void onClose(@PathParam( "token") String token){System.out.println("浏览器和服务器断开连接");clients.remove(token);}/*** socket报错** @param error*/@OnErrorpublic void onError(Throwable error) {error.printStackTrace();}
    }
    
  3. 启动类型上, 把ServerEndpointExporter注入到IOC, 就会扫描我们贴了@ServerEndpoint注解的类, 把它的地址发布出去

    package com.xiaoge;import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** TODO** @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>* @since*/
    @SpringBootApplication
    public class WebsocketServerApplication {public static void main(String[] args) {SpringApplication.run(WebsocketServerApplication.class, args);}/*** 扫描我们贴了@ServerEndpoint注解的类, 把它的地址发布出去* @return*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
    }
    
  4. MessageController.class 通过这个/sendMsg接口对跟socket长连接的前端通信

    package com.xiaoge;import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;import javax.websocket.Session;
    import java.io.IOException;/*** TODO** @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>* @since*/
    @RestController
    public class MessageController {/*** todo 访问这个接口的时候, websocket就会给跟websocket建立连接的客户变标识为token的发送消息* @param token* @param msg* @return* @throws IOException*/@GetMapping("/sendMsg")public String sendMessage(String token, String msg) throws IOException {Session session = WebSocketServer.clients.get(token);// 正常应该需要判断session是否为空, 但是我这里就不判断了session.getBasicRemote().sendText(msg);return "消息发送成功!";}}

演示

客户端A/B链接后端socket

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CmHOI7cN-1693291730116)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20230829144515875.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YvPJ1jBP-1693291730116)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20230829144559640.png)]

客户端A/B给socket发送消息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RMBsES98-1693291730116)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20230829144653456.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WD2Bevx1-1693291730116)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20230829144707202.png)]

后端给前端发送消息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U2lGIV7y-1693291730117)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20230829144752955.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wPARSEiq-1693291730117)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20230829144823572.png)]

应对很多的Socket链接应该怎么应对?

在这里插入图片描述
客户端通过nginx, 使用ip_hash到对应的webSocket服务, 应用程序通过mq广播模式发送到每一台webSocket服务, 总有一台是保存了, 对应的用户长连接的, 它会把消息通知给前端。
客户端不是关闭浏览器, 那样socket就没有被删除, 它只是断网了, 你不知道它还需不需要这个socket, 长此以往下去, 容易内存溢出, 这时候就需要心跳机制, 每隔一段时间发送一次心跳, 更新心跳时间, 这样就知道那些socket有用, 那些socket没用, 这样就可以把对应的socket链接删除。

demo地址: https://download.csdn.net/download/zsx1314lovezyf/88269081?spm=1001.2014.3001.5503

相关文章:

SpringBoot集成WebSocket

SpringBoot集成WebSocket 项目结构图 项目架构图 前端项目 socket.js 注意前端这里的端口是9000, 路劲是ws开头 function createScoket(token){var socket;if(typeof(WebSocket) "undefined") {console.log("您的浏览器不支持WebSocket");}else{var ho…...

Linux服务器部署JavaWeb后端项目

适用于&#xff1a;MVVM前后台分离开发、部署、域名配置 前端&#xff1a;Vue 后端&#xff1a;Spring Boot 这篇文章只讲后端部署&#xff0c;前端部署戳这里 目录 Step1&#xff1a;服务器上搭建后端所需环境1、更新服务器软件包2、安装JDK83、安装MySQL4、登录MySQL5、修…...

原生小程序 wxs 语法(详细)

WXS WXS&#xff08;WeiXin Script&#xff09;是内联在 WXML 中的脚本段。通过 WXS 可以在模版中内联少量处理脚本&#xff0c;丰富模板的数据预处理能力。另外&#xff0c; WXS 还可以用来编写简单的 WXS 事件响应函数。 从语法上看&#xff0c; WXS 类似于有少量限制的 Java…...

MySQL中count(*)和count(1)和count(column)使用比较

分页查询数据&#xff0c;需要返回total&#xff0c;而这个值一般都是通过count函数实现。但是&#xff0c;针对count函数&#xff0c;有多种写法&#xff0c;如count(*)、count(1) 和 count(column)等。本文主要介绍以上几种写法的差异。 注意&#xff0c;这里仅针对MySQL数据…...

python用 xlwings库对Excel进行 字体、边框设置、合并单元格, 版本转换等操作

xlwings 其他的一些单元格读取写入操作网上很多&#xff0c; 下面就写些如何设置单元格的 字体对齐&#xff0c;字体大小、边框&#xff0c; 合并单元格&#xff0c; 这些设置。 import xlwings as xwapp xw.App(visibleTrue, add_bookFalse) app.display_alerts False #…...

Golang 中的 archive/zip 包详解(二):常用类型

Golang 中的 archive/zip 包用于处理 ZIP 格式的压缩文件&#xff0c;提供了一系列用于创建、读取和解压缩 ZIP 格式文件的函数和类型&#xff0c;使用起来非常方便。 zip.File 类型 定义如下&#xff1a; type File struct {FileHeaderzip *Readerzipr io…...

Qt应用开发(基础篇)——错误提示框 QErrorMessage

一、前言 QErrorMessage类继承于QDialog&#xff0c;是一个用来显示错误信息的对话框。 提示框QDialog 消息对话框 QMessageBox QErrorMessage错误消息对话框提供了一个主文本窗口、一个复选框、一个图标和按钮。文本框用来显示错误信息&#xff0c;复选框用来让用户选择未来是…...

HLS 后端示例

更多 TVM 中文文档可访问 →Apache TVM 是一个端到端的深度学习编译框架&#xff0c;适用于 CPU、GPU 和各种机器学习加速芯片。 | Apache TVM 中文站 TVM 支持带有 SDAccel 的 Xilinx FPGA 板&#xff0c;接下来介绍如何将 TVM 部署到 AWS F1 FPGA 实例。 备注&#xff1a;此功…...

实录分享 | Alluxio在AI/ML场景下的应用

欢迎来到【微直播间】&#xff0c;2min纵览大咖观点 本次分享主要包括五个方面&#xff1a; 关于Alluxio&#xff1b;盘点企业在尝试AI时面临的挑战&#xff1b;Alluxio在技术栈中的位置&#xff1b;Alluxio在模型训练&模型上线场景的应用&#xff1b;效果对比&#xff1…...

Streamlit 讲解专栏(十二):数据可视化-图表绘制详解(下)

文章目录 1 前言2 使用st.vega_lite_chart绘制Vega-Lite图表2.1 示例1&#xff1a;绘制散点图2.2 示例2&#xff1a;自定义主题样式 3 使用st.plotly_chart函数创建Plotly图表3.1 st.plotly_chart函数的基本用法3.2 st.plotly_chart 函数的更多用法 4 Streamlit 与 Bokeh 结合进…...

Dockerfile 使用教程

1.Dockerfile 1.1 什么是Dockerfile Dockerfile可以认为是 Docker镜像的描述文件&#xff0c;是由一系列命令和参数构成的脚本 。主要作用是 用来构建docker镜像的构建文件 。 通过架构图可以看出通过DockerFile可以直接构建镜像 1.2 Dockerfile解析过程 构建镜像步骤&#xf…...

InnoDB的Buffer

一、Buffer内存结构 MySQL 服务器启动的时候就向操作系统申请了一片连续的内存&#xff0c;默认128M&#xff0c;可通过从参数修改。 [server] innodb_buffer_pool_size 268435456 1.1 控制块 控制块包括该页所属的 表空间编号、页号、缓存页在 Buffer Pool 中的地址、链表…...

普洛斯常熟东南数据中心获LEED金级认证及IDCC绿色算力基础设施奖

近日&#xff0c;普洛斯常熟东南数据中心获得美国绿色建筑评估标准体系LEED v4 BDC&#xff08;建筑设计与建造&#xff09;金级认证&#xff0c;并获评IDCC2023长三角区域绿色算力基础设施奖。以可持续发展理念为核心&#xff0c;该数据中心从设计规划、开发建设&#xff0c;到…...

RabbitMQ 启动及参数说明

/usr/local/lib/erlang/erts-10.4/bin/beam.smp -W w -A 128 -MBas ageffcbf -MHas ageffcbf -MBlmbcs 512 -MHlmbcs 512 -MMmcs 30 -P 1048576 -t 5000000 -stbt db -zdbbl 128000 -K true – -root /usr/local/lib/erlang -progname erl – -home /var/lib/rabbitmq – -pa /…...

Vite打包性能优化及填坑

最近在使用 Vite4.0 构建一个中型前端项目的过程中&#xff0c;遇到了一些坑&#xff0c;也做了一些项目在构建生产环境时的优化&#xff0c;在这里做一个记录&#xff0c;以便后期查阅。(完整配置在后面) 上面是dist文件夹的截图&#xff0c;里面的内容已经有30mb了&#xff…...

JDBC使用了哪种设计模式

JDK中提供了操作数据库的接口&#xff0c;比如 java.sql.Driver java.sql.Connection java.sql.Statement java.sql.PreparedStatement 不同的数据库厂商提供操作自己数据库的驱动包&#xff0c; 比如mysql public class Driver extends NonRegisteringDriver implements jav…...

JVM-性能优化工具 MAT

一、MAT下载和安装 1、概述 MAT&#xff08;Memory Analyzer Tool&#xff09;工具是一款功能强大的]ava堆内存分析器。可以用于查找内存泄漏以及查看内存消耗情况。MAT是基于Eclipse开发的&#xff0c;不仅可以单独使用&#xff0c;还可以作为插件的形式嵌入在Eclipse中使用…...

Python Flask flasgger api文档[python/flask/flasgger]

首先需要安装依赖&#xff1a; pip install flasgger封装swagger.py文件&#xff0c;代码如下&#xff1a; from flasgger import Swagger swagger Swagger() 然后在主应用中&#xff08;项目入口文件&#xff09;加入以下代码&#xff1a; from flask import Flask from …...

k8s常见命令

基础知识 1&#xff0c;deployment和pod关系 一个pod里面好几个container&#xff0c;deployment是针对这个pod的配置文件&#xff0c;比如设置这个pod有几个副本 2&#xff0c;ip地址 node有ip&#xff0c;pod也有ip。 node的ip用于集群内部和外部访问&#xff0c;pod用于…...

Unity3d C#实现调取网络时间限制程序的体验时长的功能

前言 如题的需求应该经常在开发被提到&#xff0c;例如给客户体验3–5天的程序&#xff0c;到期后使其不可使用&#xff0c;或者几年的使用期限。这个功能常常需要使用到usb加密狗来限制&#xff0c;当然这也的话就需要一定的硬件投入。很多临时提供的版本基本是要求软件来实现…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...