SpringBoot集成WebSocket
SpringBoot集成WebSocket
项目结构图
项目架构图
前端项目
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>
后端项目
-
需要引入websocket的依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency>
-
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();} }
-
启动类型上, 把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();} }
-
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
客户端A/B给socket发送消息
后端给前端发送消息
应对很多的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后端项目
适用于:MVVM前后台分离开发、部署、域名配置 前端:Vue 后端:Spring Boot 这篇文章只讲后端部署,前端部署戳这里 目录 Step1:服务器上搭建后端所需环境1、更新服务器软件包2、安装JDK83、安装MySQL4、登录MySQL5、修…...

原生小程序 wxs 语法(详细)
WXS WXS(WeiXin Script)是内联在 WXML 中的脚本段。通过 WXS 可以在模版中内联少量处理脚本,丰富模板的数据预处理能力。另外, WXS 还可以用来编写简单的 WXS 事件响应函数。 从语法上看, WXS 类似于有少量限制的 Java…...
MySQL中count(*)和count(1)和count(column)使用比较
分页查询数据,需要返回total,而这个值一般都是通过count函数实现。但是,针对count函数,有多种写法,如count(*)、count(1) 和 count(column)等。本文主要介绍以上几种写法的差异。 注意,这里仅针对MySQL数据…...
python用 xlwings库对Excel进行 字体、边框设置、合并单元格, 版本转换等操作
xlwings 其他的一些单元格读取写入操作网上很多, 下面就写些如何设置单元格的 字体对齐,字体大小、边框, 合并单元格, 这些设置。 import xlwings as xwapp xw.App(visibleTrue, add_bookFalse) app.display_alerts False #…...
Golang 中的 archive/zip 包详解(二):常用类型
Golang 中的 archive/zip 包用于处理 ZIP 格式的压缩文件,提供了一系列用于创建、读取和解压缩 ZIP 格式文件的函数和类型,使用起来非常方便。 zip.File 类型 定义如下: type File struct {FileHeaderzip *Readerzipr io…...

Qt应用开发(基础篇)——错误提示框 QErrorMessage
一、前言 QErrorMessage类继承于QDialog,是一个用来显示错误信息的对话框。 提示框QDialog 消息对话框 QMessageBox QErrorMessage错误消息对话框提供了一个主文本窗口、一个复选框、一个图标和按钮。文本框用来显示错误信息,复选框用来让用户选择未来是…...
HLS 后端示例
更多 TVM 中文文档可访问 →Apache TVM 是一个端到端的深度学习编译框架,适用于 CPU、GPU 和各种机器学习加速芯片。 | Apache TVM 中文站 TVM 支持带有 SDAccel 的 Xilinx FPGA 板,接下来介绍如何将 TVM 部署到 AWS F1 FPGA 实例。 备注:此功…...

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

Streamlit 讲解专栏(十二):数据可视化-图表绘制详解(下)
文章目录 1 前言2 使用st.vega_lite_chart绘制Vega-Lite图表2.1 示例1:绘制散点图2.2 示例2:自定义主题样式 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镜像的描述文件,是由一系列命令和参数构成的脚本 。主要作用是 用来构建docker镜像的构建文件 。 通过架构图可以看出通过DockerFile可以直接构建镜像 1.2 Dockerfile解析过程 构建镜像步骤…...

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

普洛斯常熟东南数据中心获LEED金级认证及IDCC绿色算力基础设施奖
近日,普洛斯常熟东南数据中心获得美国绿色建筑评估标准体系LEED v4 BDC(建筑设计与建造)金级认证,并获评IDCC2023长三角区域绿色算力基础设施奖。以可持续发展理念为核心,该数据中心从设计规划、开发建设,到…...
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 构建一个中型前端项目的过程中,遇到了一些坑,也做了一些项目在构建生产环境时的优化,在这里做一个记录,以便后期查阅。(完整配置在后面) 上面是dist文件夹的截图,里面的内容已经有30mb了ÿ…...

JDBC使用了哪种设计模式
JDK中提供了操作数据库的接口,比如 java.sql.Driver java.sql.Connection java.sql.Statement java.sql.PreparedStatement 不同的数据库厂商提供操作自己数据库的驱动包, 比如mysql public class Driver extends NonRegisteringDriver implements jav…...

JVM-性能优化工具 MAT
一、MAT下载和安装 1、概述 MAT(Memory Analyzer Tool)工具是一款功能强大的]ava堆内存分析器。可以用于查找内存泄漏以及查看内存消耗情况。MAT是基于Eclipse开发的,不仅可以单独使用,还可以作为插件的形式嵌入在Eclipse中使用…...
Python Flask flasgger api文档[python/flask/flasgger]
首先需要安装依赖: pip install flasgger封装swagger.py文件,代码如下: from flasgger import Swagger swagger Swagger() 然后在主应用中(项目入口文件)加入以下代码: from flask import Flask from …...

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

Unity3d C#实现调取网络时间限制程序的体验时长的功能
前言 如题的需求应该经常在开发被提到,例如给客户体验3–5天的程序,到期后使其不可使用,或者几年的使用期限。这个功能常常需要使用到usb加密狗来限制,当然这也的话就需要一定的硬件投入。很多临时提供的版本基本是要求软件来实现…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...

【Oracle】分区表
个人主页:Guiat 归属专栏: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的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...

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