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

java 复制代码
<?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配置类

java 复制代码
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常见关闭状态码:
java 复制代码
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端点类的对象映射的路径与服务端映射的路径相同
  • J avaScript的WebSocket端点类也可以捕捉4个事件:
    • 打开连接事件
    • 接收消息事件
    • 发生错误事件
    • 关闭连接事件
    • 这4个事件与服务器端点的4个事件具有相同的逻辑
  • WebSocket端点类的对象常用方法:
    • send():向服务端发送消息
    • close():正常关闭连接
html 复制代码
<!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控制器

java 复制代码
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启动类

java 复制代码
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

关闭浏览器后

相关推荐
假装我不帅1 小时前
asp.net framework从webform开始创建mvc项目
后端·asp.net·mvc
神仙别闹1 小时前
基于ASP.NET+SQL Server实现简单小说网站(包括PC版本和移动版本)
后端·asp.net
计算机-秋大田2 小时前
基于Spring Boot的船舶监造系统的设计与实现,LW+源码+讲解
java·论文阅读·spring boot·后端·vue
货拉拉技术2 小时前
货拉拉-实时对账系统(算盘平台)
后端
掘金酱3 小时前
✍【瓜分额外奖金】11月金石计划附加挑战赛-活动命题发布
人工智能·后端
代码之光_19803 小时前
保障性住房管理:SpringBoot技术优势分析
java·spring boot·后端
ajsbxi3 小时前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
颜淡慕潇4 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决