当前位置: 首页 > news >正文

基于websocket聊天室的基本点

一、核心注解与变量说明

1. 类注解
  • @ServerEndpoint(value="/chat/{roomId}/{nickname}", configurator = GetHttpSessionConfig.class)
    标记这是一个 WebSocket 端点,客户端通过 ws://服务器地址/chat/房间ID/用户名 连接。configurator 用于获取 HTTP 会话信息(可选)。
  • @Component:将该类注册为 Spring 组件,使其被 Spring 管理。
  • @Slf4j:Lombok 注解,提供日志打印功能(log.info() 等)。
2. 静态变量(全局共享)
  • onlineCount:原子整数,线程安全地记录当前在线用户总数。
  • userToRoomMapConcurrentHashMap,记录「用户会话 ID → 房间 ID」的映射(用于快速查找用户所在房间)。
  • roomToUsersMapConcurrentHashMap,记录「房间 ID → 房间内用户集合」的映射(用于管理房间内的用户)。
3. 实例变量(每个连接独有)
  • session:当前用户的 WebSocket 会话对象(用于收发消息)。
  • roomId:当前用户所在的房间 ID。
  • nickname:当前用户的昵称。
  • gson:Gson 实例,用于 JSON 格式的消息转换(前后端消息通过 JSON 传递)。

二、核心方法详解

1. 连接建立:@OnOpen 注解方法

java

运行

@OnOpen
public void onOpen(Session session, @PathParam("roomId") String roomId, @PathParam("nickname") String nickname) throws IOException

  • 触发时机:客户端首次连接到 WebSocket 端点时调用。
  • 功能
    • 初始化当前连接的会话(session)、房间 ID(roomId)、用户昵称(nickname)。
    • 在线用户数 +1(onlineCount.incrementAndGet())。
    • 将用户加入房间:如果房间不存在则创建(roomToUsersMap.computeIfAbsent),并将用户信息(User 对象)存入房间。
    • 记录用户与房间的映射(userToRoomMap.put)。
    • 发送欢迎消息给当前用户(sendMessage)。
    • 广播 “用户加入” 的系统消息给房间内其他用户(broadcastSystemMessage)。
    • 广播更新房间内的在线用户列表(broadcastUserList)。
2. 接收消息:@OnMessage 注解方法

java

运行

@OnMessage
public void onMessage(String message, Session session)

  • 触发时机:收到客户端发送的消息时调用(消息格式为 JSON 字符串)。
  • 功能
    • 解析 JSON 消息为 MapparseMessage 方法),获取消息类型(type)。
    • 根据消息类型分发给不同的处理方法:
      • type="msg":文本消息 → 调用 handleTextMessage
      • type="img":图片消息 → 调用 handleImageMessage
      • type="init":初始化房间 → 调用 handleRoomJoin
      • type="ping":心跳检测 → 忽略。
3. 连接关闭:@OnClose 注解方法

java

运行

@OnClose
public void onClose(Session session)

  • 触发时机:客户端断开 WebSocket 连接时调用。
  • 功能
    • 调用 handleUserExit 处理用户退出逻辑。
    • 打印日志记录用户断开连接。
4. 消息处理核心方法
(1)处理图片消息:handleImageMessage

java

运行

private void handleImageMessage(Map<String, String> msgMap)

  • 功能:处理客户端发送的图片消息(本质是图片 URL)。
    • 通过 getUser(session) 获取发送者信息。
    • 构建响应消息:包含类型(type="img")、图片 URL(msg 字段,来自客户端的 content)、发送者昵称(sendUser)。
    • 调用 broadcastMessage 将图片消息广播给房间内所有用户。
(2)处理文本消息:handleTextMessage

java

运行

private void handleTextMessage(Map<String, String> msgMap)

  • 功能:处理客户端发送的文本消息。
    • 获取发送者信息,构建响应消息:类型(type="msg")、文本内容(msg)、发送者昵称(sendUser)。
    • 广播消息给房间内所有用户(支持排除被屏蔽的用户)。
(3)处理用户加入房间:handleRoomJoin

java

运行

private void handleRoomJoin(Map<String, String> msgMap)

  • 功能:当客户端主动发送 “加入房间” 请求时调用(补充 onOpen 逻辑)。
    • 从消息中获取房间 ID 和昵称,创建用户对象并加入房间。
    • 广播 “用户加入” 的系统消息。
(4)处理用户退出:handleUserExit

java

运行

private void handleUserExit()

  • 功能:用户断开连接时,清理用户信息并更新房间状态。
    • 从房间中移除用户,在线用户数 -1。
    • 广播 “用户离开” 的系统消息,更新在线用户列表。
    • 如果房间为空(用户全部离开),删除房间(roomToUsersMap.remove)。
5. 消息广播方法
(1)广播系统消息:broadcastSystemMessage

java

运行

private void broadcastSystemMessage(CopyOnWriteArraySet<User> users, String message)

  • 功能:向房间内所有用户发送系统消息(如 “用户加入 / 离开”)。
    • 构建系统消息(type="system",发送者为 “系统消息”)。
    • 遍历房间内用户,仅向会话未关闭的用户发送消息。
(2)广播用户列表:broadcastUserList

java

运行

private void broadcastUserList(CopyOnWriteArraySet<User> users)

  • 功能:当房间内用户变化时(加入 / 离开),向所有用户广播最新的在线用户列表。
    • 构建用户列表消息(type="user-list"),包含每个用户的 ID 和昵称。
    • 通过 broadcastMessage 广播给房间内用户。
(3)通用广播方法:broadcastMessage

java

运行

private void broadcastMessage(CopyOnWriteArraySet<User> users, String message, String excludeUsers)

  • 功能:向房间内用户广播消息,支持排除指定用户(如被屏蔽的用户)。
    • 过滤条件:仅向会话打开的用户发送,且不在排除列表中。
    • 遍历用户并发送消息(user.getWebSocket().sendMessage)。
6. 辅助方法
  • sendMessage:向当前会话(单个用户)发送消息(需检查会话是否打开)。
  • parseMessage:将 JSON 字符串解析为 Map(方便获取消息字段)。
  • getRoomUsers:根据会话获取用户所在房间的所有用户。
  • getUser:根据会话查找对应的用户对象(通过会话 ID 匹配)。

三、整体流程总结

  1. 用户连接:客户端通过 ws://地址/chat/房间ID/昵称 连接,onOpen 方法初始化并加入房间,广播用户加入。
  2. 发送消息:客户端发送文本 / 图片消息,onMessage 解析类型后调用对应处理方法,构建响应并广播给房间内所有用户。
  3. 用户退出:客户端断开连接,onClose 触发 handleUserExit,清理用户信息,广播用户离开,更新在线列表。

通过线程安全的集合(ConcurrentHashMapCopyOnWriteArraySet)保证多用户并发操作时的数据一致性,实现了一个支持多房间、多用户实时聊天的功能。

http://www.dtcms.com/a/342853.html

相关文章:

  • SQL中的游标
  • html ajax前端页面
  • 51单片机-驱动直流电机模块教程
  • 单片机\物联网\51单片机\嵌入式开发\软硬件结合的基于STM32的电梯管理系统的设计/基于STM32的电梯运行系统的设计
  • 【华为OD-C卷-020 -关联端口组合并 100分(python、java、c++、js、c)】
  • 解决 uniapp 修改index.html文件不生效的问题
  • PCB文件怎么快速判断是通孔还是盲孔呢?
  • Git 2.15.0 64位安装步骤Windows详细教程从下载到验证(附安装包下载)
  • 14、外部中断
  • 【科普向-第三篇】汽车电子MCU操作系统详解:CP AUTOSAR与FreeRTOS
  • 1688电商商品大数据采集之路 技术篇
  • 嵌入式接口通识知识之PWM接口
  • 机器学习聚类与集成算法全解析:从 K-Means 到随机森林的实战指南
  • 从系统漏洞归零到候诊缩短20%:一个信创样本的效能革命
  • 播放器视频后处理实践(一)
  • 视频加水印 视频加水印软件 视频加动态水印
  • 音视频面试题集锦第 29 期
  • 如何有效防止视频在浏览器播放时被录屏?
  • 全媒体人才培育对接会:国际数字影像产业园赋能企业发展
  • 如何学习编程
  • 完全背包(模板)
  • Mysql基础(③事务)
  • [ Servlet 服务器]
  • LTM框架Letta
  • Java项目:基于SpringBoot和VUE的在线拍卖系统(源码+数据库+文档)
  • 【leetcode】202. 快乐数
  • IKE工作过程
  • 树表转换成有层次的List列表(无限层级)
  • 北京-15k测试-入职甲方金融-上班第二天
  • Python面向对象高级编程——多重继承