Spring集成WebSocket

Spring集成WebSocket归纳

一、集成 spring-boot-starter-websocket

场景:通常用于在Java项目中做socket服务器

1.添加Maven依赖
xml 复制代码
<dependencies>
  <!-- 只需要这一个依赖,其他都自动包含 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
</dependencies>
2.启用 @ServerEndpoint 支持
java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * 启用标准 JSR-356 WebSocket 支持(@ServerEndpoint)
 */
@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
3.编写 WebSocket 服务端(使用 @ServerEndpoint)
java 复制代码
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * WebSocket 服务端点
 * 注意:包是 javax.websocket.*(Spring Boot 2.x)
 *       如果是 Spring Boot 3.x,则是 jakarta.websocket.*
 */
@ServerEndpoint("/ws/hello")
public class HelloWebSocket {

    private static final CopyOnWriteArrayList<Session> sessions = new CopyOnWriteArrayList<>();

    @OnOpen
    public void onOpen(Session session) {
        sessions.add(session);
        System.out.println("新客户端连接: " + session.getId());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("收到消息: " + message);
        // 广播给所有客户端
        for (Session s : sessions) {
            if (s.isOpen()) {
                try {
                    s.getBasicRemote().sendText("服务端回复: " + message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @OnMessage
    public void onBinaryMessage(byte[] data, Session session) {
        // 可处理二进制消息
    }
}
4.Spring Boot 启动类
java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WebSocketApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebSocketApplication.class, args);
    }
}
5.前端页面
html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <title>WebSocket @ServerEndpoint 测试</title>
  </head>
  <body>
    <h3>打开浏览器控制台查看消息</h3>
    <script>
      const ws = new WebSocket("ws://localhost:8080/ws/hello");
      ws.onopen = () => {
        console.log("WebSocket 连接成功");
        ws.send("Hello from browser!");
      };
      ws.onmessage = (event) => {
        console.log("收到消息: " + event.data);
      };
      ws.onerror = (error) => {
        console.error("WebSocket 错误: ", error);
      };
    </script>
  </body>
</html>
6.说明
Spring Boot 版本 WebSocket 包名 说明
2.x javax.websocket.* Java EE 风格
3.x jakarta.websocket.* Jakarta EE 风格(Java EE 的延续)

但无论哪个版本,都不需要手动添加 javax.websocket-api 或 jakarta.websocket-api 依赖。

二、继承 WebSocketClient 实现客户端

场景:通常用于在Java程序中,使用websocket连接远程服务器,进行通信

1.添加Maven依赖
xml 复制代码
<dependency>
  <groupId>org.java-websocket</groupId>
  <artifactId>Java-WebSocket</artifactId>
  <version>1.5.3</version> <!-- 请使用最新版本 -->
</dependency>
2.继承 WebSocketClient 实现客户端
java 复制代码
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.java_websocket.drafts.Draft_6455;

import java.net.URI;
import java.net.URISyntaxException;

public class MyWebSocketClient extends WebSocketClient {

    public MyWebSocketClient(URI serverUri) {
        super(serverUri, new Draft_6455()); // 使用标准 WebSocket 协议 Draft
    }

    @Override
    public void onOpen(ServerHandshake handshake) {
        System.out.println("WebSocket 连接已建立");
        System.out.println("握手信息: " + handshake.getHttpStatusMessage());
    }

    @Override
    public void onMessage(String message) {
        System.out.println("收到消息: " + message);
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {
        System.out.println("连接关闭,Code: " + code + ", 原因: " + reason + ", 是否远程关闭: " + remote);
    }

    @Override
    public void onError(Exception ex) {
        System.err.println("发生错误: " + ex.getMessage());
        ex.printStackTrace();
    }

    // 可选:重写 onMessage 处理二进制消息
    // @Override
    // public void onMessage(ByteBuffer bytes) { ... }
}
3.启动客户端连接服务器
java 复制代码
public class WebSocketClientExample {
    public static void main(String[] args) {
        try {
            // 连接到本地运行的 WebSocket 服务端(例如 ws://localhost:8080/websocket)
            URI uri = new URI("ws://localhost:8080/websocket");

            MyWebSocketClient client = new MyWebSocketClient(uri);
            client.connect(); // 异步连接

            // 等待连接建立(简单等待,生产环境建议用 latch 或事件机制)
            Thread.sleep(3000);

            if (client.isOpen()) {
                client.send("Hello from Java-WebSocket Client!");
            }

            // 保持程序运行,接收消息
            System.out.println("按回车键退出...");
            System.in.read();

            // 关闭连接
            client.close();

        } catch (URISyntaxException | InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            System.err.println("启动客户端失败: " + e.getMessage());
        }
    }
}
4.说明
方法 说明
onOpen() 连接成功建立时触发
onMessage(String) 收到文本消息时触发
onMessage(ByteBuffer) 收到二进制消息时触发(可重写)
onClose() 连接关闭时触发,包括正常关闭和异常断开
onError() 发生网络错误、解析错误等时触发
send(String) 发送文本消息
send(ByteBuffer) 发送二进制消息
close() 主动关闭连接

三、实现 WebSocketMessageBrokerConfigurer 接口

场景:通常用于支持PC或H5页面连接通信的服务器

1.添加 Maven 依赖
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>websocket-demo</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.12</version>
    <relativePath/>
  </parent>

  <dependencies>
    <!-- Spring Boot Web Starter -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Boot WebSocket Starter -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>

    <!-- STOMP over WebSocket 支持 -->
    <dependency>
      <groupId>org.webjars</groupId>
      <artifactId>webjars-locator-core</artifactId>
    </dependency>
    <dependency>
      <groupId>org.webjars</groupId>
      <artifactId>sockjs-client</artifactId>
      <version>1.5.1</version>
    </dependency>
    <dependency>
      <artifactId>stomp-websocket</artifactId>
      <groupId>org.webjars</groupId>
      <version>2.3.4</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>
2.配置 WebSocket(WebSocketConfig.java)核心
java 复制代码
package com.example.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker  // 启用 WebSocket 消息代理功能
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    /**
     * 注册 STOMP 端点
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/user/ws")               // 客户端连接的 WebSocket 路径
        .withSockJS();                   // 支持降级到 SockJS(兼容性更好)
    }

    /**
     * 配置消息代理
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic");   // 订阅路径前缀,用于广播消息
        registry.setApplicationDestinationPrefixes("/app"); // 应用消息前缀(发给后端)
    }
}
3.创建消息模型(Greeting.java)
java 复制代码
package com.example.demo;

public class Greeting {
    private String content;

    public Greeting() {}

    public Greeting(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}
4.创建控制器(GreetingController.java)
java 复制代码
package com.example.demo.controller;

import com.example.demo.Greeting;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;

@Controller
public class GreetingController {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    /**
     * 接收客户端发送的消息:/app/greeting
     */
    @MessageMapping("/greeting")
    public void handleGreeting(String name) {
        // 广播消息到所有订阅了 /topic/greeting 的客户端
        messagingTemplate.convertAndSend("/topic/greeting", new Greeting("Hello, " + name + " !"));
    }
}
5.启动类
java 复制代码
package com.example.demo;

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

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
6.前端页面
html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>Spring Boot WebSocket Demo</title>
    <script src="/webjars/sockjs-client/sockjs.min.js"></script>
    <script src="/webjars/stomp-websocket/stomp.min.js"></script>
</head>
<body>
<h2>WebSocket 聊天测试</h2>
<button onclick="connect()">连接</button>
<button onclick="disconnect()">断开</button><br><br>

用户名: <input type="text" id="name" /><br><br>
<button onclick="sendName()">发送问候</button><br><br>

<div id="greeting"></div>

<script>
    let stompClient = null;

    function connect() {
        const socket = new SockJS('/ws');  // 连接到 /ws
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function (frame) {
            console.log('Connected: ' + frame);
            stompClient.subscribe('/topic/greeting', function (greeting) {
                const data = JSON.parse(greeting.body);
                document.getElementById('greeting').innerHTML += `<p>${data.content}</p>`;
            });
        });
    }

    function disconnect() {
        if (stompClient) {
            stompClient.disconnect();
        }
        console.log("Disconnected");
    }

    function sendName() {
        const name = document.getElementById('name').value;
        stompClient.send("/app/greeting", {}, name);
    }
</script>
</body>
</html>
7.说明

/topic 服务端广播给客户端路径

/app 客户端发送给服务端路径

相关推荐
hygge99919 小时前
类加载机制、生命周期、类加载器层次、JVM的类加载方式
java·开发语言·jvm·经验分享·面试
韩立学长19 小时前
基于Springboot的汽车推荐系统设计与实现7f7h74np(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·汽车
一 乐19 小时前
海产品销售系统|海鲜商城购物|基于SprinBoot+vue的海鲜商城系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·后端
q***656919 小时前
Spring Boot集成Kafka:最佳实践与详细指南
spring boot·kafka·linq
大飞哥~BigFei21 小时前
RabbitMq消费延迟衰减重试实现思路
java·分布式·rabbitmq
有趣的野鸭21 小时前
JAVA课程十一次实验课程主要知识点示例
java·前端·数据库
开开心心_Every1 天前
专业视频修复软件,简单操作效果好
学习·elasticsearch·pdf·excel·音视频·memcache·1024程序员节
q***07141 天前
Spring Boot 多数据源解决方案:dynamic-datasource-spring-boot-starter 的奥秘(上)
java·spring boot·后端
郝开1 天前
Spring Boot 2.7.18(最终 2.x 系列版本)8 - 日志:Log4j2 基本概念;Log4j2 多环境日志配置策略
spring boot·单元测试·log4j
q***49861 天前
Spring Boot 3.4 正式发布,结构化日志!
java·spring boot·后端