java通信:Springboot整合Websocket

Springboot整合Websocket

什么是webSocket?

WebSocket(Web套接字)是一种在单个 TCP 连接上实现全双工通信的协议,允许客户端和服务器之间进行双向实时通信。WebSocket 是 HTML5 标准的一部分,其主要特点包括:

  1. 双向通信: WebSocket 允许服务器向客户端主动推送消息,同时也允许客户端发送消息给服务器,实现了双向通信。
  2. 持久连接: 与传统的 HTTP 请求-响应模型不同,WebSocket 连接在建立后可以一直保持,而不需要为每个消息都建立新的连接,减少了通信的延迟和开销。
  3. 低延迟: WebSocket 具有较低的通信延迟,适用于需要实时性的应用,如在线聊天、实时数据监控、在线游戏等。
  4. 跨域支持: WebSocket 支持跨域通信,可以在不同域名的服务器之间建立连接。
  5. 轻量级头部: WebSocket 协议的头部数据较小,减少了通信开销。

WebSocket 原理

WebSocket 协议建立在 HTTP 协议之上,通过 HTTP 请求的升级机制(Upgrade)来升级为 WebSocket 连接。基本的连接过程如下:

客户端发起 WebSocket 连接请求,与服务器建立 TCP 连接

服务器响应 WebSocket 握手请求,双方达成协议升级,完成连接建立。

建立连接后,客户端和服务器可以通过 WebSocket 消息进行双向通信。

连接可以一直保持开启,直到其中一方发送关闭连接请求。

WebSocket 连接是一个持久连接,使用固定的套接字地址(ws:// 或 wss://)和端口号(通常是 80 或 443)。WebSocket 消息使用一种轻量级的帧格式,减少了通信开销。这使得 WebSocket 适用于需要实时通信的应用,如在线聊天、实时数据更新、在线游戏等。

在 Java 中,WebSocket 库通常会处理 WebSocket 握手、消息编码和解码、连接管理等底层细节,开发者可以专注于应用层的逻辑。WebSocket 协议的双向通信模型使其成为实时通信应用的理想选择,它在实时性要求高的场景中有广泛的应用。

springboot整合websocket过程

pom文件

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.5.6</version> <!-- 使用正确的版本号 -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springws</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springws</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>8</java.version>
    </properties>

基本依赖

java 复制代码
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>5.3.12</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-websocket</artifactId>
            <version>9.0.55</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

</project>

系统配置

java 复制代码
server.port=8080
# WebSocket
websocket.address=ws://localhost:8080

配置文件

java 复制代码
@Configuration
public class WebSocketConfig {

    @Value("${ws://localhost:8080}")
    private String websocketAddress;

    /**
     * 注入ServerEndpointExporter,
     * 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

Wbsocket操作类

java 复制代码
package com.hs.websocket;

import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
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;

@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")  // 接口路径 ws://localhost:8087/webSocket/userId;
public class WebSocket {

    private Session session;
    private String userId;
    private static Map<String, Session> sessionPool = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        sessionPool.put(userId, session);
        log.info("&#8203;``【oaicite:3】``&#8203;有新的连接,总数为: {}", sessionPool.size());
    }

    @OnClose
    public void onClose() {
        sessionPool.remove(userId);
        log.info("&#8203;``【oaicite:2】``&#8203;连接断开,总数为: {}", sessionPool.size());
    }

    @OnMessage
    public void onMessage(String messageText) {
        log.info("&#8203;``【oaicite:1】``&#8203;收到客户端消息: {}", messageText);
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户错误, 原因: {}", error.getMessage());
    }

    public void sendAllMessage(String message) {
        log.info("&#8203;``【oaicite:0】``&#8203;广播消息: {}", message);
        sessionPool.values().forEach(this::sendMessage);
    }

    public void sendOneMessage(String targetUserId, String message) {
        Session session = sessionPool.get(targetUserId);
        if (session != null && session.isOpen()) {
            sendMessage(session, message);
        }
    }

    public void sendMoreMessage(String[] targetUserIds, String message) {
        for (String targetUserId : targetUserIds) {
            Session session = sessionPool.get(targetUserId);
            if (session != null && session.isOpen()) {
                sendMessage(session, message);
            }
        }
    }

    private void sendMessage(Session targetSession, String message) {
        try {
            targetSession.getAsyncRemote().sendText(message);
        } catch (IOException e) {
            log.error("发送消息失败: {}", e.getMessage());
        }
    }
}

前端测试

java 复制代码
<!DOCTYPE HTML>
<html>
<head>
    <title>Test My WebSocket</title>
</head>


<body>
TestWebSocket
<input id="text" type="text"/>
<button onclick="send()">SEND MESSAGE</button>
<button onclick="closeWebSocket()">CLOSE</button>
<div id="message"></div>
</body>

<script type="text/javascript">
    var websocket = null;


    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        //连接WebSocket节点
        websocket = new WebSocket("ws://localhost:8080/websocket/88");
    } else {
        alert('Not support websocket')
    }


    //连接发生错误的回调方法
    websocket.onerror = function () {
        setMessageInnerHTML("error");
    };


    //连接成功建立的回调方法
    websocket.onopen = function (event) {
        setMessageInnerHTML("open");
    }


    //接收到消息的回调方法
    websocket.onmessage = function (event) {
        setMessageInnerHTML(event.data);
    }


    //连接关闭的回调方法
    websocket.onclose = function () {
        setMessageInnerHTML("close");
    }


    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function () {
        websocket.close();
    }


    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }


    //关闭连接
    function closeWebSocket() {
        websocket.close();
    }


    //发送消息
    function send() {
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
</script>
</html>

postman测试

创建新的workspaces

通过ctrl+n进入

基于以下url进行联通测试

java 复制代码
ws://localhost:8080/websocket/88
相关推荐
欢乐少年19043 小时前
SpringBoot集成Sentry日志收集-3 (Spring Boot集成)
spring boot·后端·sentry
夏天的味道٥4 小时前
使用 Java 执行 SQL 语句和存储过程
java·开发语言·sql
冰糖码奇朵5 小时前
大数据表高效导入导出解决方案,mysql数据库LOAD DATA命令和INTO OUTFILE命令详解
java·数据库·sql·mysql
好教员好5 小时前
【Spring】整合【SpringMVC】
java·spring
浪九天6 小时前
Java直通车系列13【Spring MVC】(Spring MVC常用注解)
java·后端·spring
堕落年代7 小时前
Maven匹配机制和仓库库设置
java·maven
功德+n7 小时前
Maven 使用指南:基础 + 进阶 + 高级用法
java·开发语言·maven
随风九天7 小时前
Spring Boot + MyBatis + MySQL:快速搭建CRUD应用
spring boot·mysql·mybatis
香精煎鱼香翅捞饭7 小时前
java通用自研接口限流组件
java·开发语言
ChinaRainbowSea8 小时前
Linux: Centos7 Cannot find a valid baseurl for repo: base/7/x86_64 解决方案
java·linux·运维·服务器·docker·架构