liusuyi
2025-12-22 8c94d8fb9b374cec4626ec01440fa077e62fa67e
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package com.ard.sample.component.websocket.service.impl;
 
import org.springframework.stereotype.Component;
 
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * WebSocket端点类:处理连接、消息收发、断开等事件
 * 端点路径:ws://localhost:8080/ws/{username}(username为客户端标识)
 */
@ServerEndpoint("/ws/Dock/{username}")
@Component
public class WebSocketDockServer {
 
    // 静态变量:存储所有在线客户端的会话(线程安全)
    private static final ConcurrentHashMap<String, Session> ONLINE_USERS = new ConcurrentHashMap<>();
 
    // 当前连接的用户名
    private String username;
 
 
    /**
     * 客户端连接成功时触发
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("username") String username) {
        this.username = username;
        // 保存会话
        ONLINE_USERS.put(username, session);
        // 群发"用户上线"通知
        sendToAll("系统通知:用户【" + username + "】已上线,当前在线人数:" + ONLINE_USERS.size());
        System.out.println("用户【" + username + "】连接成功,在线人数:" + ONLINE_USERS.size());
    }
 
 
    /**
     * 客户端断开连接时触发
     */
    @OnClose
    public void onClose() {
        // 移除会话
        ONLINE_USERS.remove(username);
        // 群发"用户下线"通知
        sendToAll("系统通知:用户【" + username + "】已下线,当前在线人数:" + ONLINE_USERS.size());
        System.out.println("用户【" + username + "】断开连接,在线人数:" + ONLINE_USERS.size());
    }
 
 
    /**
     * 收到客户端消息时触发
     * 消息格式支持:"all:消息内容"(群发)、"username:消息内容"(指定用户发送)
     */
    @OnMessage
    public void onMessage(String message) {
        System.out.println("收到【" + username + "】的消息:" + message);
 
        if (message.startsWith("all:")) {
            // 群发消息(格式:all:你好大家)
            String content = message.substring(4);
            sendToAll("【" + username + "】:" + content);
        } else if (message.contains(":")) {
            // 给指定用户发消息(格式:目标用户名:消息内容)
            String[] parts = message.split(":", 2);
            String targetUser = parts[0];
            String content = parts[1];
            sendToUser(targetUser, "【" + username + "】对你说:" + content);
        } else {
            // 默认群发
            sendToAll("【" + username + "】:" + message);
        }
    }
 
 
    /**
     * 连接异常时触发
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.err.println("WebSocket错误(用户【" + username + "】):");
        error.printStackTrace();
    }
 
 
    // -------------------------- 消息发送工具方法 --------------------------
 
    /**
     * 向单个用户发送消息
     * @param targetUser 目标用户名
     * @param message 消息内容
     */
    public static void sendToUser(String targetUser, String message) {
        Session session = ONLINE_USERS.get(targetUser);
        if (session != null && session.isOpen()) { // 检查会话是否有效
            try {
                // 同步发送消息
                session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                System.err.println("向【" + targetUser + "】发送消息失败:" + e.getMessage());
            }
        } else {
            System.out.println("用户【" + targetUser + "】不在线");
        }
    }
 
 
    /**
     * 向所有在线用户群发消息
     * @param message 消息内容
     */
    public static void sendToAll(String message) {
        for (Session session : ONLINE_USERS.values()) {
            if (session.isOpen()) { // 只给活跃会话发送
                try {
                    session.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    System.err.println("群发消息失败:" + e.getMessage());
                }
            }
        }
    }
}