16.WebSocket聊天室

基于SpringBoot 2.6.11

1.WebSocket

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议,可以在html页面直接使用。

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

在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

过去,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

image-20220409085906297

浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过TCP连接直接交换数据。

当获取WebSocket连接后,可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

WebSocket在传输的过程中不再使用http协议,而是Stomp协议

1.1 STOMP

STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,简单(流)文本定向消息协议,它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互。STOMP协议由于设计简单,易于开发客户端,因此在多种语言和多种平台上得到广泛地应用。

STOMP协议的前身是TTMP协议(一个简单的基于文本的协议),专为消息中间件设计。

STOMP是一个非常简单和容易实现的协议,其设计灵感源自于HTTP的简单性。尽管STOMP协议在服务器端的实现可能有一定的难度,但客户端的实现却很容易。例如,可以使用Telnet登录到任何的STOMP代理,并与STOMP代理进行交互。

1.2 WebSocket 事件

以下是 WebSocket 对象的相关事件。

事件事件处理程序描述
openSocket.onopen连接建立时触发
messageSocket.onmessage客户端接收服务端数据时触发
errorSocket.onerror通信发生错误时触发
closeSocket.onclose连接关闭时触发

1.3 WebSocket 方法

以下是 WebSocket 对象的相关方法。

方法描述
Socket.send()使用连接发送数据
Socket.close()关闭连接

2.用WebSocket实现网页端聊天室

        导入依赖

<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;/*** @author: Elivs.Xiang* @Email: 406862257@qq.com* @create 2022-12-06 15:09* @verson IDEA 2020.3*/@Configuration
public class WebsocketConfig {@Bean    //在容器中创建bean对象,在WebSocketUtil中需要用到的RemoteEndpoint对象public ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

        创建工具类

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;import javax.websocket.Session;
import javax.websocket.RemoteEndpoint;
public class WebSocketUtil {//HashMap:不支持多线程,并发情况下线程不安全public static final Map<String, Session> MESSAGEMAP = new ConcurrentHashMap<>();//发送消息给客户端public static void sendMessage(Session session,String message) {if (session!=null) {final RemoteEndpoint.Basic basic = session.getBasicRemote();if (basic!=null) {try {basic.sendText(message);//发送消息回客户端} catch (IOException e) {e.printStackTrace();}}}}//将消息给所有聊天室的人//循环发送public static void sendMessageToAll(String message) {MESSAGEMAP.forEach((sessionId,session)->sendMessage(session, message));}
}

        创建handler

import java.io.IOException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;import com.example.web.util.WebSocketUtil;
import org.springframework.web.bind.annotation.RestController;@RestController
@ServerEndpoint("/WebSocketHandler/{userName}")		//表示接受的是STOMP协议提交的数据
public class WebSocketHandler {//建立连接@OnOpenpublic void openSession(@PathParam("userName")String userName,Session session) {//消息String message = "欢迎:"+userName+"加入群聊";//加入聊天室WebSocketUtil.MESSAGEMAP.put(userName, session);//发送消息WebSocketUtil.sendMessageToAll(message);}@OnMessagepublic void onMessage(@PathParam("userName")String userName,String message) {message = userName+":"+message;WebSocketUtil.sendMessageToAll(message);}//离开聊天室@OnClosepublic void onClose(@PathParam("userName")String userName,Session session) {//将当前用户从map中移除 注销WebSocketUtil.MESSAGEMAP.remove(userName);//群发消息WebSocketUtil.sendMessageToAll("用户:"+userName+"离开聊天室");//关闭sessiontry {session.close();} catch (IOException e) {e.printStackTrace();}}//连接异常@OnErrorpublic void onError(Session session,Throwable throwable) {try {session.close();} catch (IOException e) {e.printStackTrace();}}
}

        主启动类开启websocket

@SpringBootApplication
@EnableWebSocket
public class WebApplication {public static void main(String[] args) {SpringApplication.run(WebApplication.class, args);}
}

        前端代码

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Insert title here</title><link rel="stylesheet" type="text/css" href="css/index.css"><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript">$(document).ready(function(){let url = "ws://192.168.7.131:9988/WebSocketHandler/";let ws = null;//连接服务器$("#join").click(function(){let userName = $("#userName").val();let newUrl = url + userName;	//传递用户名console.info(newUrl);//创建对象,连接服务器ws = new WebSocket(newUrl); 	//html5中提供了//给open事件绑定方法ws.onopen = function(){console.info("连接成功");}//接收到数据ws.onmessage = function(result){var textarea = document.getElementById('textarea');textarea.append(result.data+"\n");//将文本域的滚动条滚动到最后textarea.scrollTop = textarea.scrollHeight;}//关闭连接ws.onclose = function(){$("#textarea").append("用户:"+userName+"离开聊天室"+"\n");console.info("关闭连接");}});//发送消息$("#send").click(function(){//将输入框中的消息发送给服务器,并且显示到消息框中var messageInput = $("#message");var message = messageInput.val();if(ws!=null){ws.send(message);	//发送消息messageInput.val("");}});//断开连接$("#out").click(function(){if(ws!=null){ws.close();}});})</script>
</head>
<body>
<div id="box"><p>蜗牛聊天室</p><textarea rows="10" cols="50" disabled="disabled" id="textarea"></textarea><br><div class="infoBox">用户名:<input type="text" id="userName"><br><br><button style="color: green;" id="join">加入聊天室</button>&nbsp;&nbsp;&nbsp;&nbsp;<button style="color: red;" id="out">离开聊天室</button></div><br><br><div class="infoBox">消&nbsp;&nbsp;&nbsp;息:<input type="text" id="message"><br><br><button id="send">发送消息</button></div><br></div>
</body>
</html>

        css

#box{width: 500px;background: pink;text-align: center;
}
.infoBox{text-align:left;position: relative;left: 62px;
}
#message{width: 322px;
}
#send{position:relative;left:50px;height:30px;width: 326px;
}

        启动项目报错

Caused by: java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available

在测试类上的@SpringBootTest中加上

webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class WebApplicationTests {@Testvoid contextLoads() {}
}

整合Gateway

在application.yml中配置websocket路由

spring:application:name: gatewaycloud:gateway:routes:- id: chat  #uri: "ws://127.0.0.1:8000"   # ws 协议    需要指定IP,通过微服务名字会报503predicates:- Path=/WebSocketHandler/**

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/118281.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java对时间序列根据阈值进行连续性分片

问题描述&#xff1a;我需要对一个连续的时间戳list进行分片&#xff0c;分片规则是下一个数据比当前数据要大于某一个阈值则进行分片&#xff1b; 解决方式&#xff1a; 1、输入的有顺序的list &#xff0c;和需要进行分片的阈值 2、调用方法&#xff0c;填入该排序的list和阈…

docker安装redis,并挂载配置文件

1&#xff1a;下载镜像&#xff0c;不添加版本 默认下载最新的 docker pull redis下载成功后如图所示 2&#xff1a;下载redis配置文件&#xff0c;我是在docker中下载的&#xff0c;也可以使用文件上传工具将配置文件上传到自己指定的目录。 首先需要安装wget&#xff0c;否…

蓝牙发展现状

目录 一、产品分类1、Bluetooth经典2、Bluetooth低能耗(LE)3、二者差异 二、出货量三、未来需要加强的方向四、技术行业细分五、学习资料1、蓝牙官网2、大神博客——于忠军 一、产品分类 1、Bluetooth经典 Bluetooth Classic无线电&#xff0c;也被称为Bluetooth 基本速率/增强…

QT 界面相关操作

1> 创建自定义类时需要指定父类 2> 第一个界面的相关操作 #include "widget.h" #include<iostream> //printf #include<QDebug> //qDebuf #include<QIcon> //图标的头文件 using namespace std; //coutWidget::Widget(QWidget *…

go gin 自定义验证

我们上一篇已经提到了gin中binding时候可以指定json字段大小等限制&#xff0c;但是那个错误却是英文的&#xff0c;现在想搞成中文的&#xff0c;以便前端可读&#xff0c;demo如下 package mainimport ("net/http""reflect""github.com/gin-gonic/…

基于JAVA SpringBoot互联网就医门诊挂号管理系统

摘要 随着时代的发展,无线互联网技术的应用和普及给人们的生活带来了极大的改变,现在信息技术不仅可以提高我们的工作效率,还能有效的规避一些错误风险,节约人力成本。我国国民一方面对健康的要求越来越重视了&#xff0c;另一方面现代人的健康问题日益严重&#xff0c;所以医院…

Linux系统调试中出现核心转储(core dump)的问题

​ 大家好&#xff0c;我是ST。今天主要分享一下&#xff0c;Linux应用程序发生Segmentation fault段错误时&#xff0c;如何利用core dump文件定位错误。 核心转储 在 Linux 系统中&#xff0c;常将“主内存”称为核心(core)&#xff0c;而核心映像(core image) 就是 “进…

4.1 链式栈StackT

C关键词&#xff1a;内部类/模板类/头插 C自学精简教程 目录(必读) C数据结构与算法实现&#xff08;目录&#xff09; 栈的内存结构 空栈&#xff1a; 有一个元素的栈&#xff1a; 多个元素的栈&#xff1a; 成员函数说明 0 clear 清空栈 clear 函数负责将栈的对内存释放…

arduino仿真 SimulIDE1.0仿真器

SimulIDE 是一个开源的电子电路模拟器&#xff0c;支持模拟各种电子元器件的行为&#xff0c;可以帮助电子工程师和爱好者进行电路设计和测试。以下是 SimulIDE 的安装和使用说明&#xff1a; 安装 SimulIDE SimulIDE 可以在 Windows、Linux 和 Mac OS X 等操作系统上安装。您…

仿京东 项目笔记1

目录 项目代码1. 项目配置2. 前端Vue核心3. 组件的显示与隐藏用v-if和v-show4. 路由传参4.1 路由跳转有几种方式&#xff1f;4.2 路由传参&#xff0c;参数有几种写法&#xff1f;4.3 路由传参相关面试题4.3.1 路由传递参数&#xff08;对象写法&#xff09;path是否可以结合pa…

Qt应用开发(基础篇)——进度对话框 QProgressDialog

一、前言 QProgressDialog类继承于QDialog&#xff0c;是Qt设计用来反馈进度的对话框。 对话框QDialog QProgressDialog提供了一个进度条&#xff0c;表示当前程序的某操作的执行进度&#xff0c;让用户知道操作依旧在激活状态&#xff0c;配合按钮&#xff0c;用户就可以随时终…

【C++入门】string类常用方法(万字详解)

目录 1.STL简介1.1什么是STL1.2STL的版本1.3STL的六大组件1.4STL的缺陷 2.string类的使用2.1C语言中的字符串2.2标准库中的string类2.3string类的常用接口说明 &#xff08;只讲解最常用的接口&#xff09;2.3.1string类对象的常见构造2.3.2 string类对象的容量操作2.3.3string…

nnUNet v2数据准备及格式转换 (二)

如果你曾经使用过nnUNet V1&#xff0c;那你一定明白数据集的命名是有严格要求的&#xff0c;必须按照特定的格式来进行命名才能正常使用。 这一节的学习需要有数据&#xff0c;如果你有自己的数据&#xff0c;可以拿自己的数据来实验&#xff0c;如果没有&#xff0c;可以用十…

Python语音识别处理详解

概要 人们对智能语音助手的需求不断提高&#xff0c;语音识别技术也随之迅速发展。在这篇文章中&#xff0c;我们将介绍如何使用Python的SpeechRecognition和pydub等库来实现语音识别和处理&#xff0c;从而打造属于自己的智能语音助手。 1. 什么是语音识别&#xff1f; 语音…

Vue学习(三)

一、列表渲染 v-for指令 用于展示列表数据 语法<li v-for"(item, index) in items" :key"index"></li>key可以是index,最好是遍历对象的唯一标识 可遍历&#xff1a;数组、对象 <!DOCTYPE html> <html lang"en">&l…

MySQL8.xx 解决1251 client does not support ..解决方案

MySQL8.0.30一主两从复制与配置(一)_蜗牛杨哥的博客-CSDN博客 MySQL8.xx一主两从复制安装与配置 MySQL8.XX随未生成随机密码解决方案 一、客户端连接mysql&#xff0c;问题&#xff1a;1251 client does not support ... 二、解决 1.查看用户信息 备注&#xff1a;host为 % …

linux并发服务器 —— 多进程并发(四)

进程概述 程序是包含一系列信息的文件&#xff0c;描述了如何在运行时创建一个进程&#xff1b; 进程是正在运行的程序的实例&#xff0c;可以用一个程序来创建多个进程&#xff1b; 用户内存空间包含程序代码以及代码所使用的变量&#xff0c;内核数据结构用于维护进程状态…

Spring Cloud--从零开始搭建微服务基础环境【三】

&#x1f600;前言 本篇博文是关于Spring Cloud–从零开始搭建微服务基础环境【三】&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;…

深度学习推荐系统(五)DeepCrossing模型及其在Criteo数据集上的应用

深度学习推荐系统(五)Deep&Crossing模型及其在Criteo数据集上的应用 在2016年&#xff0c; 随着微软的Deep Crossing&#xff0c; 谷歌的Wide&Deep以及FNN、PNN等一大批优秀的深度学习模型被提出&#xff0c; 推荐系统全面进入了深度学习时代&#xff0c; 时至今日&am…

Qt应用开发(基础篇)——对话框窗口 QDialog

一、前言 QDialog类继承于QWidget&#xff0c;是Qt基于对话框窗口(消息窗口QMessageBox、颜色选择窗口QColorDialog、文件选择窗口QFileDialog等)的基类。 QDialog窗口是顶级的窗口&#xff0c;一般情况下&#xff0c;用来当做用户短期任务(确认、输入、选择)或者和用户交流(提…