SpringBoot——整合WebSocket长连接

目录

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

关闭浏览器后

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spark参数配置不合理的情况

1.1 内存设置 &#x1f4be; 常见的内存设置有两类&#xff1a;堆内和堆外 &#x1f4a1; 我们作业中大量的设置 driver 和 executor 的堆外内存为 4g&#xff0c;造成资源浪费 &#x1f4c9;。 通常 executor 堆外内存在 executor.cores1 的时候&#xff0c;1g 足够了&…

C语言 树与二叉树基础部分

树与二叉树基础部分 树的基础概念二叉树的性质二叉树的遍历前序遍历中序遍历后序遍历层序遍历根据遍历结果恢复二叉树 二叉树的创建第一种第二种 二叉树的其他典型操作查找指定元素&#xff08;一般二叉树&#xff09;二叉树的高度&#xff08;深度&#xff09;二叉树的拷贝二叉…

BFS实现图的点的层次-java

加强对广度优先搜索的理解&#xff0c;其实就是主要的3个步骤&#xff0c;外加数组模拟单链表是基础&#xff0c;要搞懂。 目录 前言 一、图中点的层次 二、算法思路 1.广度优先遍历 2.算法思路 三、代码如下 1.代码如下&#xff08;示例&#xff09;&#xff1a; 2.读入…

地理信息系统(ArcGIS)在水文水资源、水环境中的实践技术应用及案例分析教程

原文链接&#xff1a;地理信息系统&#xff08;ArcGIS&#xff09;在水文水资源、水环境中的实践技术应用及案例分析教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247606047&idx5&sn8c9701518e13b85d8429186fcfe98ad8&chksmfa821ef8cdf597ee7a8a1…

数据加密验签机的工作原理

数据加密验签机&#xff0c;作为网络安全领域的关键设备&#xff0c;其重要性不言而喻。以下是对数据加密验签机的详细介绍&#xff1a; 一、引言 在数字化时代&#xff0c;数据的机密性、完整性和真实性是企业和个人都极为关注的问题。数据加密验签机&#xff0c;正是为了解决…

嘉立创面板制作不规则图案技巧

首先附上效果图展示&#xff1a; 所需软件&#xff1a;嘉立创EDA(专业版)、photoshop、Adobe Illustrator 嘉立创EDA(专业版)&#xff1a; 嘉立创面板绘制很容易上手&#xff0c;只要了解这几个图层的作用便可以做出自己想要的面板。 材料边界层&#xff1a; 代表选⽤的材料…

时隔很久运行苍穹外卖项目,出现很多错误

中途运行了很多其他项目&#xff0c;maven的配置文件还被我修改了一次。导致再次运行苍穹外卖项目出现很多错误。 发现没有办法&#xff0c;把本地的仓库删了个干干净净。然后点击clean发现报错&#xff1a; Cannot access alimaven (http://mavejavascript:void(0);n.aliyun.…

Verilog实战学习到RiscV - 4 : ICEStick 评估板计数器

这篇是关于always 时序逻辑的。直接上代码。 引脚配置文件 set_io leds[0] 99 set_io leds[1] 98 set_io leds[2] 97 set_io leds[3] 96set_io -pullup yes pmod[0] 78 set_io -pullup yes pmod[1] 79参看icestick的原理图 这里在pmod上使用了内部的上拉电阻。…

数据结构:旋转数组

方法1 &#xff08;三次逆置法&#xff09;&#xff1a; void reverse(int* nums, int start, int end) {while (start < end) {int temp nums[start];nums[start] nums[end];nums[end] temp;start;end--;} }void rotate(int* nums, int numsSize, int k) {k k % numsS…

Camtasia Studio怎么自动加字幕呢,Camtasia Studio有什么功能呢

在信息化高度发达的今天&#xff0c;视频作为一种直观、生动的信息表达方式&#xff0c;受到了越来越多人的青睐。无论是教育领域的教学视频&#xff0c;还是企业宣传的推广短片&#xff0c;甚至是个人创作的分享作品&#xff0c;都离不开一款优秀的视频编辑软件。Camtasia Stu…

uc/OS-III多任务程序

文章目录 一、实验内容二、实验步骤&#xff08;一&#xff09;基于STM32CubeMX建立工程&#xff08;二&#xff09;获取uc/OS-III源码&#xff08;三&#xff09;代码移植 三、修改mai.c文件四、实验现象 一、实验内容 学习嵌入式实时操作系统&#xff08;RTOS&#xff09;,以…

ssm613个性化旅游攻略定制系统设计与实现+jsp【已测试】

前言&#xff1a;&#x1f469;‍&#x1f4bb; 计算机行业的同仁们&#xff0c;大家好&#xff01;作为专注于Java领域多年的开发者&#xff0c;我非常理解实践案例的重要性。以下是一些我认为有助于提升你们技能的资源&#xff1a; &#x1f469;‍&#x1f4bb; SpringBoot…

数据结构笔记 3 串 数组 广义表

以下了解即可&#xff0c;暂时没发现有什么考点 参考&#xff1a; 【数据结构】——多维数组和广义表_数据结构loc-CSDN博客 相对应的题目&#xff1a; 他这个数组不是从0开始的&#xff0c;是从1开始的&#xff0c;所以为了配合公式要减1 下面这道题又不一样&#xff0c;它是…

C++从入门到精通(最详细教程,12万总结,带你掌握c++知识,涵盖大量知识点)

目录 一、面向对象的思想 二、类的使用 1.类的构成 2.类的设计 三、对象的基本使用 四、类的构造函数 1.构造函数的作用 2.构造函数的特点 3.默认构造函数 3.1.合成的默认构造函数 3.2.手动定义的默认构造函数 四、自定义的重载构造函数 五、拷贝构造函数 1.手动…

「React」RSC 服务端组件

前言 RSC&#xff08;React Server Components&#xff09;是React框架的一个新特性&#xff0c;它允许开发者编写只在服务器端渲染的组件。与传统的服务器端渲染&#xff08;SSR&#xff09;不同&#xff0c;RSC的目标是提升性能和用户体验&#xff0c;同时减少客户端加载的J…

vivado HW_ILA

HW_ILA 描述 集成逻辑分析器&#xff08;ILA&#xff09;调试核心允许您执行系统内监控 通过对内核上的调试探针&#xff0c;在实现的设计中对信号进行处理。您可以配置 ILA核心实时触发特定硬件事件&#xff0c;并在 以系统速度探测。 ILA调试核心可以通过从IP目录实例化ILA核…

windows软件手动设置开机自启

博主需求 由于很多线上课程使用outlook进行教学&#xff0c;课程链接都关联到outlook日历中了&#xff0c;只要保持outlook是打开的状态就能收到上课提醒&#xff0c;非常方便。 但是有时候会忘记打开outlook查看&#xff0c;我偶尔会错过一些提醒QAQ。 所以如何让outlook常…

重生奇迹MU剑士怎么连招

剑士有很多技能&#xff0c;所以在连招方面就比较有讲究了。我们先来看一下这些技能的介绍吧。 1技能&#xff1a;造成伤害&#xff0c;冷却3秒。 2技能&#xff1a;旋转造成范围伤害&#xff0c;冷却6秒。 3技能&#xff1a;突刺前方敌人&#xff0c;短暂眩晕&#xff0c;冷…

Codeforces Round 951 (Div. 2)C. Earning on Bets

Problem - C - Codeforces 合理的答案&#xff1a; 求出 k1 ~ kn 的最小公倍数lcm&#xff0c;如果 lcm/k1 lcm/k2 ... lcm/kn < lcm 即符合题意。 左边之和为我们付的总钱数&#xff0c;右边才是每次选择得到的钱数(都为lcm)。 直接拿1e9检查是否可以分即可&#xff…

【Redis学习笔记06】Jedis客户端(下)

Jedis客户端 1. 命令 1.1 Hash类型 Hash类型相信大家并不陌生&#xff0c;许多编程语言都有对应数据结构的实现&#xff0c;可能叫做哈希、字典、映射、关联数组&#xff0c;是相当重要的&#xff01; 在实际开发中非常常用在面试中也是高频考点 1.1.1 常见命令 HSET命令…