Spring Boot 应用中使用 WebSocket

在 Spring Boot 应用中使用 @ServerEndpoint 实现 WebSocket 通信是一种常见方式。@ServerEndpoint 是 Java EE 提供的注解,通常需要配合 javax.websocket API 使用。Spring Boot 本身并不直接管理 @ServerEndpoint,但可以通过一些技巧让它与 Spring 环境集成,同时实现客户端识别和管理。

本文将介绍如何在 Spring Boot 应用中使用 @ServerEndpoint 注解实现 WebSocket 通信,并实现对客户端的识别与管理。

项目依赖配置

首先,在 pom.xml 中添加必要的依赖:

1
2
3
4
5
6
7
<dependencies>
<!-- Spring Boot WebSocket 支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>

这些依赖确保了 Spring Boot 应用能够支持 WebSocket 通信。

WebSocket 配置类

为了使 @ServerEndpoint 注解生效,需要配置 ServerEndpointExporter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {
/**
* 自动注册使用了 @ServerEndpoint 注解声明的 WebSocket 端点
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

注意:如果使用外部的 Tomcat 容器部署应用,则不需要配置 ServerEndpointExporter

创建 WebSocket 服务端端点

使用 @ServerEndpoint 注解定义 WebSocket 端点,并实现客户端的识别与管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@ServerEndpoint("/ws/{clientId}")
public class WebSocketServer {

// 记录当前在线连接数
private static AtomicInteger onlineCount = new AtomicInteger(0);

// 存放所有在线客户端
private static ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();

private String clientId;

/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("clientId") String clientId) {
this.clientId = clientId;
sessionMap.put(clientId, session);
onlineCount.incrementAndGet();
System.out.println("客户端连接: " + clientId + ",当前在线人数为: " + onlineCount.get());
}

/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
sessionMap.remove(clientId);
onlineCount.decrementAndGet();
System.out.println("客户端断开连接: " + clientId + ",当前在线人数为: " + onlineCount.get());
}

/**
* 收到客户端消息后调用的方法
*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("收到客户端(" + clientId + ")消息: " + message);
// 示例:将消息发送给指定客户端
sendMessageToClient(clientId, "服务端收到: " + message);
}

/**
* 发生错误时调用的方法
*/
@OnError
public void onError(Session session, Throwable error) {
System.err.println("客户端(" + clientId + ")发生错误: " + error.getMessage());
}

/**
* 发送消息给指定客户端
*/
public void sendMessageToClient(String clientId, String message) {
Session session = sessionMap.get(clientId);
if (session != null && session.isOpen()) {
session.getAsyncRemote().sendText(message);
}
}

/**
* 广播消息给所有客户端
*/
public void broadcastMessage(String message) {
sessionMap.forEach((clientId, session) -> {
if (session.isOpen()) {
session.getAsyncRemote().sendText(message);
}
});
}
}

在上述代码中,@ServerEndpoint("/ws/{clientId}") 表示客户端连接的地址,其中 {clientId} 用于标识客户端。通过 ConcurrentHashMap 存储客户端的 Session,实现对客户端的识别与管理。

总结

通过上述配置和代码实现,我们在 Spring Boot 应用中成功集成了 WebSocket,并使用 @ServerEndpoint 注解实现了客户端的识别与管理。这种方式适用于需要实时通信的应用场景,如聊天室、通知系统等。

如果您需要进一步的功能扩展,如心跳检测、消息持久化等,可以在此基础上进行开发。