springboot websocket(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

在现代互联网应用中,实时通讯功能已成为用户交互的核心需求之一。无论是聊天室、在线游戏、股票行情推送还是物联网设备数据同步,都需要一种高效、低延迟的通讯方式。Spring Boot WebSocket 正是为了解决这一需求而设计的技术方案。它基于 WebSocket 协议,结合 Spring Boot 的简洁开发理念,为开发者提供了开箱即用的实时通讯能力。本文将从基础概念到实战案例,逐步解析如何利用 Spring Boot 快速构建 WebSocket 应用,并帮助开发者掌握其核心原理与最佳实践。


一、WebSocket 协议的核心概念

1.1 传统 HTTP 的局限性

HTTP 协议采用“请求-响应”模式,每次客户端需要数据时必须主动发送请求,服务端响应后连接立即关闭。这种模式在处理实时性需求时存在两个主要问题:

  1. 延迟高:客户端需要不断轮询服务器获取更新,增加了网络开销和延迟。
  2. 资源浪费:频繁的短连接会消耗服务器资源,尤其在高并发场景下,性能瓶颈明显。

1.2 WebSocket 的解决方案

WebSocket 是一种在单个 TCP 连接上进行全双工通讯的协议。它通过以下方式优化了实时通讯:

  • 持久连接:建立一次连接后,客户端与服务端可以长期保持通信,无需重复握手。
  • 双向传输:双方可随时主动发送数据,无需等待对方请求。
  • 低开销:数据帧头部仅占 2-10 字节,传输效率远高于 HTTP。

形象比喻
可以将 HTTP 比作“电话通话”,每次通话都需要拨号(建立连接),通话结束后立即挂断;而 WebSocket 则像“视频会议”,双方保持连接,随时传递信息,无需反复建立连接。


二、Spring Boot WebSocket 的核心组件

2.1 核心接口与类

Spring Boot 对 WebSocket 的支持主要通过以下组件实现:
| 组件名称 | 功能描述 |
|-------------------------|--------------------------------------------------------------------------|
| WebSocketHandler | 处理 WebSocket 连接的核心接口,定义消息接收、发送和连接生命周期管理方法。 |
| TextMessage | 用于传输文本消息的对象,支持普通字符串或二进制数据。 |
| WebSocketSession | 表示客户端与服务端之间的连接会话,包含消息收发、元数据存储等能力。 |
| @ServerEndpoint | Spring Boot 早期版本中用于标注 WebSocket 端点的注解(已逐渐被 @MessageMapping 替代)。 |

2.2 Spring Boot 的集成方式

Spring Boot 提供了两种主要集成 WebSocket 的方式:

  1. 基于 WebSocketHandler 的低层 API:适合需要高度自定义逻辑的场景。
  2. 基于注解的 @MessageMapping:通过注解驱动,简化消息处理逻辑的编写(推荐用于大多数场景)。

三、实战案例:构建一个聊天室

3.1 环境搭建

3.1.1 项目依赖

pom.xml 中添加以下依赖:

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

3.1.2 启用 WebSocket 支持

创建配置类并启用 WebSocket

@Configuration  
@EnableWebSocketMessageBroker  
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {  
    @Override  
    public void registerStompEndpoints(StompEndpointRegistry registry) {  
        registry.addEndpoint("/chat")  
                .setAllowedOrigins("*") // 允许跨域  
                .withSockJS(); // 兼容非原生 WebSocket 的客户端  
    }  

    @Override  
    public void configureMessageBroker(MessageBrokerRegistry registry) {  
        registry.setApplicationDestinationPrefixes("/app"); // 前缀用于区分客户端消息  
        registry.enableSimpleBroker("/topic"); // 简单广播机制  
    }  
}  

3.2 消息处理器编写

3.2.1 定义消息格式

创建 ChatMessage 类:

public class ChatMessage {  
    private String content;  
    private String sender;  

    // 构造方法、Getter/Setter 略  
}  

3.2.2 处理消息逻辑

通过 @MessageMapping 注解标注消息处理方法:

@Controller  
public class ChatController {  
    @MessageMapping("/chat.sendMessage")  
    @SendTo("/topic/public")  
    public ChatMessage sendMessage(@Payload ChatMessage message) {  
        return new ChatMessage(message.getContent(), "Server"); // 示例:服务端转发消息  
    }  
}  

3.3 客户端实现

使用 JavaScript 的 WebSocket API 或 SockJS 库连接服务端:

const socket = new SockJS('/chat');  
const stompClient = Stomp.over(socket);  

stompClient.connect({}, function (frame) {  
    console.log('Connected: ' + frame);  
    stompClient.subscribe('/topic/public', function (message) {  
        const msg = JSON.parse(message.body);  
        console.log('Received:', msg.content);  
    });  
});  

// 发送消息  
function sendMessage() {  
    const message = {  
        content: document.getElementById('messageInput').value,  
        sender: 'User'  
    };  
    stompClient.send(  
        "/app/chat.sendMessage",  
        {},  
        JSON.stringify(message)  
    );  
}  

四、进阶优化与注意事项

4.1 消息广播与定向推送

4.1.1 简单广播

通过 @SendTo 注解可将消息广播给所有订阅 /topic/public 的客户端。

4.1.2 定向推送

使用 SimpMessagingTemplate 实现一对一或组内推送:

@Autowired  
private SimpMessagingTemplate messagingTemplate;  

public void sendPrivateMessage(String destination, ChatMessage message) {  
    messagingTemplate.convertAndSendToUser(  
        destination,  
        "/queue/private",  
        message  
    );  
}  

4.2 连接管理与安全性

4.2.1 连接拦截器

通过 HandshakeHandlerWebSocketHandshakeInterceptor 实现身份验证:

@Component  
public class AuthHandshakeInterceptor implements WebSocketHandshakeInterceptor {  
    @Override  
    public boolean beforeHandshake(WebSocketHandler wsHandler,  
                                  WebSocketSession session,  
                                  HandshakeRequest request,  
                                  HandshakeResponse response) {  
        // 验证请求头中的 Token  
        return true; // 验证通过返回 true  
    }  
}  

4.2.2 会话管理

利用 WebSocketSessiongetAttributesetAttribute 方法存储用户信息:

session.setAttribute("userId", 123);  
Object userId = session.getAttribute("userId");  

4.3 性能调优

  • 消息压缩:通过 WebSocketMessageBrokerConfigurer 启用消息压缩。
  • 异步处理:使用 @Async 注解处理耗时操作,避免阻塞主线程。
  • 消息队列:结合 RabbitMQ 或 Kafka 实现高吞吐量的分布式消息分发。

五、常见问题与解决方案

5.1 跨域问题

WebSocketConfigregisterStompEndpoints 方法中设置:

registry.addEndpoint("/chat")  
    .setAllowedOrigins("http://your-frontend-domain");  

5.2 连接超时

通过配置 WebSocketContainer 的超时时间或服务端心跳检测:

@Configuration  
public class WebSocketConfig {  
    @Bean  
    public WebSocketContainer webSocketContainer() {  
        ContainerProvider containerProvider = ContainerProvider.getWebSocketContainer();  
        containerProvider.setDefaultMaxBinaryMessageBufferSize(1024 * 1024); // 自定义配置  
        return containerProvider;  
    }  
}  

5.3 与 REST API 的结合

通过 @MessageMapping@RequestMapping 共存于同一项目,但需确保端点路径不冲突。


六、结论

通过本文的讲解,读者应已掌握 Spring Boot WebSocket 的核心原理、配置方法及实战技巧。从基础概念到聊天室案例,再到性能优化与问题排查,逐步构建了一个完整的实时通讯系统。随着技术的深入,开发者可以进一步探索与消息中间件的集成、移动端适配等高级场景,以满足复杂业务需求。

Spring Boot WebSocket 不仅降低了实时通讯的开发门槛,还通过 Spring 生态的扩展性提供了强大的灵活性。希望本文能帮助开发者快速上手并高效应用这一技术,为构建更流畅的用户交互体验提供坚实基础。

最新发布