10 KiB
10 KiB
聊天室实现文档
1. 业务规则
- 一个工单只能创建一个聊天室,一个聊天室可以发起多次会议
- 创建聊天室时自动添加来客和所有在线客服到成员表
- 消息发送使用分布式锁保证时间戳递增,避免并发乱序
2. 核心文件结构
workcase/
├── src/main/java/org/xyzh/workcase/
│ ├── service/
│ │ ├── ChatRoomServiceImpl.java # 聊天室服务实现
│ │ └── MeetServiceImpl.java # 会议服务实现(伪代码)
│ ├── listener/
│ │ └── ChatMessageListener.java # Redis消息监听器
│ ├── config/
│ │ ├── WebSocketConfig.java # STOMP WebSocket配置
│ │ └── RedisSubscriberConfig.java # Redis订阅配置
│ └── mapper/
│ ├── TbChatRoomMapper.java
│ ├── TbChatRoomMemberMapper.java
│ ├── TbChatMessageMapper.java
│ └── TbCustomerServiceMapper.java
apis/api-workcase/
├── src/main/java/org/xyzh/api/workcase/
│ ├── constant/
│ │ └── WorkcaseConstant.java # 常量定义
│ ├── service/
│ │ ├── ChatRoomService.java # 聊天室服务接口
│ │ └── MeetService.java # 会议服务接口
│ ├── dto/
│ │ ├── TbChatRoomDTO.java
│ │ ├── TbChatRoomMemberDTO.java
│ │ └── TbChatMessageDTO.java
│ └── vo/
│ ├── ChatRoomVO.java
│ ├── ChatMemberVO.java
│ └── ChatMessageVO.java
3. Redis Key 设计
| Key | 说明 | 示例 |
|---|---|---|
chat:room:{roomId} |
聊天室消息Pub/Sub频道 | chat:room:abc123 |
chat:room:online:{roomId} |
在线用户Set | chat:room:online:abc123 |
chat:room:lock:{roomId} |
消息发送锁 | chat:room:lock:abc123 |
chat:room:lasttime:{roomId} |
最后消息时间戳 | chat:room:lasttime:abc123 |
chat:list:update |
聊天室列表更新通知频道 | chat:list:update |
4. 消息流转架构
┌─────────────────────────────────────────────────────────────────┐
│ 消息发送流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 客户端 ──HTTP POST──> ChatRoomServiceImpl.sendMessage() │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 获取分布式锁 │ │
│ │ chat:room:lock │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 递增时间戳保证 │ │
│ │ 消息顺序 │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 保存到数据库 │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ redisService.publish("chat:room:{roomId}") │
│ │ │
│ ▼ │
│ redisService.publish("chat:list:update") │
│ │ │
└──────────────────────────────┼──────────────────────────────────┘
│
┌──────────────────────────────┼──────────────────────────────────┐
│ 消息接收流程 │
├──────────────────────────────┼──────────────────────────────────┤
│ │ │
│ RedisSubscriberConfig (订阅 chat:room:*, chat:list:update)│
│ │ │
│ ▼ │
│ ChatMessageListener.onMessage() │
│ ┌────┴────┐ │
│ │ │ │
│ ▼ ▼ │
│ /topic/chat/{roomId} /topic/chat/list-update │
│ (聊天窗口消息) (聊天室列表更新) │
│ │ │ │
│ ▼ ▼ │
│ 聊天窗口订阅者 列表页面订阅者 │
│ │
└─────────────────────────────────────────────────────────────────┘
5. 用户类型常量
| 常量 | 值 | 说明 |
|---|---|---|
USER_TYPE_GUEST |
guest |
来客 |
USER_TYPE_STAFF |
staff |
客服 |
USER_TYPE_AI |
ai |
AI助手 |
6. 状态常量
聊天室状态
| 常量 | 值 | 说明 |
|---|---|---|
ROOM_STATUS_ACTIVE |
active |
活跃 |
ROOM_STATUS_CLOSED |
closed |
已关闭 |
成员状态
| 常量 | 值 | 说明 |
|---|---|---|
MEMBER_STATUS_ACTIVE |
active |
活跃 |
MEMBER_STATUS_LEFT |
left |
已离开 |
MEMBER_STATUS_REMOVED |
removed |
被移除 |
消息状态
| 常量 | 值 | 说明 |
|---|---|---|
MESSAGE_STATUS_SENT |
sent |
已发送 |
MESSAGE_STATUS_RECALLED |
recalled |
已撤回 |
7. 并发消息处理
// 获取分布式锁
String lockKey = WorkcaseConstant.REDIS_CHAT_LOCK + roomId;
redisService.setIfAbsent(lockKey, "1", 5); // 5秒过期
// 保证时间戳递增
String timeKey = WorkcaseConstant.REDIS_CHAT_LASTTIME + roomId;
long lastTime = redisService.get(timeKey);
if (currentTime <= lastTime) {
currentTime = lastTime + 1;
}
message.setSendTime(new Date(currentTime));
redisService.set(timeKey, currentTime);
// 释放锁
redisService.delete(lockKey);
8. 前端WebSocket连接示例
// 连接WebSocket
const socket = new SockJS('/ws/chat');
const stompClient = Stomp.over(socket);
stompClient.connect({}, () => {
// 1. 订阅聊天室消息(聊天窗口使用)
stompClient.subscribe('/topic/chat/' + roomId, (message) => {
const chatMessage = JSON.parse(message.body);
// 处理收到的消息,添加到聊天窗口
console.log('收到消息:', chatMessage);
});
// 2. 订阅聊天室列表更新(列表页面使用)
stompClient.subscribe('/topic/chat/list-update', (message) => {
const chatMessage = JSON.parse(message.body);
// 根据roomId更新对应聊天室的lastMessage和lastMessageTime
updateChatRoomInList(chatMessage.roomId, {
lastMessage: chatMessage.content,
lastMessageTime: chatMessage.sendTime,
senderName: chatMessage.senderName
});
});
});
// 断开连接
stompClient.disconnect();
9. API接口
ChatRoomService
| 方法 | 说明 |
|---|---|
createChatRoom(dto) |
创建聊天室,自动添加来客和客服 |
updateChatRoom(dto) |
更新聊天室信息 |
closeChatRoom(roomId, closedBy) |
关闭聊天室 |
deleteChatRoom(roomId) |
删除聊天室 |
getChatRoomById(roomId) |
获取聊天室详情 |
getChatRoomPage(pageRequest) |
分页查询聊天室 |
addChatRoomMember(member) |
添加成员 |
removeChatRoomMember(memberId) |
移除成员 |
sendMessage(message) |
发送消息(含并发处理) |
getChatMessagePage(pageRequest) |
分页查询消息 |
assignCustomerService(roomId) |
分配所有客服到聊天室 |
MeetService(伪代码)
| 方法 | 说明 |
|---|---|
createMeeting(dto) |
创建会议 |
startMeeting(meetingId) |
开始会议 |
endMeeting(meetingId) |
结束会议 |
joinMeeting(participant) |
参与者加入 |
leaveMeeting(participantId) |
参与者离开 |
generateMeetingJoinUrl(...) |
生成Jitsi加入链接 |
addTranscription(dto) |
添加转录记录 |