Springboot整合WebSocket实现浏览器和服务器交互
Websocket定义
代码实现
引入maven依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>
配置类
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** WebSocket配置类*/@Configurationpublic class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}
WebSocketServer 服务端
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.hc.dialer_server.service.SendMessageService;
import com.hc.dialer_server.utils.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;/*** WebSocket的操作类*/
@Component
@Slf4j
@ServerEndpoint("/websocket/{number}")
@DependsOn("springContext")
public class WebSocketServer {SendMessageService sendMessageServiceImpl = SpringContextUtils.getBean("sendMessageServiceImpl");// 记录当前在线连接数private static AtomicInteger onlineSessionClientCount = new AtomicInteger(0);// 记录number和 session的对应关系public static Map<String, Session> connectionMap = new ConcurrentHashMap<>();private String number;@OnOpenpublic void onOpen(@PathParam("number") String number, Session session) throws IOException {log.info("连接建立中 ==> session_id = {}, number = {}", session.getId(), number);// 在线人数+1onlineSessionClientCount.incrementAndGet();this.number = number;connectionMap.put(number, session);session.getBasicRemote().sendText("连接建立成功");log.info("连接建立成功, 当前在线数为: {}, session_id = {}, number = {}", onlineSessionClientCount, session.getId(), number);}@OnClosepublic void onClose(@PathParam("number") String number, Session session) {connectionMap.remove(number);onlineSessionClientCount.decrementAndGet();log.info("连接关闭成功, 当前在线数为: {} ==> 关闭该连接信息: session_id = {}, number = {}", onlineSessionClientCount, session.getId(), number);}@OnMessagepublic void onMessage(String message, Session session) throws Exception {if (StringUtils.isBlank(message)) {return;}JSONObject jsonObject = JSON.parseObject(message);String eventType = jsonObject.getString("eventType");String msg = jsonObject.getString("message");log.info("服务端收到客户端消息 ==> number = {}, eventType = {}, message = {}", number, eventType, msg);session.getBasicRemote().sendText("服务端给客户端发送消息");}@OnDisconnectpublic void onDisconnect(Session session) {connectionMap.remove(number);onlineSessionClientCount.decrementAndGet();log.info("disconnect event ==> number: {}, session_id: {}, 当前在线数: {}", number, session.getId(), onlineSessionClientCount);}@OnErrorpublic void onError(Session session, Throwable error) {log.error("WebSocket发生错误, session id = {}, 错误信息为:{}", session.getId(), error.getMessage());}}
工具类
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;@Component("springContext")
public class SpringContextUtils implements ApplicationContextAware {/*** Spring应用上下文环境*/private static ApplicationContext applicationContext;/*** 获取对象** @return Object 一个以所给名字注册的bean的实例*/@SuppressWarnings("unchecked")public static <T> T getBean(String name) {return (T) applicationContext.getBean(name);}/*** 获取类型为requiredType的对象*/public static <T> T getBean(Class<T> clz) {return applicationContext.getBean(clz);}/*** 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true** @return boolean*/public static boolean containsBean(String name) {return applicationContext.containsBean(name);}/*** 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)** @return boolean*/public static boolean isSingleton(String name) {return applicationContext.isSingleton(name);}/*** @return Class 注册对象的类型*/public static Class<?> getType(String name) {return applicationContext.getType(name);}@Overridepublic synchronized void setApplicationContext(ApplicationContext applicationContext) {if (SpringContextUtils.applicationContext == null) {SpringContextUtils.applicationContext = applicationContext;}}
}
前端
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>测试webSocket</title>
</head>
<body>
Client传来的number:
<!--<input type="text" th:value="${number}" id="number"/>-->
<p>【eventType】:
<div><input id="toUserId" name="toUserId" type="text" value="message"></div>
<p>【messageText】:
<div><input id="contentText" name="contentText" type="text" value="hello websocket"></div>
<p>【操作】:
<div><button type="button" onclick="sendMessage()">发送消息</button><button type="button" onclick="sendMessage1()">1626</button></div>
</body><script type="text/javascript">var socket;if (typeof (WebSocket) == "undefined") {console.log("您的浏览器不支持WebSocket");} else {console.log("您的浏览器支持WebSocket");//实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接var number = '1626';console.log("number-->" + number);// socket服务器端的ip和端口var reqUrl = "http://localhost:8080/websocket/" + number;socket = new WebSocket(reqUrl.replace("http", "ws"));//打开事件socket.onopen = function () {console.log("Socket 已打开");//socket.send("这是来自客户端的消息" + location.href + new Date());};//获得消息事件socket.onmessage = function (msg) {console.log("onmessage--" + msg.data);//发现消息进入,开始处理前端触发逻辑};//关闭事件socket.onclose = function () {console.log("Socket已关闭");};//发生了错误事件socket.onerror = function () {alert("Socket发生了错误");//此时可以尝试刷新页面}}function sendMessage() {if (typeof (WebSocket) == "undefined") {console.log("您的浏览器不支持WebSocket");} else {// console.log("您的浏览器支持WebSocket");var toUserId = document.getElementById('toUserId').value;var contentText = document.getElementById('contentText').value;var msg = '{"eventType":"' + toUserId + '","message":"' + contentText + '"}';console.log(msg);socket.send(msg);}}//发送json串function sendMessage1() {if (typeof (WebSocket) == "undefined") {console.log("您的浏览器不支持WebSocket");} else {// console.log("您的浏览器支持WebSocket");var toUserId = document.getElementById('toUserId').value;var contentText = document.getElementById('contentText').value;// var msg = '{"eventType":"' + toUserId + '","message":"' + contentText + '"}';var msg = '{"eventType":"' + toUserId + '","message":{"number":"1626","serviceNumber":"60600","req":"event01"}}';console.log(msg);socket.send(msg);}}</script>
</html>
测试

相关文章:
Springboot整合WebSocket实现浏览器和服务器交互
Websocket定义 代码实现 引入maven依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>配置类 import org.springframework.context.annotation.Bean;i…...
这些 channel 用法你都用起来了吗?
channel 是什么? channel 是GO语言中一种特殊的类型,是连接并发goroutine的管道 channel 通道是可以让一个 goroutine 协程发送特定值到另一个 goroutine 协程的通信机制。 关于 channel 的原理,channel通道需要注意的地方,之前…...
纽交所上市公司安费诺宣布将以1.397亿美元收购无线解决方案提供商PCTEL
来源:猛兽财经 作者:猛兽财经 猛兽财经获悉,纽交所上市公司安费诺(APH)宣布将以每股7美元现金,总价格1.397亿美元收购无线解决方案提供商PCTEL(PCTI)。 该交易预计将在第四季度或2024年初完成。 Lake Street Capital Markets担任…...
二分查找算法(Python)
目录 1、概念 2、思路 3、实现算法 1、概念 二分查找又称折半查找,它是一种效率较高的查找方法 原理:首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成…...
“第四十二天”
这个,之前用的b去存储a的总和和排名,后来在比较的过程中,只改变的b的值,却没有改变a的值,但在比较语文成绩的时候用的还是a,这个时候a和b同样是第i个对应的可能不是同一个对象了 ,因为上面b的值…...
Qt/C++编写物联网组件/支持modbus/rtu/tcp/udp/websocket/mqtt/多线程采集
一、功能特点 支持多种协议,包括Modbus_Rtu_Com/Modbus_Rtu_Tcp/Modbus_Rtu_Udp/Modbus_Rtu_Web/Modbus_Tcp/Modbus_Udp/Modbus_Web等,其中web指websocket。支持多种采集通讯方式,包括串口和网络等,可自由拓展其他方式。自定义采…...
windows常用命令
一.文件操作 dir:查看文件当前路径目录列表 cd .. :返回上一级目录 cd 路径:进入路径...
数据结构--堆
一. 堆 1. 堆的概念 堆(heap):一种有特殊用途的数据结构——用来在一组变化频繁(发生增删查改的频率较高)的数据集中查找最值。 堆在物理层面上,表现为一组连续的数组区间:long[] array &…...
Android12之报错 error: BUILD_COPY_HEADERS is obsolete(一百六十七)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...
vue前端中v-model与ref的区别
v-model <template><input type"text" v-model"message"> </template>作用:将输入框与message绑定,及将用户输入的内容绑定到message这个变量上,但是message是无法在script中获取到的,要想…...
探索未来:硬件架构之路
文章目录 🌟 硬件架构🍊 基本概念🍊 设计原则🍊 应用场景🍊 结论 📕我是廖志伟,一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出版社签约作…...
Linux 系统安装 Redis7 —— 超详细操作演示!
内存数据库 Redis7 一、Redis 概述1.1 Redis 简介1.2 Redis 的用途1.3 Redis 特性1.4 Redis 的IO模型 二、Redis 的安装与配置2.1 Redis 的安装2.2 连接前的配置2.3 Redis 客户端分类2.4 Redis 配置文件详解 三、Redis 命令四、Redis 持久化五、Redis 主从集群六、Redis 分布式…...
首次建站用香港服务器有影响没?
对于首次租用香港服务器的朋友来说,难免会对它没有一个很清晰的认知。因此,本文就从香港服务器适用人群,以及建站影响,选择技巧上做一个全方位的解答。 1. 哪一类人群适合使用香港服务器建站? 做外贸业务的网站。香港走的国…...
大数据Flink(九十八):SQL函数的归类和引用方式
文章目录 SQL函数的归类和引用方式 一、SQL 函数的归类...
Python文件共享+cpolar内网穿透:轻松实现公网访问
文章目录 1.前言2.本地文件服务器搭建2.1.Python的安装和设置2.2.cpolar的安装和注册 3.本地文件服务器的发布3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 数据共享作为和连接作为互联网的基础应用,不仅在商业和办公场景有广泛的应用&#…...
Flink之源算子Data Source
源算子Data Source 概述内置Data Source基于集合构建基于文件构建基于Socket构建 自定义Data SourceSourceFunctionRichSourceFunction 常见连接器第三方系统连接器File Source连接器DataGen Source连接器Kafka Source连接器RabbitMQ Source连接器MongoDB Source连接器 概述 Fl…...
在雷电模拟器9上安装magisk并安装LSPosed模块以及其Manager管理器(一)
环境:win10 64,雷电模拟器9.0.60(9),Android 9。 之前我都是用雷电模拟器版本4.0.78,Android版本7.1.2,为什么本篇要使用9了呢?先解答下这个问题。原因如下:经过我的测试,LSPosed不支…...
Apache atlas 元数据管理治理平台使用和架构
1、前言 Apache Atlas 是托管于 Apache 旗下的一款元数据管理和治理的产品,目前在大数据领域应用颇为广泛,可以很好的帮助企业管理数据资产,并对这些资产进行分类和治理,为数据分析,数据治理提供高质量的元数据信息。…...
MFF论文笔记
论文名称:Improving Pixel-based MIM by Reducing Wasted Modeling Capability_发表时间:ICCV2023 作者及组织:上海人工智能实验室,西门菲沙大学,香港中文大学 问题与贡献 MIM(Model Maksed Model)方法可以分为两部分…...
Leetcode 02.07 链表相交(链表)
Leetcode 02.07 链表相交(链表) 解法1 尾部对齐解法2:太厉害了,数学归纳推导的方法 很巧妙,这就是将链表的尾端对齐后再一起遍历,这样能满足题目的要求。因为相交之后两个链表到结束的所有节点都一样了&…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化
是不是受够了安装了oracle database之后sqlplus的简陋,无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话,配置.bahs_profile后也能解决上下翻页这些,但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可,…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...
Pydantic + Function Calling的结合
1、Pydantic Pydantic 是一个 Python 库,用于数据验证和设置管理,通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发(如 FastAPI)、配置管理和数据解析,核心功能包括: 数据验证:通过…...
海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...
