SpringBoot——整合WebSocket长连接

news2024/12/27 12:31:12

目录

WebSocket

项目总结

 新建一个SpringBoot项目

pom.xml

WebSocketConfig配置类

TestWebSocketEndpoint服务端点类

socket.html客户端

IndexController控制器

SpringbootWebsocketApplication启动类

测试客户端和服务端如何使用WebSocket进行连接和通信


WebSocket

  • SpringBoot实现长连接时最常用的技术就是WebSocket
  • WebSocket是用在Web浏览器和服务器之间进行双向数据传输的一种协议,基于TCP
    • 在WebSocket中,只需要服务器和浏览器通过HTTP完成一个“握手”的动作,然后单独建立 一条TCP的通信通道即可进行数据的双向传送了。
    • 如果有一方想要关闭连接,则需要再完成一次“握手”通知对方,使得双方同步关闭
  • 避免服务器打开多个HTTP连接以节约资源,提高工作效率和资源利用率
  • 在SpringBoot项目中的使用:
    • 客户端需要在HTML页面上使用JavaScript创建WebSocket端点类的对象
    • 服务端需要使用SpringBoot提供的注解标注WebSocket端点类

项目总结

  1. 当客户端创建WebSocket端点类对象时,就是在尝试创建连接
  2. 如果连接被成功创建,则同时触发两端的打开连接事件
  3. 客户端的send()方法会触发服务端的发送消息事件
  4. 服务端通过远程端点对象发送消息会触发客户端的接收消息事件
  5. 不管是客户端关闭WebSocket端点类对象,还是服务端关闭Session对象,都会触发双方的关闭连接事件,导致连接被关闭

 新建一个SpringBoot项目

项目结构:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.12.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.study</groupId>
	<artifactId>springboot_websocket</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springboot_websocket</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
			<version>2.4.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

WebSocketConfig配置类

package com.study.springboot_websocket.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

TestWebSocketEndpoint服务端点类

  • 一个服务端可以同时拥有多个WebSocket端点类,不同WebSocket端点类所映射的路径也不同
  • @ServerEndpoint
    • 该注解将该类标识为WebSocket端点类
    • 需要和@Component注解一起使用,让WebSocket端点类可以被SpringBoot注册
    • 完整路径是以"ws://"开头的,比如下列代码中,是"ws://localhost:8080/test"
    • 客户端使用该完整路径与服务端建立连接
  • Session对象:
    • 客户端每次与服务端建立连接后都会产生一个Session对象,Session对象可以存储一些由客户端传递给服务端的资料信息
    • 客户端只能使用一个Session对象,因为服务端可以连接多个客户端,所以服务端可以同时使用多个Session对象
  • WebSocket端点类可以捕捉4个事件:
    • 打开连接事件:@OnOpen
    • 发送消息事件:@OnMessage
    • 发生错误事件:@OnError
    • 关闭连接事件:@OnClose
    • 当发生某一个事件时可自行触发注解所标注的方法
  • WebSocket常见关闭状态码:
package com.study.springboot_websocket.websocket;

import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
/**
 * 服务器端点类
 */

@Component
@ServerEndpoint("/test")//设置端点的映射路径,将该类标识为WebSocket端点类
public class TestWebSocketEndpoint {

    @OnOpen
    public void onOpen(Session session)throws IOException {
        System.out.println(session.getId()+"客户端已连接");
    }

    /**
     * 当连接关闭时,在控制台打印关闭状态码
     */
    @OnClose
    public void onClose(Session session, CloseReason reason){
        System.out.println(session.getId()+"客户端已关闭,关闭吗:"+reason.getCloseCode().getCode());
    }

    /**
     * 当服务端收到客户端发来的消息后,延迟500毫秒回复
     */
    @OnMessage
    public void onMessage(String message,Session session){
        System.out.println("客户端发来消息:"+message);
        try {
            Thread.sleep(500);//休眠500毫秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //getAsyncRemote:使用异步发送消息接口的对象向客户端发送消息
        session.getAsyncRemote().sendText("服务端收到客户端发来的消息:"+message);
    }

    /**
     * 打印异常
     */
    @OnError
    public void onError(Session session,Throwable e){
        e.printStackTrace();//打印异常
    }
}

socket.html客户端

  • WebSocket客户端通常是网页浏览器,因此需要使用JavaScript予以实现
  • 须保证WebSocket端点类的对象映射的路径与服务端映射的路径相同
  • JavaScript的WebSocket端点类也可以捕捉4个事件:
    • 打开连接事件
    • 接收消息事件
    • 发生错误事件
    • 关闭连接事件
    • 这4个事件与服务器端点的4个事件具有相同的逻辑
  • WebSocket端点类的对象常用方法:
    • send():向服务端发送消息
    • close():正常关闭连接
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script type="text/javascript">
        var websocket=null;
        var local=window.location;//当前页面的URL地址
        var url="ws://"+local.host+"/test";//长链接地址
        if("WebSocket" in window){
            websocket=new WebSocket(url);
        }else{
            alert("当前浏览器不支持长链接,请更换浏览器")
        }
        //连接发生错误触发的方法
        websocket.onerror=function () {
            document.getElementById("message").innerHTML+="<br/>发生错误";
            websocket.close();
        }
        //连接成功建立触发的方法
        websocket.onopen=function (event) {
            document.getElementById("message").innerHTML+="<br/>连接已创建";
        }
        //连接关闭触发的方法
        websocket.onclose=function () {
            document.getElementById("message").innerHTML+="<br/>连接已关闭";
        }
        //接收到消息触发的方法
        websocket.onmessage=function (event) {
            //将服务端发来的消息拼接到div中
            document.getElementById("message").innerHTML+="<br/>"+event.data;
        }
        //监听窗口关闭事件,当窗口关闭后要主动关闭websocket连接
        websocket.opbeforeunload=function () {
            websocket.close();
        }
        //单击按钮触发的方法
        function send() {
            var message=document.getElementById("text").value;//获取输入框中的文本
            websocket.send(message);//发送给服务端
        }
    </script>
</head>
<body>
    <input type="text" id="text">
    <input type="button" id="btn" value="发送" onclick="send()"/>
    <br/>
    <div id="message"></div>
</body>
</html>

IndexController控制器

package com.study.springboot_websocket.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {
    @RequestMapping("/index")
    public String index(){
        return "socket";//当用户访问"/index"地址时跳转到socket.html页面
    }
}

SpringbootWebsocketApplication启动类

package com.study.springboot_websocket;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootWebsocketApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringbootWebsocketApplication.class, args);
	}

}

测试客户端和服务端如何使用WebSocket进行连接和通信

运行启动类,访问网址:http://localhost:8080/index

关闭浏览器后

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LayUI的暗淡:错误的押宝了前后端不分离

LayUI是一个不错的中后台UI框架&#xff0c;贝格前端工场用的CMS就是基于layUI的&#xff0c;可以说简单轻便。除此之外&#xff0c;贝格前端工场很少接到客户要求升级LayUI界面&#xff0c;或者采用LayUI框架的。 一、LayUI官网的谢幕&#xff0c;吹起了前后端不分离模式没落…

Java Set系列集合的使用规则和场景(HashSet,LinkedHashSet,TreeSet)

Set集合 package SetDemo;import java.util.HashSet; import java.util.Iterator; import java.util.Set;public class SetDemo {public static void main(String[] args) {/*Set集合的特点&#xff1a;1.Set系列集合的特点&#xff1a;Set集合是一个存储元素不能重复的集合方…

【数据结构(邓俊辉)学习笔记】图03——拓扑排序

文章目录 0. 概述1. 零入度算法1. 1 拓扑排序1. 2 算法 2. 零出度算法2.1 算法2.2 实现2.3. 复杂度 0. 概述 学习下拓扑排序 1. 零入度算法 1. 1 拓扑排序 首先理解下拓扑排序 其实老师经常干这事&#xff0c;如编讲义&#xff0c;将已经知道的知识点串起来变成讲课序列。那…

AIGC作答《2024年高考作文|新课标I卷》能拿多少分?

AIGC作答《2024年高考作文&#xff5c;新课标I卷》能拿多少分&#xff1f; 一、前言二、题目三、作答 一、前言 如火如荼的2024年高考圆满落幕&#xff0c;在如此Happy的时刻&#xff0c;AIGC技术正以其前所未有的热度席卷全球。它不仅改变了我们获取信息的方式&#xff0c;也…

RJ45 PCB布线

RJ45底盘接地和数字地通过一个1M欧姆的电阻和一个0.1uF的去耦电容隔离。其底盘接地和数字地的间距&#xff0c;必须比60mil宽。如图11及图12所示。 图11 典型变压器集成单RJ45的机箱/数字地平面 图12 典型RJ45和变压器分开的机箱/数字地平面https://www.bilibili.com/read/…

Java学习-JDBC(二)

核心API 注册驱动 Class.forName(“com.mysql.cj.jdbc.Driver”);在Java中&#xff0c;当使用JDBC连接数据库时&#xff0c;需要加载数据库特定的驱动程序&#xff0c;以便与数据库进行通信&#xff0c;加载驱动程序的目的是为了注册驱动程序&#xff0c;使得JDBC API能够识别…

Element-UI入门

目录 1.什么是Element-UI 2.作用 3.版本历史 4.优缺点 4.1.优点 4.2.缺点 5.应用场景 6.代码示例 7.未来展望 8.总结 1.什么是Element-UI Element-UI 是由饿了么前端团队开发的一套基于 Vue.js 的桌面端组件库。提供了一整套 UI 组件&#xff0c;使开发者能够快速构…

统信UOS1070上配置文件管理器默认属性01

原文链接&#xff1a;统信UOS 1070上配置文件管理器默认属性01 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于在统信UOS 1070上配置文件管理器默认属性的文章。文件管理器是我们日常操作系统使用中非常重要的工具&#xff0c;了解如何配置其默认属性可以极大地…

使用贝塞尔曲线实现一个iOS时间轴

UI效果 实现的思路 就是通过贝塞尔曲线画出时间轴的圆环的路径&#xff0c;然后 使用CAShaper来渲染UI&#xff0c;再通过 animation.beginTime [cilrclLayer convertTime:CACurrentMediaTime() fromLayer:nil] circleTimeOffset 来设置每个圆环的动画开始时间&#xff0c; …

手写kNN算法的实现-用余弦相似度来度量距离

设a为预测点&#xff0c;b为其中一个样本点&#xff0c;在向量空间里&#xff0c;它们的形成的夹角为θ&#xff0c;那么θ越小&#xff08;cosθ的值越接近1&#xff09;&#xff0c;就说明a点越接近b点。所以我们可以通过考察余弦相似度来预测a点的类型。 from collections i…

【学术小白成长之路】03三方演化博弈(基于复制动态方程)均衡点与稳定性分析

从本专栏开始&#xff0c;笔者正式研究演化博弈分析&#xff0c;其中涉及到双方演化博弈分析&#xff0c;三方演化博弈分析&#xff0c;复杂网络博弈分析等等。 先阅读了大量相关的博弈分析的文献&#xff0c;总结了现有的研究常用的研究流程&#xff0c;针对每个流程进行拆解。…

HTML-CSS练习例子

HTML CSS 练习 https://icodethis.com 作为前端练习生。不敲代码只看&#xff0c;入门是很慢的&#xff0c;所以直接实战是学习前端最快的途径之一。 这个网站练习HTML CSS的&#xff0c;可以打开了解一下&#xff0c;可以每天打卡&#xff0c;例子简单&#xff0c;循序渐进&…

《TCP/IP网络编程》(第十三章)多种I/O函数(2)

使用readv和writev函数可以提高数据通信的效率&#xff0c;它们的功能可以概括为**“对数据进行整合传输及发送”**。 即使用writev函数可以将分散在多个缓冲中的数据一并发送&#xff0c;使用readv函数可以由多个缓冲分别接受&#xff0c;所以适当使用他们可以减少I/O函数的调…

Pytorch 实现目标检测一(Pytorch 23)

一 目标检测和边界框 在图像分类任务中&#xff0c;我们假设图像中只有一个主要物体对象&#xff0c;我们只关注如何识别其类别。然而&#xff0c;很多时候图像里有多个我们感兴趣的目标&#xff0c;我们不仅想知 道它们的类别&#xff0c;还想得到它们在图像中的具体位置。在…

ESP8266+STM32+阿里云保姆级教程(AT指令+MQTT)

前言&#xff1a;在开发过程中&#xff0c;几乎踩便了所有大坑小坑总结出的文章&#xff0c;我是把坑踩满了&#xff0c;帮助更过小白快速上手&#xff0c;如有错误之处&#xff0c;还麻烦各位大佬帮忙指正、 目录 一、ESP-01s介绍 1、ESP-01s管脚功能&#xff1a; 模组启动模…

vscode 突然无法启动 WSL terminal 了怎么办?

参考&#xff1a;https://github.com/microsoft/vscode/issues/107485 根据参考网页&#xff0c;似乎在 windows 更新之后&#xff0c;重启&#xff0c;就有可能出现标题所说的 vscode 无法启动 WSL terminal 的情况。 首先使用 cmd 进入 wsl 终端&#xff0c;把 ~/.vscode-se…

EON安装ASE Interface

EON安装 我的eon路径于/eon/。 则环境为 export PYTHONPATH/eon/:$PYTHONPATH export PATH/eon/bin:$PATHsource: https://theory.cm.utexas.edu/eon/installation.html ASE 测试系统ubuntu。如果你python2和python3总是纠缠不清&#xff0c;可以sudo apt install python-…

vscode中执行python语句dir(torch)不返回结果

输入半天&#xff0c;发现在IDLE运行后的shell界面输入语句就会返回一大串。但是在vscode中老是不返回值。 结果恍然发现这没加print&#xff08;&#xff09;。 无语惨了。 家人们&#xff0c;这是python&#xff0c;而不是matlab。思维还没转换过来&#xff0c;笑死

扩散模型Stable Diffusion

扩散模型构成 Text Encoder(CLIPText) Clip Text为文本编码器。以77 token为输入&#xff0c;输出为77 token 嵌入向量&#xff0c;每个向量有768维度。 Diffusion(UNetScheduler) 在潜在空间中逐步处理扩散信息。以文本嵌入向量和由噪声组成的起始多维数组为输入&#xff0c…

二叉树—leetcode

前言 本篇博客我们来仔细说一下二叉树二叉树的一些OJ题目 请看完上一篇&#xff1a;数据结构-二叉树-CSDN博客 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;LeetCode_普通young man的博客-CSDN博客 若有问题 评论区见&#x1f4dd; &…