1516 lines
29 KiB
Markdown
1516 lines
29 KiB
Markdown
|
|
# 直播IM系统技术方案
|
|||
|
|
|
|||
|
|
## 一、项目概述
|
|||
|
|
|
|||
|
|
### 1.1 项目目标
|
|||
|
|
搭建一个面向直播场景的即时通讯系统,支持1-10万用户规模,一周内完成MVP版本交付。
|
|||
|
|
|
|||
|
|
### 1.2 核心场景
|
|||
|
|
|
|||
|
|
**直播场景**
|
|||
|
|
- 直播间实时弹幕
|
|||
|
|
- 主播与观众互动消息
|
|||
|
|
- 直播间礼物打赏
|
|||
|
|
- 进入/离开直播间通知
|
|||
|
|
|
|||
|
|
**社交交友场景**
|
|||
|
|
- 用户一对一私聊
|
|||
|
|
- 好友申请与通知
|
|||
|
|
- 私聊礼物赠送
|
|||
|
|
- 语音消息发送
|
|||
|
|
- 图片/视频分享
|
|||
|
|
- 表情包发送
|
|||
|
|
- 消息已读/未读状态
|
|||
|
|
|
|||
|
|
**互动场景**
|
|||
|
|
- 作品评论通知
|
|||
|
|
- 点赞通知
|
|||
|
|
- 关注/粉丝通知
|
|||
|
|
- @提醒通知
|
|||
|
|
- 系统公告推送
|
|||
|
|
|
|||
|
|
### 1.3 技术选型原则
|
|||
|
|
- 快速开发,优先使用成熟方案
|
|||
|
|
- 架构简单,便于维护和扩展
|
|||
|
|
- 成本可控,适合初期规模
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、系统架构设计
|
|||
|
|
|
|||
|
|
### 2.1 整体架构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
客户端层(Android App)
|
|||
|
|
↓
|
|||
|
|
API网关层(Nginx)
|
|||
|
|
↓
|
|||
|
|
业务服务层
|
|||
|
|
├── IM服务(WebSocket/长连接)
|
|||
|
|
├── REST API服务(HTTP)
|
|||
|
|
└── 消息推送服务
|
|||
|
|
↓
|
|||
|
|
数据存储层
|
|||
|
|
├── MySQL(用户数据、消息记录)
|
|||
|
|
├── Redis(在线状态、消息缓存)
|
|||
|
|
└── MongoDB(可选,消息归档)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.2 核心模块
|
|||
|
|
|
|||
|
|
#### 2.2.1 连接管理模块
|
|||
|
|
- WebSocket长连接维护
|
|||
|
|
- 心跳检测(30秒间隔)
|
|||
|
|
- 断线重连机制
|
|||
|
|
- 在线状态管理
|
|||
|
|
|
|||
|
|
#### 2.2.2 消息路由模块
|
|||
|
|
- 单聊消息路由
|
|||
|
|
- 群聊(直播间)消息广播
|
|||
|
|
- 消息优先级队列
|
|||
|
|
- 消息去重
|
|||
|
|
|
|||
|
|
#### 2.2.3 消息存储模块
|
|||
|
|
- 离线消息存储
|
|||
|
|
- 历史消息查询
|
|||
|
|
- 消息已读状态
|
|||
|
|
- 消息漫游(7天)
|
|||
|
|
|
|||
|
|
#### 2.2.4 业务功能模块
|
|||
|
|
- 弹幕发送与接收
|
|||
|
|
- 礼物打赏消息(直播间+私聊)
|
|||
|
|
- 好友关系管理
|
|||
|
|
- 消息已读回执
|
|||
|
|
- 语音消息处理
|
|||
|
|
- 图片/视频消息
|
|||
|
|
- 系统通知
|
|||
|
|
- 敏感词过滤
|
|||
|
|
- 消息撤回
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、技术实现方案
|
|||
|
|
|
|||
|
|
### 3.1 通信协议选择
|
|||
|
|
|
|||
|
|
#### 方案一:WebSocket(推荐)
|
|||
|
|
**优点:**
|
|||
|
|
- 双向实时通信
|
|||
|
|
- 浏览器原生支持
|
|||
|
|
- 开发简单,调试方便
|
|||
|
|
- 适合直播弹幕场景
|
|||
|
|
|
|||
|
|
**实现:**
|
|||
|
|
```
|
|||
|
|
协议:ws:// 或 wss://(生产环境必须用wss)
|
|||
|
|
框架:Spring Boot + Spring WebSocket
|
|||
|
|
心跳:客户端30秒发送ping,服务端响应pong
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 方案二:MQTT(备选)
|
|||
|
|
**优点:**
|
|||
|
|
- 轻量级协议
|
|||
|
|
- 支持QoS消息质量保证
|
|||
|
|
- 适合物联网和移动场景
|
|||
|
|
|
|||
|
|
**缺点:**
|
|||
|
|
- 需要额外的Broker(如Mosquitto、EMQ)
|
|||
|
|
- 学习成本稍高
|
|||
|
|
|
|||
|
|
**建议:** 一周交付选WebSocket,后期可扩展MQTT
|
|||
|
|
|
|||
|
|
### 3.2 消息格式设计
|
|||
|
|
|
|||
|
|
#### 3.2.1 通用消息结构(JSON)
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"msgId": "uuid",
|
|||
|
|
"msgType": "text|image|gift|system|barrage",
|
|||
|
|
"fromUserId": "发送者ID",
|
|||
|
|
"toUserId": "接收者ID(私聊)",
|
|||
|
|
"roomId": "直播间ID(弹幕)",
|
|||
|
|
"content": "消息内容",
|
|||
|
|
"timestamp": 1640000000000,
|
|||
|
|
"extra": {
|
|||
|
|
"nickname": "用户昵称",
|
|||
|
|
"avatar": "头像URL",
|
|||
|
|
"giftId": "礼物ID(打赏消息)",
|
|||
|
|
"giftCount": 1
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3.2.2 消息类型定义
|
|||
|
|
| 类型 | 说明 | 场景 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| text | 文本消息 | 私聊、弹幕 |
|
|||
|
|
| image | 图片消息 | 私聊 |
|
|||
|
|
| video | 视频消息 | 私聊 |
|
|||
|
|
| voice | 语音消息 | 私聊 |
|
|||
|
|
| emoji | 表情包消息 | 私聊 |
|
|||
|
|
| gift | 礼物打赏 | 直播间、私聊 |
|
|||
|
|
| barrage | 弹幕 | 直播间 |
|
|||
|
|
| system | 系统通知 | 全局 |
|
|||
|
|
| friend_request | 好友申请 | 社交 |
|
|||
|
|
| friend_accept | 好友通过 | 社交 |
|
|||
|
|
| like | 点赞通知 | 社交 |
|
|||
|
|
| comment | 评论通知 | 社交 |
|
|||
|
|
| follow | 关注通知 | 社交 |
|
|||
|
|
| at_mention | @提醒 | 社交 |
|
|||
|
|
| enter_room | 进入直播间 | 直播间 |
|
|||
|
|
| leave_room | 离开直播间 | 直播间 |
|
|||
|
|
| recall | 消息撤回 | 私聊 |
|
|||
|
|
|
|||
|
|
### 3.3 数据库设计
|
|||
|
|
|
|||
|
|
#### 3.3.1 MySQL表结构
|
|||
|
|
|
|||
|
|
**用户表(user)**
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE `user` (
|
|||
|
|
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
`username` VARCHAR(50) UNIQUE NOT NULL,
|
|||
|
|
`nickname` VARCHAR(50),
|
|||
|
|
`avatar` VARCHAR(255),
|
|||
|
|
`status` TINYINT DEFAULT 1 COMMENT '1-正常 0-禁用',
|
|||
|
|
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
INDEX idx_username (username)
|
|||
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**会话表(conversation)**
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE `conversation` (
|
|||
|
|
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
`user_id` BIGINT NOT NULL,
|
|||
|
|
`target_id` BIGINT NOT NULL COMMENT '对方用户ID或直播间ID',
|
|||
|
|
`type` TINYINT NOT NULL COMMENT '1-单聊 2-直播间',
|
|||
|
|
`last_msg_id` BIGINT,
|
|||
|
|
`last_msg_time` DATETIME,
|
|||
|
|
`unread_count` INT DEFAULT 0,
|
|||
|
|
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|||
|
|
INDEX idx_user_id (user_id),
|
|||
|
|
UNIQUE KEY uk_user_target (user_id, target_id, type)
|
|||
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**消息表(message)**
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE `message` (
|
|||
|
|
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
`msg_id` VARCHAR(64) UNIQUE NOT NULL,
|
|||
|
|
`msg_type` VARCHAR(20) NOT NULL,
|
|||
|
|
`from_user_id` BIGINT NOT NULL,
|
|||
|
|
`to_user_id` BIGINT COMMENT '私聊接收者',
|
|||
|
|
`room_id` BIGINT COMMENT '直播间ID',
|
|||
|
|
`content` TEXT,
|
|||
|
|
`extra` JSON COMMENT '扩展字段(图片URL、语音时长、礼物信息等)',
|
|||
|
|
`status` TINYINT DEFAULT 1 COMMENT '1-正常 2-撤回 3-删除',
|
|||
|
|
`is_read` TINYINT DEFAULT 0 COMMENT '0-未读 1-已读',
|
|||
|
|
`read_at` DATETIME COMMENT '已读时间',
|
|||
|
|
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
INDEX idx_from_user (from_user_id, created_at),
|
|||
|
|
INDEX idx_to_user (to_user_id, created_at),
|
|||
|
|
INDEX idx_room (room_id, created_at),
|
|||
|
|
INDEX idx_msg_id (msg_id),
|
|||
|
|
INDEX idx_unread (to_user_id, is_read)
|
|||
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**好友关系表(friend)**
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE `friend` (
|
|||
|
|
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
`user_id` BIGINT NOT NULL,
|
|||
|
|
`friend_id` BIGINT NOT NULL,
|
|||
|
|
`remark` VARCHAR(50) COMMENT '好友备注',
|
|||
|
|
`status` TINYINT DEFAULT 1 COMMENT '1-正常 2-拉黑',
|
|||
|
|
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
UNIQUE KEY uk_user_friend (user_id, friend_id),
|
|||
|
|
INDEX idx_user_id (user_id),
|
|||
|
|
INDEX idx_friend_id (friend_id)
|
|||
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**好友申请表(friend_request)**
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE `friend_request` (
|
|||
|
|
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
`from_user_id` BIGINT NOT NULL,
|
|||
|
|
`to_user_id` BIGINT NOT NULL,
|
|||
|
|
`message` VARCHAR(200) COMMENT '申请留言',
|
|||
|
|
`status` TINYINT DEFAULT 0 COMMENT '0-待处理 1-已同意 2-已拒绝',
|
|||
|
|
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|||
|
|
INDEX idx_to_user (to_user_id, status),
|
|||
|
|
INDEX idx_from_user (from_user_id),
|
|||
|
|
UNIQUE KEY uk_from_to (from_user_id, to_user_id)
|
|||
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**礼物记录表(gift_record)**
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE `gift_record` (
|
|||
|
|
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
`from_user_id` BIGINT NOT NULL COMMENT '送礼者',
|
|||
|
|
`to_user_id` BIGINT NOT NULL COMMENT '收礼者',
|
|||
|
|
`gift_id` INT NOT NULL,
|
|||
|
|
`gift_name` VARCHAR(50),
|
|||
|
|
`gift_price` INT NOT NULL COMMENT '礼物价格(金币)',
|
|||
|
|
`count` INT DEFAULT 1 COMMENT '数量',
|
|||
|
|
`total_price` INT NOT NULL COMMENT '总价',
|
|||
|
|
`room_id` BIGINT COMMENT '直播间ID(直播间送礼)',
|
|||
|
|
`scene` VARCHAR(20) NOT NULL COMMENT 'live-直播间 chat-私聊',
|
|||
|
|
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
INDEX idx_from_user (from_user_id, created_at),
|
|||
|
|
INDEX idx_to_user (to_user_id, created_at),
|
|||
|
|
INDEX idx_room (room_id, created_at)
|
|||
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**直播间表(live_room)**
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE `live_room` (
|
|||
|
|
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
`room_id` VARCHAR(50) UNIQUE NOT NULL,
|
|||
|
|
`anchor_id` BIGINT NOT NULL COMMENT '主播ID',
|
|||
|
|
`title` VARCHAR(100),
|
|||
|
|
`cover` VARCHAR(255),
|
|||
|
|
`status` TINYINT DEFAULT 1 COMMENT '1-直播中 0-已结束',
|
|||
|
|
`online_count` INT DEFAULT 0,
|
|||
|
|
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
INDEX idx_anchor (anchor_id),
|
|||
|
|
INDEX idx_status (status)
|
|||
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3.3.2 Redis数据结构
|
|||
|
|
|
|||
|
|
**在线用户(Hash)**
|
|||
|
|
```
|
|||
|
|
Key: online:users
|
|||
|
|
Field: userId
|
|||
|
|
Value: {serverId, connectTime, lastHeartbeat}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**直播间在线列表(Set)**
|
|||
|
|
```
|
|||
|
|
Key: room:online:{roomId}
|
|||
|
|
Member: userId
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**用户连接映射(String)**
|
|||
|
|
```
|
|||
|
|
Key: user:connection:{userId}
|
|||
|
|
Value: {serverId, sessionId}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**离线消息队列(List)**
|
|||
|
|
```
|
|||
|
|
Key: offline:msg:{userId}
|
|||
|
|
Value: [msgId1, msgId2, ...]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**消息缓存(String,TTL=7天)**
|
|||
|
|
```
|
|||
|
|
Key: msg:cache:{msgId}
|
|||
|
|
Value: JSON消息体
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、核心功能实现
|
|||
|
|
|
|||
|
|
### 4.1 连接建立流程
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
1. 客户端发起WebSocket连接
|
|||
|
|
ws://domain/ws?token=xxx
|
|||
|
|
|
|||
|
|
2. 服务端验证token
|
|||
|
|
- 解析JWT token
|
|||
|
|
- 验证用户身份
|
|||
|
|
- 检查用户状态
|
|||
|
|
|
|||
|
|
3. 连接成功
|
|||
|
|
- 保存连接到内存Map
|
|||
|
|
- 更新Redis在线状态
|
|||
|
|
- 返回连接成功消息
|
|||
|
|
|
|||
|
|
4. 拉取离线消息
|
|||
|
|
- 从Redis获取离线消息ID列表
|
|||
|
|
- 批量查询消息详情
|
|||
|
|
- 推送给客户端
|
|||
|
|
|
|||
|
|
5. 启动心跳
|
|||
|
|
- 客户端每30秒发送ping
|
|||
|
|
- 服务端响应pong
|
|||
|
|
- 超过90秒无心跳则断开连接
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 单聊消息流程
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
1. 客户端发送消息
|
|||
|
|
{
|
|||
|
|
"action": "sendMessage",
|
|||
|
|
"toUserId": "123",
|
|||
|
|
"msgType": "text",
|
|||
|
|
"content": "你好"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2. 服务端处理
|
|||
|
|
- 生成msgId(UUID)
|
|||
|
|
- 敏感词过滤
|
|||
|
|
- 保存到MySQL
|
|||
|
|
- 缓存到Redis(7天)
|
|||
|
|
|
|||
|
|
3. 消息路由
|
|||
|
|
- 查询接收者在线状态
|
|||
|
|
- 如果在线:通过WebSocket推送
|
|||
|
|
- 如果离线:存入离线消息队列
|
|||
|
|
|
|||
|
|
4. 客户端接收
|
|||
|
|
- 收到消息后发送ACK确认
|
|||
|
|
- 更新会话列表
|
|||
|
|
- 显示消息内容
|
|||
|
|
|
|||
|
|
5. 已读回执(可选)
|
|||
|
|
- 用户查看消息后发送已读状态
|
|||
|
|
- 更新消息已读标记
|
|||
|
|
- 通知发送方
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 直播间弹幕流程
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
1. 用户进入直播间
|
|||
|
|
- 发送enterRoom消息
|
|||
|
|
- 加入Redis直播间在线集合
|
|||
|
|
- 广播进入消息(可选)
|
|||
|
|
|
|||
|
|
2. 发送弹幕
|
|||
|
|
{
|
|||
|
|
"action": "sendBarrage",
|
|||
|
|
"roomId": "room_001",
|
|||
|
|
"content": "主播666"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
3. 服务端处理
|
|||
|
|
- 频率限制(1秒1条)
|
|||
|
|
- 敏感词过滤
|
|||
|
|
- 保存到MySQL(可异步)
|
|||
|
|
- 不缓存到Redis(弹幕量大)
|
|||
|
|
|
|||
|
|
4. 消息广播
|
|||
|
|
- 获取直播间所有在线用户
|
|||
|
|
- 遍历推送消息
|
|||
|
|
- 失败的用户从在线列表移除
|
|||
|
|
|
|||
|
|
5. 离开直播间
|
|||
|
|
- 发送leaveRoom消息
|
|||
|
|
- 从Redis在线集合移除
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.4 礼物打赏流程
|
|||
|
|
|
|||
|
|
**场景一:直播间送礼**
|
|||
|
|
```
|
|||
|
|
1. 客户端发送礼物
|
|||
|
|
{
|
|||
|
|
"action": "sendGift",
|
|||
|
|
"roomId": "room_001",
|
|||
|
|
"anchorId": "456",
|
|||
|
|
"giftId": "gift_001",
|
|||
|
|
"count": 1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2. 服务端处理
|
|||
|
|
- 验证用户余额
|
|||
|
|
- 扣除金币
|
|||
|
|
- 增加主播收益
|
|||
|
|
- 保存打赏记录
|
|||
|
|
|
|||
|
|
3. 消息广播
|
|||
|
|
- 构造礼物消息
|
|||
|
|
- 广播到直播间所有用户
|
|||
|
|
- 触发礼物动画
|
|||
|
|
|
|||
|
|
4. 通知主播
|
|||
|
|
- 发送私信通知
|
|||
|
|
- 更新收益统计
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**场景二:私聊送礼(社交场景)**
|
|||
|
|
```
|
|||
|
|
1. 客户端发送礼物
|
|||
|
|
{
|
|||
|
|
"action": "sendPrivateGift",
|
|||
|
|
"toUserId": "789",
|
|||
|
|
"giftId": "gift_002",
|
|||
|
|
"count": 1,
|
|||
|
|
"message": "送你一朵玫瑰"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2. 服务端处理
|
|||
|
|
- 验证用户余额
|
|||
|
|
- 扣除金币
|
|||
|
|
- 增加对方收益
|
|||
|
|
- 保存礼物记录
|
|||
|
|
- 构造礼物消息
|
|||
|
|
|
|||
|
|
3. 消息推送
|
|||
|
|
- 推送给接收者
|
|||
|
|
- 显示礼物卡片
|
|||
|
|
- 触发礼物动画
|
|||
|
|
- 更新会话列表
|
|||
|
|
|
|||
|
|
4. 收益通知
|
|||
|
|
- 发送收益通知
|
|||
|
|
- 更新用户余额
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.5 好友关系管理
|
|||
|
|
|
|||
|
|
**添加好友流程**
|
|||
|
|
```
|
|||
|
|
1. 发送好友申请
|
|||
|
|
{
|
|||
|
|
"action": "sendFriendRequest",
|
|||
|
|
"toUserId": "123",
|
|||
|
|
"message": "你好,可以加个好友吗?"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2. 服务端处理
|
|||
|
|
- 检查是否已是好友
|
|||
|
|
- 检查是否已发送过申请
|
|||
|
|
- 保存好友申请记录
|
|||
|
|
- 构造申请通知消息
|
|||
|
|
|
|||
|
|
3. 推送通知
|
|||
|
|
- 推送给目标用户
|
|||
|
|
- 显示好友申请红点
|
|||
|
|
- 更新申请列表
|
|||
|
|
|
|||
|
|
4. 处理申请
|
|||
|
|
{
|
|||
|
|
"action": "handleFriendRequest",
|
|||
|
|
"requestId": "456",
|
|||
|
|
"accept": true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
5. 同意后处理
|
|||
|
|
- 更新申请状态
|
|||
|
|
- 双向添加好友关系
|
|||
|
|
- 发送同意通知
|
|||
|
|
- 创建会话
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**删除好友流程**
|
|||
|
|
```
|
|||
|
|
1. 客户端请求删除
|
|||
|
|
{
|
|||
|
|
"action": "deleteFriend",
|
|||
|
|
"friendId": "123"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2. 服务端处理
|
|||
|
|
- 删除好友关系
|
|||
|
|
- 保留历史消息(可选)
|
|||
|
|
- 发送删除通知(可选)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.6 多媒体消息处理
|
|||
|
|
|
|||
|
|
**图片消息流程**
|
|||
|
|
```
|
|||
|
|
1. 上传图片
|
|||
|
|
POST /api/upload/image
|
|||
|
|
- 客户端先上传图片到服务器
|
|||
|
|
- 返回图片URL和缩略图URL
|
|||
|
|
|
|||
|
|
2. 发送图片消息
|
|||
|
|
{
|
|||
|
|
"action": "sendMessage",
|
|||
|
|
"toUserId": "123",
|
|||
|
|
"msgType": "image",
|
|||
|
|
"content": "imageUrl",
|
|||
|
|
"extra": {
|
|||
|
|
"thumbnail": "thumbnailUrl",
|
|||
|
|
"width": 1080,
|
|||
|
|
"height": 1920,
|
|||
|
|
"size": 102400
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
3. 服务端处理
|
|||
|
|
- 验证图片URL合法性
|
|||
|
|
- 保存消息记录
|
|||
|
|
- 推送给接收者
|
|||
|
|
|
|||
|
|
4. 客户端显示
|
|||
|
|
- 先显示缩略图
|
|||
|
|
- 点击查看大图
|
|||
|
|
- 支持图片保存
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**语音消息流程**
|
|||
|
|
```
|
|||
|
|
1. 录制语音
|
|||
|
|
- 客户端录制语音(最长60秒)
|
|||
|
|
- 转换为MP3/AAC格式
|
|||
|
|
- 上传到服务器
|
|||
|
|
|
|||
|
|
2. 发送语音消息
|
|||
|
|
{
|
|||
|
|
"action": "sendMessage",
|
|||
|
|
"toUserId": "123",
|
|||
|
|
"msgType": "voice",
|
|||
|
|
"content": "voiceUrl",
|
|||
|
|
"extra": {
|
|||
|
|
"duration": 15,
|
|||
|
|
"size": 51200
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
3. 服务端处理
|
|||
|
|
- 验证语音文件
|
|||
|
|
- 保存消息记录
|
|||
|
|
- 推送给接收者
|
|||
|
|
|
|||
|
|
4. 客户端播放
|
|||
|
|
- 显示语音时长
|
|||
|
|
- 点击播放
|
|||
|
|
- 显示播放进度
|
|||
|
|
- 标记已读
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**视频消息流程**
|
|||
|
|
```
|
|||
|
|
1. 上传视频
|
|||
|
|
POST /api/upload/video
|
|||
|
|
- 限制视频大小(如50MB)
|
|||
|
|
- 限制视频时长(如30秒)
|
|||
|
|
- 生成视频封面
|
|||
|
|
|
|||
|
|
2. 发送视频消息
|
|||
|
|
{
|
|||
|
|
"action": "sendMessage",
|
|||
|
|
"toUserId": "123",
|
|||
|
|
"msgType": "video",
|
|||
|
|
"content": "videoUrl",
|
|||
|
|
"extra": {
|
|||
|
|
"cover": "coverUrl",
|
|||
|
|
"duration": 20,
|
|||
|
|
"width": 720,
|
|||
|
|
"height": 1280,
|
|||
|
|
"size": 5242880
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
3. 客户端显示
|
|||
|
|
- 显示视频封面
|
|||
|
|
- 显示时长标识
|
|||
|
|
- 点击播放
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.7 消息已读回执
|
|||
|
|
|
|||
|
|
**已读状态更新**
|
|||
|
|
```
|
|||
|
|
1. 用户查看消息
|
|||
|
|
{
|
|||
|
|
"action": "markAsRead",
|
|||
|
|
"conversationId": "123",
|
|||
|
|
"lastMsgId": "msg_456"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2. 服务端处理
|
|||
|
|
- 更新消息已读状态
|
|||
|
|
- 更新会话未读数
|
|||
|
|
- 记录已读时间
|
|||
|
|
|
|||
|
|
3. 推送已读回执
|
|||
|
|
- 通知发送方消息已读
|
|||
|
|
- 显示"已读"标识
|
|||
|
|
- 更新发送方会话列表
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**未读消息统计**
|
|||
|
|
```
|
|||
|
|
1. 获取未读数
|
|||
|
|
GET /api/message/unreadCount
|
|||
|
|
Response: {
|
|||
|
|
"totalUnread": 15,
|
|||
|
|
"conversations": [
|
|||
|
|
{"conversationId": 1, "unread": 5},
|
|||
|
|
{"conversationId": 2, "unread": 10}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2. 实时更新
|
|||
|
|
- 收到新消息时更新未读数
|
|||
|
|
- 标记已读时减少未读数
|
|||
|
|
- 推送未读数变化
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.8 消息撤回功能
|
|||
|
|
|
|||
|
|
**撤回流程**
|
|||
|
|
```
|
|||
|
|
1. 客户端请求撤回
|
|||
|
|
{
|
|||
|
|
"action": "recallMessage",
|
|||
|
|
"msgId": "msg_123"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2. 服务端验证
|
|||
|
|
- 检查消息是否存在
|
|||
|
|
- 检查是否是发送者本人
|
|||
|
|
- 检查是否在2分钟内
|
|||
|
|
- 更新消息状态为已撤回
|
|||
|
|
|
|||
|
|
3. 推送撤回通知
|
|||
|
|
- 通知接收者消息已撤回
|
|||
|
|
- 显示"对方撤回了一条消息"
|
|||
|
|
- 更新会话最后一条消息
|
|||
|
|
|
|||
|
|
4. 客户端处理
|
|||
|
|
- 移除或替换消息内容
|
|||
|
|
- 显示撤回提示
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.9 社交互动通知
|
|||
|
|
|
|||
|
|
**点赞通知**
|
|||
|
|
```
|
|||
|
|
1. 用户点赞作品/评论
|
|||
|
|
POST /api/like
|
|||
|
|
{
|
|||
|
|
"targetType": "work|comment",
|
|||
|
|
"targetId": 123
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2. 服务端处理
|
|||
|
|
- 保存点赞记录
|
|||
|
|
- 构造通知消息
|
|||
|
|
- 推送给作品作者
|
|||
|
|
|
|||
|
|
3. 通知消息格式
|
|||
|
|
{
|
|||
|
|
"type": "like",
|
|||
|
|
"data": {
|
|||
|
|
"userId": 456,
|
|||
|
|
"username": "张三",
|
|||
|
|
"avatar": "xxx",
|
|||
|
|
"targetType": "work",
|
|||
|
|
"targetId": 123,
|
|||
|
|
"targetTitle": "作品标题",
|
|||
|
|
"timestamp": 1640000000000
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**评论通知**
|
|||
|
|
```
|
|||
|
|
1. 用户发表评论
|
|||
|
|
POST /api/comment
|
|||
|
|
{
|
|||
|
|
"workId": 123,
|
|||
|
|
"content": "很棒的作品!"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2. 服务端处理
|
|||
|
|
- 保存评论记录
|
|||
|
|
- 构造通知消息
|
|||
|
|
- 推送给作品作者
|
|||
|
|
|
|||
|
|
3. @提醒处理
|
|||
|
|
- 解析评论中的@用户
|
|||
|
|
- 发送@提醒通知
|
|||
|
|
- 推送给被@的用户
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**关注通知**
|
|||
|
|
```
|
|||
|
|
1. 用户关注他人
|
|||
|
|
POST /api/follow
|
|||
|
|
{
|
|||
|
|
"targetUserId": 123
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
2. 服务端处理
|
|||
|
|
- 保存关注关系
|
|||
|
|
- 构造通知消息
|
|||
|
|
- 推送给被关注者
|
|||
|
|
|
|||
|
|
3. 通知消息
|
|||
|
|
{
|
|||
|
|
"type": "follow",
|
|||
|
|
"data": {
|
|||
|
|
"userId": 456,
|
|||
|
|
"username": "张三",
|
|||
|
|
"avatar": "xxx",
|
|||
|
|
"timestamp": 1640000000000
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.5 系统通知流程
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
1. 后台触发通知
|
|||
|
|
- 关注通知
|
|||
|
|
- 点赞通知
|
|||
|
|
- 评论通知
|
|||
|
|
- 系统公告
|
|||
|
|
- 审核通知
|
|||
|
|
|
|||
|
|
2. 服务端处理
|
|||
|
|
- 构造系统消息
|
|||
|
|
- 保存到MySQL
|
|||
|
|
- 推送给目标用户
|
|||
|
|
|
|||
|
|
3. 客户端接收
|
|||
|
|
- 显示通知红点
|
|||
|
|
- 弹出提示(可选)
|
|||
|
|
- 更新通知列表
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、性能优化方案
|
|||
|
|
|
|||
|
|
### 5.1 连接优化
|
|||
|
|
|
|||
|
|
**单机连接数优化**
|
|||
|
|
- 使用Netty或Spring WebFlux(异步非阻塞)
|
|||
|
|
- 单机支持10万+连接
|
|||
|
|
- 调整系统参数:ulimit -n 100000
|
|||
|
|
|
|||
|
|
**连接保活**
|
|||
|
|
- 客户端心跳:30秒
|
|||
|
|
- 服务端超时:90秒
|
|||
|
|
- 减少无效连接占用
|
|||
|
|
|
|||
|
|
### 5.2 消息优化
|
|||
|
|
|
|||
|
|
**弹幕限流**
|
|||
|
|
- 用户级别:1秒1条
|
|||
|
|
- 直播间级别:每秒1000条(超过则丢弃)
|
|||
|
|
- 使用Redis令牌桶算法
|
|||
|
|
|
|||
|
|
**消息批量处理**
|
|||
|
|
- 弹幕批量入库(100条/批次)
|
|||
|
|
- 离线消息批量拉取(50条/次)
|
|||
|
|
- 减少数据库IO
|
|||
|
|
|
|||
|
|
**消息压缩**
|
|||
|
|
- 启用WebSocket压缩(permessage-deflate)
|
|||
|
|
- 减少30-50%流量
|
|||
|
|
|
|||
|
|
### 5.3 存储优化
|
|||
|
|
|
|||
|
|
**MySQL优化**
|
|||
|
|
- 消息表按月分表
|
|||
|
|
- 历史消息归档到MongoDB
|
|||
|
|
- 只保留3个月热数据
|
|||
|
|
|
|||
|
|
**Redis优化**
|
|||
|
|
- 消息缓存设置TTL(7天)
|
|||
|
|
- 使用Redis Cluster(后期扩展)
|
|||
|
|
- 离线消息队列限制长度(最多100条)
|
|||
|
|
|
|||
|
|
### 5.4 广播优化
|
|||
|
|
|
|||
|
|
**直播间消息广播**
|
|||
|
|
- 异步推送,不阻塞主线程
|
|||
|
|
- 失败重试1次,超时则放弃
|
|||
|
|
- 单次广播超时时间:100ms
|
|||
|
|
|
|||
|
|
**分组广播(后期优化)**
|
|||
|
|
- 将直播间用户分组(每组1000人)
|
|||
|
|
- 多线程并行推送
|
|||
|
|
- 提升广播效率
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、技术栈选型
|
|||
|
|
|
|||
|
|
### 6.1 后端技术栈
|
|||
|
|
|
|||
|
|
**核心框架**
|
|||
|
|
- Spring Boot 2.7+
|
|||
|
|
- Spring WebSocket
|
|||
|
|
- Spring Data JPA / MyBatis-Plus
|
|||
|
|
|
|||
|
|
**中间件**
|
|||
|
|
- MySQL 8.0(主数据库)
|
|||
|
|
- Redis 6.0+(缓存、在线状态)
|
|||
|
|
- Nginx(反向代理、负载均衡)
|
|||
|
|
|
|||
|
|
**工具库**
|
|||
|
|
- JWT(用户认证)
|
|||
|
|
- Jackson(JSON序列化)
|
|||
|
|
- Hutool(工具类)
|
|||
|
|
- Lombok(简化代码)
|
|||
|
|
|
|||
|
|
### 6.2 前端技术栈(Android)
|
|||
|
|
|
|||
|
|
**网络库**
|
|||
|
|
- OkHttp(HTTP请求)
|
|||
|
|
- OkHttp WebSocket(长连接)
|
|||
|
|
|
|||
|
|
**UI框架**
|
|||
|
|
- Material Design Components
|
|||
|
|
- RecyclerView(消息列表)
|
|||
|
|
- ViewPager2(直播间)
|
|||
|
|
|
|||
|
|
**工具库**
|
|||
|
|
- Gson(JSON解析)
|
|||
|
|
- Glide(图片加载)
|
|||
|
|
- EventBus(事件总线)
|
|||
|
|
|
|||
|
|
### 6.3 开发工具
|
|||
|
|
|
|||
|
|
- IntelliJ IDEA(后端开发)
|
|||
|
|
- Android Studio(Android开发)
|
|||
|
|
- Postman(API测试)
|
|||
|
|
- Redis Desktop Manager(Redis管理)
|
|||
|
|
- Navicat(数据库管理)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、部署方案
|
|||
|
|
|
|||
|
|
### 7.1 服务器配置(初期)
|
|||
|
|
|
|||
|
|
**单机部署方案**
|
|||
|
|
```
|
|||
|
|
服务器:阿里云ECS
|
|||
|
|
配置:4核8G 5M带宽
|
|||
|
|
系统:CentOS 7.9
|
|||
|
|
|
|||
|
|
服务部署:
|
|||
|
|
- Nginx(80/443端口)
|
|||
|
|
- Spring Boot IM服务(8080端口)
|
|||
|
|
- MySQL(3306端口)
|
|||
|
|
- Redis(6379端口)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**预估支持规模**
|
|||
|
|
- 同时在线:5000人
|
|||
|
|
- 单直播间:500人
|
|||
|
|
- 消息吞吐:5000条/秒
|
|||
|
|
|
|||
|
|
### 7.2 扩展方案(后期)
|
|||
|
|
|
|||
|
|
**水平扩展**
|
|||
|
|
```
|
|||
|
|
负载均衡(Nginx)
|
|||
|
|
↓
|
|||
|
|
IM服务集群(3台)
|
|||
|
|
↓
|
|||
|
|
Redis集群(主从)
|
|||
|
|
↓
|
|||
|
|
MySQL主从(读写分离)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**支持规模**
|
|||
|
|
- 同时在线:5万人
|
|||
|
|
- 单直播间:5000人
|
|||
|
|
- 消息吞吐:5万条/秒
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 八、开发计划(7天)
|
|||
|
|
|
|||
|
|
### Day 1-2:基础架构搭建
|
|||
|
|
- [x] 搭建Spring Boot项目
|
|||
|
|
- [x] 集成WebSocket
|
|||
|
|
- [x] 配置MySQL、Redis
|
|||
|
|
- [x] 实现用户认证(JWT)
|
|||
|
|
- [x] 实现连接管理模块
|
|||
|
|
|
|||
|
|
### Day 3-4:核心功能开发
|
|||
|
|
- [x] 实现单聊消息收发
|
|||
|
|
- [x] 实现直播间弹幕
|
|||
|
|
- [x] 实现离线消息
|
|||
|
|
- [x] 实现消息存储
|
|||
|
|
- [x] 实现敏感词过滤
|
|||
|
|
|
|||
|
|
### Day 5:业务功能开发
|
|||
|
|
- [x] 实现礼物打赏消息
|
|||
|
|
- [x] 实现系统通知
|
|||
|
|
- [x] 实现消息已读
|
|||
|
|
- [x] 实现历史消息查询
|
|||
|
|
|
|||
|
|
### Day 6:Android客户端对接
|
|||
|
|
- [x] 实现WebSocket连接
|
|||
|
|
- [x] 实现消息收发UI
|
|||
|
|
- [x] 实现弹幕显示
|
|||
|
|
- [x] 实现礼物动画
|
|||
|
|
|
|||
|
|
### Day 7:测试与优化
|
|||
|
|
- [x] 功能测试
|
|||
|
|
- [x] 压力测试(JMeter)
|
|||
|
|
- [x] 性能优化
|
|||
|
|
- [x] 部署上线
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 九、接口设计
|
|||
|
|
|
|||
|
|
### 9.1 WebSocket接口
|
|||
|
|
|
|||
|
|
**连接地址**
|
|||
|
|
```
|
|||
|
|
ws://domain/ws?token=xxx
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**客户端发送消息格式**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"action": "sendMessage|sendBarrage|enterRoom|leaveRoom|heartbeat",
|
|||
|
|
"data": {
|
|||
|
|
// 具体数据
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**服务端推送消息格式**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"type": "message|barrage|gift|system|notification",
|
|||
|
|
"data": {
|
|||
|
|
// 具体数据
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 9.2 HTTP接口
|
|||
|
|
|
|||
|
|
**用户认证**
|
|||
|
|
```
|
|||
|
|
POST /api/auth/login
|
|||
|
|
Body: {
|
|||
|
|
"username": "user123",
|
|||
|
|
"password": "xxx"
|
|||
|
|
}
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": {
|
|||
|
|
"token": "jwt_token",
|
|||
|
|
"userId": 123,
|
|||
|
|
"username": "user123",
|
|||
|
|
"nickname": "张三",
|
|||
|
|
"avatar": "xxx"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**好友相关接口**
|
|||
|
|
|
|||
|
|
**获取好友列表**
|
|||
|
|
```
|
|||
|
|
GET /api/friend/list
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": [
|
|||
|
|
{
|
|||
|
|
"friendId": 123,
|
|||
|
|
"username": "user123",
|
|||
|
|
"nickname": "张三",
|
|||
|
|
"avatar": "xxx",
|
|||
|
|
"remark": "备注名",
|
|||
|
|
"online": true,
|
|||
|
|
"lastOnlineTime": "2024-12-25 10:00:00"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**发送好友申请**
|
|||
|
|
```
|
|||
|
|
POST /api/friend/request
|
|||
|
|
Body: {
|
|||
|
|
"toUserId": 123,
|
|||
|
|
"message": "你好,可以加个好友吗?"
|
|||
|
|
}
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"message": "申请已发送"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**获取好友申请列表**
|
|||
|
|
```
|
|||
|
|
GET /api/friend/requests?status=0
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": [
|
|||
|
|
{
|
|||
|
|
"requestId": 1,
|
|||
|
|
"fromUserId": 456,
|
|||
|
|
"username": "user456",
|
|||
|
|
"nickname": "李四",
|
|||
|
|
"avatar": "xxx",
|
|||
|
|
"message": "你好",
|
|||
|
|
"status": 0,
|
|||
|
|
"createdAt": "2024-12-25 10:00:00"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**处理好友申请**
|
|||
|
|
```
|
|||
|
|
POST /api/friend/handle
|
|||
|
|
Body: {
|
|||
|
|
"requestId": 1,
|
|||
|
|
"accept": true
|
|||
|
|
}
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"message": "已同意好友申请"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**删除好友**
|
|||
|
|
```
|
|||
|
|
DELETE /api/friend/{friendId}
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"message": "已删除好友"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**会话相关接口**
|
|||
|
|
|
|||
|
|
**获取会话列表**
|
|||
|
|
```
|
|||
|
|
GET /api/conversation/list
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": [
|
|||
|
|
{
|
|||
|
|
"conversationId": 1,
|
|||
|
|
"type": 1,
|
|||
|
|
"targetId": 123,
|
|||
|
|
"targetName": "张三",
|
|||
|
|
"targetAvatar": "xxx",
|
|||
|
|
"lastMessage": "你好",
|
|||
|
|
"lastMessageType": "text",
|
|||
|
|
"lastTime": "2024-12-25 10:00:00",
|
|||
|
|
"unreadCount": 3,
|
|||
|
|
"online": true
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**删除会话**
|
|||
|
|
```
|
|||
|
|
DELETE /api/conversation/{conversationId}
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"message": "会话已删除"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**消息相关接口**
|
|||
|
|
|
|||
|
|
**获取历史消息**
|
|||
|
|
```
|
|||
|
|
GET /api/message/history?targetId=123&pageSize=20&lastMsgId=xxx
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": {
|
|||
|
|
"messages": [
|
|||
|
|
{
|
|||
|
|
"msgId": "msg_001",
|
|||
|
|
"msgType": "text",
|
|||
|
|
"fromUserId": 456,
|
|||
|
|
"toUserId": 123,
|
|||
|
|
"content": "你好",
|
|||
|
|
"extra": {},
|
|||
|
|
"status": 1,
|
|||
|
|
"isRead": 1,
|
|||
|
|
"createdAt": "2024-12-25 10:00:00"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"hasMore": true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**上传图片**
|
|||
|
|
```
|
|||
|
|
POST /api/upload/image
|
|||
|
|
Content-Type: multipart/form-data
|
|||
|
|
Body: file=xxx
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": {
|
|||
|
|
"url": "https://xxx.com/image.jpg",
|
|||
|
|
"thumbnail": "https://xxx.com/image_thumb.jpg",
|
|||
|
|
"width": 1080,
|
|||
|
|
"height": 1920,
|
|||
|
|
"size": 102400
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**上传语音**
|
|||
|
|
```
|
|||
|
|
POST /api/upload/voice
|
|||
|
|
Content-Type: multipart/form-data
|
|||
|
|
Body: file=xxx
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": {
|
|||
|
|
"url": "https://xxx.com/voice.mp3",
|
|||
|
|
"duration": 15,
|
|||
|
|
"size": 51200
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**上传视频**
|
|||
|
|
```
|
|||
|
|
POST /api/upload/video
|
|||
|
|
Content-Type: multipart/form-data
|
|||
|
|
Body: file=xxx
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": {
|
|||
|
|
"url": "https://xxx.com/video.mp4",
|
|||
|
|
"cover": "https://xxx.com/cover.jpg",
|
|||
|
|
"duration": 20,
|
|||
|
|
"width": 720,
|
|||
|
|
"height": 1280,
|
|||
|
|
"size": 5242880
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**发送图片消息**
|
|||
|
|
```
|
|||
|
|
POST /api/message/sendImage
|
|||
|
|
Body: {
|
|||
|
|
"toUserId": 123,
|
|||
|
|
"imageUrl": "xxx",
|
|||
|
|
"thumbnail": "xxx",
|
|||
|
|
"width": 1080,
|
|||
|
|
"height": 1920
|
|||
|
|
}
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": {
|
|||
|
|
"msgId": "msg_001"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**标记消息已读**
|
|||
|
|
```
|
|||
|
|
POST /api/message/markRead
|
|||
|
|
Body: {
|
|||
|
|
"conversationId": 1,
|
|||
|
|
"lastMsgId": "msg_456"
|
|||
|
|
}
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"message": "已标记为已读"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**撤回消息**
|
|||
|
|
```
|
|||
|
|
POST /api/message/recall
|
|||
|
|
Body: {
|
|||
|
|
"msgId": "msg_123"
|
|||
|
|
}
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"message": "消息已撤回"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**获取未读消息数**
|
|||
|
|
```
|
|||
|
|
GET /api/message/unreadCount
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": {
|
|||
|
|
"totalUnread": 15,
|
|||
|
|
"conversations": [
|
|||
|
|
{"conversationId": 1, "unread": 5},
|
|||
|
|
{"conversationId": 2, "unread": 10}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**礼物相关接口**
|
|||
|
|
|
|||
|
|
**获取礼物列表**
|
|||
|
|
```
|
|||
|
|
GET /api/gift/list
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": [
|
|||
|
|
{
|
|||
|
|
"giftId": 1,
|
|||
|
|
"name": "玫瑰",
|
|||
|
|
"icon": "xxx",
|
|||
|
|
"price": 10,
|
|||
|
|
"animation": "rose_animation"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**私聊送礼**
|
|||
|
|
```
|
|||
|
|
POST /api/gift/sendPrivate
|
|||
|
|
Body: {
|
|||
|
|
"toUserId": 123,
|
|||
|
|
"giftId": 1,
|
|||
|
|
"count": 1,
|
|||
|
|
"message": "送你一朵玫瑰"
|
|||
|
|
}
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": {
|
|||
|
|
"recordId": 1,
|
|||
|
|
"balance": 990
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**直播间送礼**
|
|||
|
|
```
|
|||
|
|
POST /api/gift/sendLive
|
|||
|
|
Body: {
|
|||
|
|
"roomId": "room_001",
|
|||
|
|
"anchorId": 456,
|
|||
|
|
"giftId": 1,
|
|||
|
|
"count": 1
|
|||
|
|
}
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": {
|
|||
|
|
"recordId": 1,
|
|||
|
|
"balance": 990
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**获取礼物记录**
|
|||
|
|
```
|
|||
|
|
GET /api/gift/records?type=send&pageSize=20&page=1
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": {
|
|||
|
|
"records": [
|
|||
|
|
{
|
|||
|
|
"recordId": 1,
|
|||
|
|
"fromUserId": 123,
|
|||
|
|
"toUserId": 456,
|
|||
|
|
"giftName": "玫瑰",
|
|||
|
|
"count": 1,
|
|||
|
|
"totalPrice": 10,
|
|||
|
|
"scene": "chat",
|
|||
|
|
"createdAt": "2024-12-25 10:00:00"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"total": 100
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**通知相关接口**
|
|||
|
|
|
|||
|
|
**获取通知列表**
|
|||
|
|
```
|
|||
|
|
GET /api/notification/list?type=all&pageSize=20&page=1
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": [
|
|||
|
|
{
|
|||
|
|
"notificationId": 1,
|
|||
|
|
"type": "like",
|
|||
|
|
"fromUserId": 456,
|
|||
|
|
"fromUsername": "张三",
|
|||
|
|
"fromAvatar": "xxx",
|
|||
|
|
"content": "赞了你的作品",
|
|||
|
|
"targetType": "work",
|
|||
|
|
"targetId": 123,
|
|||
|
|
"isRead": 0,
|
|||
|
|
"createdAt": "2024-12-25 10:00:00"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**标记通知已读**
|
|||
|
|
```
|
|||
|
|
POST /api/notification/markRead
|
|||
|
|
Body: {
|
|||
|
|
"notificationIds": [1, 2, 3]
|
|||
|
|
}
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"message": "已标记为已读"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**获取未读通知数**
|
|||
|
|
```
|
|||
|
|
GET /api/notification/unreadCount
|
|||
|
|
Response: {
|
|||
|
|
"code": 200,
|
|||
|
|
"data": {
|
|||
|
|
"like": 5,
|
|||
|
|
"comment": 3,
|
|||
|
|
"follow": 2,
|
|||
|
|
"system": 1,
|
|||
|
|
"total": 11
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十、安全方案
|
|||
|
|
|
|||
|
|
### 10.1 认证鉴权
|
|||
|
|
- 使用JWT token认证
|
|||
|
|
- Token有效期:7天
|
|||
|
|
- 刷新Token机制
|
|||
|
|
|
|||
|
|
### 10.2 消息安全
|
|||
|
|
- 敏感词过滤(本地词库)
|
|||
|
|
- 消息内容长度限制(500字符)
|
|||
|
|
- 图片内容审核(接入第三方)
|
|||
|
|
|
|||
|
|
### 10.3 防刷机制
|
|||
|
|
- 消息发送频率限制
|
|||
|
|
- IP黑名单
|
|||
|
|
- 用户封禁机制
|
|||
|
|
|
|||
|
|
### 10.4 数据安全
|
|||
|
|
- WebSocket使用wss加密
|
|||
|
|
- 数据库密码加密存储
|
|||
|
|
- 敏感信息脱敏
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十一、监控与运维
|
|||
|
|
|
|||
|
|
### 11.1 监控指标
|
|||
|
|
- 在线用户数
|
|||
|
|
- 消息发送量(QPS)
|
|||
|
|
- 接口响应时间
|
|||
|
|
- 服务器CPU/内存/网络
|
|||
|
|
|
|||
|
|
### 11.2 日志管理
|
|||
|
|
- 使用SLF4J + Logback
|
|||
|
|
- 日志分级:ERROR、WARN、INFO
|
|||
|
|
- 日志文件按天切割
|
|||
|
|
- 保留30天日志
|
|||
|
|
|
|||
|
|
### 11.3 告警机制
|
|||
|
|
- 服务宕机告警
|
|||
|
|
- 接口异常告警
|
|||
|
|
- 资源使用告警
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十二、成本预估
|
|||
|
|
|
|||
|
|
### 12.1 服务器成本
|
|||
|
|
- 阿里云ECS 4核8G:约300元/月
|
|||
|
|
- 带宽5M:约50元/月
|
|||
|
|
- 总计:约350元/月
|
|||
|
|
|
|||
|
|
### 12.2 开发成本
|
|||
|
|
- 后端开发:3人天
|
|||
|
|
- Android开发:2人天
|
|||
|
|
- 测试:1人天
|
|||
|
|
- 总计:6人天
|
|||
|
|
|
|||
|
|
### 12.3 第三方服务(可选)
|
|||
|
|
- 图片审核:按量计费
|
|||
|
|
- 短信通知:按量计费
|
|||
|
|
- CDN加速:按流量计费
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十三、风险与应对
|
|||
|
|
|
|||
|
|
### 13.1 技术风险
|
|||
|
|
**风险:** 单机性能瓶颈
|
|||
|
|
**应对:** 提前设计水平扩展方案,预留扩展接口
|
|||
|
|
|
|||
|
|
**风险:** 消息丢失
|
|||
|
|
**应对:** 实现消息ACK机制,离线消息队列
|
|||
|
|
|
|||
|
|
**风险:** 直播间消息风暴
|
|||
|
|
**应对:** 消息限流、降级策略
|
|||
|
|
|
|||
|
|
### 13.2 业务风险
|
|||
|
|
**风险:** 用户量超预期
|
|||
|
|
**应对:** 快速扩容方案,提前准备服务器
|
|||
|
|
|
|||
|
|
**风险:** 恶意刷屏
|
|||
|
|
**应对:** 频率限制、封禁机制
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十四、后续优化方向
|
|||
|
|
|
|||
|
|
### 14.1 功能优化
|
|||
|
|
- 消息撤回
|
|||
|
|
- 消息转发
|
|||
|
|
- @提醒功能
|
|||
|
|
- 表情包支持
|
|||
|
|
- 语音/视频通话
|
|||
|
|
|
|||
|
|
### 14.2 性能优化
|
|||
|
|
- 引入消息队列(RabbitMQ/Kafka)
|
|||
|
|
- 数据库分库分表
|
|||
|
|
- 引入ElasticSearch(消息搜索)
|
|||
|
|
- CDN加速(图片、语音)
|
|||
|
|
|
|||
|
|
### 14.3 架构优化
|
|||
|
|
- 微服务拆分
|
|||
|
|
- 服务注册与发现(Nacos)
|
|||
|
|
- 分布式链路追踪(SkyWalking)
|
|||
|
|
- 容器化部署(Docker + K8s)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 附录
|
|||
|
|
|
|||
|
|
### A. 参考资料
|
|||
|
|
- WebSocket协议:RFC 6455
|
|||
|
|
- MQTT协议:MQTT 3.1.1
|
|||
|
|
- 即时通讯技术选型:https://www.zhihu.com/question/xxx
|
|||
|
|
|
|||
|
|
### B. 开源方案参考
|
|||
|
|
- Netty-SocketIO(Java WebSocket框架)
|
|||
|
|
- t-io(国产高性能IM框架)
|
|||
|
|
- OpenIM(开源IM解决方案)
|
|||
|
|
|
|||
|
|
### C. 敏感词库
|
|||
|
|
- 使用DFA算法实现高效过滤
|
|||
|
|
- 词库来源:GitHub开源项目
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**文档版本:** v1.0
|
|||
|
|
**编写日期:** 2024-12-25
|
|||
|
|
**适用范围:** 1-10万用户规模的直播IM系统
|