# 新增接口文档 > **创建时间**: 2024-12-29 > **版本**: v1.0 > **状态**: ✅ 已完成 --- ## 📋 接口概览 本次开发完成了4个待开发接口: | 序号 | 接口路径 | 方法 | 功能 | 状态 | |------|---------|------|------|------| | 1 | `/api/upload/work/video` | POST | 视频上传 | ✅ 已完成 | | 2 | `/api/upload/chat/voice` | POST | 语音上传 | ✅ 已完成 | | 3 | `/api/rooms/{roomId}/viewers` | GET | 观众列表 | ✅ 已完成 | | 4 | `/api/rooms/{roomId}/gift` | POST | 赠送礼物 | ✅ 已完成 | --- ## 1️⃣ 视频上传接口 ### 基本信息 - **接口路径**: `POST /api/upload/work/video` - **功能描述**: 上传作品视频文件 - **需要登录**: 否(公开接口) - **限流**: 无 ### 请求参数 **Content-Type**: `multipart/form-data` | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | multipart | File | 是 | 视频文件 | video.mp4 | | model | String | 否 | 模块名称 | works(默认) | | pid | Integer | 否 | 分类ID | 0(默认) | ### 文件限制 - **支持格式**: MP4, MOV, AVI, FLV - **文件大小**: 最大 500MB - **存储路径**: `video/{model}/yyyy/MM/dd/` ### 响应示例 ```json { "code": 200, "message": "操作成功", "data": { "fileName": "my_video.mp4", "fileSize": 52428800, "extName": "mp4", "url": "video/public/works/2024/12/29/abc123.mp4", "type": "video/mp4" } } ``` ### 错误码 | 错误码 | 说明 | |--------|------| | 400 | 视频格式不支持 | | 400 | 文件大小超过限制 | | 500 | 上传失败 | ### 使用示例 ```javascript // JavaScript示例 const formData = new FormData(); formData.append('multipart', videoFile); formData.append('model', 'works'); formData.append('pid', 0); fetch('/api/upload/work/video', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => console.log(data)); ``` --- ## 2️⃣ 语音上传接口 ### 基本信息 - **接口路径**: `POST /api/upload/chat/voice` - **功能描述**: 上传语音消息文件 - **需要登录**: 否(公开接口) - **限流**: 无 ### 请求参数 **Content-Type**: `multipart/form-data` | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | multipart | File | 是 | 语音文件 | voice.mp3 | | model | String | 否 | 模块名称 | chat(默认) | | pid | Integer | 否 | 分类ID | 0(默认) | ### 文件限制 - **支持格式**: MP3, AAC, WAV, M4A - **文件大小**: 最大 10MB - **存储路径**: `voice/{model}/yyyy/MM/dd/` ### 响应示例 ```json { "code": 200, "message": "操作成功", "data": { "fileName": "voice_message.mp3", "fileSize": 1048576, "extName": "mp3", "url": "voice/public/chat/2024/12/29/xyz789.mp3", "type": "audio/mp3" } } ``` ### 错误码 | 错误码 | 说明 | |--------|------| | 400 | 语音格式不支持 | | 400 | 文件大小超过限制 | | 500 | 上传失败 | ### 使用示例 ```javascript // JavaScript示例 const formData = new FormData(); formData.append('multipart', voiceFile); formData.append('model', 'chat'); formData.append('pid', 0); fetch('/api/upload/chat/voice', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => console.log(data)); ``` --- ## 3️⃣ 观众列表接口 ### 基本信息 - **接口路径**: `GET /api/rooms/{roomId}/viewers` - **功能描述**: 获取直播间在线观众列表 - **需要登录**: 否(公开接口) - **限流**: 无 ### 请求参数 **URL参数**: | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | roomId | Integer | 是 | 直播间ID | 123 | **Query参数**: | 参数名 | 类型 | 必填 | 说明 | 默认值 | |--------|------|------|------|--------| | limit | Integer | 否 | 返回数量限制 | 50 | ### 响应示例 ```json { "code": 200, "message": "操作成功", "data": [ { "userId": 1001, "nickname": "用户1001", "avatar": "https://example.com/avatar/1001.jpg", "level": 5, "isVip": true, "enterTime": 1703836800000, "isOnline": true, "clientId": "user_1001_1703836800000" }, { "userId": null, "nickname": "游客", "avatar": "", "level": 0, "isVip": false, "enterTime": 1703836900000, "isOnline": true, "clientId": "guest_abc123_1703836900000" } ] } ``` ### 响应字段说明 | 字段名 | 类型 | 说明 | |--------|------|------| | userId | Integer | 用户ID(游客为null) | | nickname | String | 用户昵称 | | avatar | String | 用户头像URL | | level | Integer | 用户等级 | | isVip | Boolean | 是否VIP | | enterTime | Long | 进入时间(时间戳) | | isOnline | Boolean | 是否在线 | | clientId | String | 客户端唯一标识 | ### 错误码 | 错误码 | 说明 | |--------|------| | 400 | 房间ID不能为空 | | 500 | 获取观众列表失败 | ### 使用示例 ```javascript // JavaScript示例 fetch('/api/rooms/123/viewers?limit=50') .then(response => response.json()) .then(data => { console.log('在线观众:', data.data); }); ``` --- ## 4️⃣ 赠送礼物接口 ### 基本信息 - **接口路径**: `POST /api/rooms/{roomId}/gift` - **功能描述**: 在直播间赠送礼物给主播 - **需要登录**: ✅ 是(需要Token) - **限流**: 建议添加(防止刷礼物) ### 请求参数 **URL参数**: | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | roomId | Integer | 是 | 直播间ID | 123 | **Body参数** (JSON): | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | giftId | Integer | 是 | 礼物ID | 1 | | giftCount | Integer | 是 | 礼物数量(≥1) | 1 | | receiverId | Integer | 是 | 接收者用户ID(主播ID) | 100 | ### 请求示例 ```json { "giftId": 1, "giftCount": 5, "receiverId": 100 } ``` ### 响应示例 ```json { "code": 200, "message": "操作成功", "data": { "recordId": 1001, "giftName": "玫瑰花", "giftCount": 5, "totalDiamond": 50.00, "remainingDiamond": 450.00, "intimacy": 50, "sendTime": 1703836800000 } } ``` ### 响应字段说明 | 字段名 | 类型 | 说明 | |--------|------|------| | recordId | Long | 礼物记录ID | | giftName | String | 礼物名称 | | giftCount | Integer | 礼物数量 | | totalDiamond | BigDecimal | 消耗钻石总数 | | remainingDiamond | BigDecimal | 剩余钻石数 | | intimacy | Integer | 增加的亲密度 | | sendTime | Long | 赠送时间(时间戳) | ### 业务逻辑 1. **验证礼物**: 检查礼物是否存在且启用 2. **验证用户**: 检查赠送者和接收者是否存在 3. **计算总价**: 单价 × 数量 4. **检查余额**: 验证赠送者钻石余额是否充足 5. **扣除钻石**: 从赠送者账户扣除钻石 6. **增加收益**: 给接收者(主播)增加钻石(70%分成) 7. **创建记录**: 保存礼物赠送记录 8. **返回结果**: 返回赠送详情 ### 错误码 | 错误码 | 说明 | |--------|------| | 400 | 房间ID不能为空 | | 400 | 礼物ID不能为空 | | 400 | 礼物数量至少为1 | | 400 | 接收者用户ID不能为空 | | 400 | 不能给自己赠送礼物 | | 404 | 礼物不存在 | | 404 | 用户不存在 | | 404 | 接收者不存在 | | 404 | 直播间不存在 | | 400 | 礼物已下架 | | 400 | 钻石余额不足 | | 401 | 请先登录 | | 500 | 扣除钻石失败 | | 500 | 赠送礼物失败 | ### 使用示例 ```javascript // JavaScript示例 fetch('/api/rooms/123/gift', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer YOUR_TOKEN' }, body: JSON.stringify({ giftId: 1, giftCount: 5, receiverId: 100 }) }) .then(response => response.json()) .then(data => { if (data.code === 200) { console.log('赠送成功:', data.data); } else { console.error('赠送失败:', data.message); } }); ``` --- ## 📦 数据库表结构 ### eb_gift_record - 礼物赠送记录表 ```sql CREATE TABLE `eb_gift_record` ( `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID', `room_id` INT NOT NULL COMMENT '直播间ID', `gift_id` INT NOT NULL COMMENT '礼物ID', `gift_name` VARCHAR(100) COMMENT '礼物名称', `gift_image` VARCHAR(255) COMMENT '礼物图片', `sender_id` INT NOT NULL COMMENT '赠送者用户ID', `sender_nickname` VARCHAR(50) COMMENT '赠送者昵称', `sender_avatar` VARCHAR(255) COMMENT '赠送者头像', `receiver_id` INT NOT NULL COMMENT '接收者用户ID(主播)', `receiver_nickname` VARCHAR(50) COMMENT '接收者昵称', `gift_count` INT NOT NULL DEFAULT 1 COMMENT '礼物数量', `diamond_price` DECIMAL(10,2) DEFAULT 0.00 COMMENT '单价(钻石)', `total_diamond` DECIMAL(10,2) DEFAULT 0.00 COMMENT '总价(钻石)', `intimacy` INT DEFAULT 0 COMMENT '增加的亲密度', `is_deleted` TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除 0=未删除 1=已删除', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `ext_field1` VARCHAR(100) COMMENT '扩展字段1:特效类型', `ext_field2` INT COMMENT '扩展字段2:连击次数', `ext_field3` VARCHAR(50) COMMENT '扩展字段3:活动标识', `ext_field4` BIGINT COMMENT '扩展字段4:关联订单ID', `ext_field5` TEXT COMMENT '扩展字段5:JSON扩展数据', PRIMARY KEY (`id`), INDEX `idx_room_id` (`room_id`), INDEX `idx_sender_id` (`sender_id`), INDEX `idx_receiver_id` (`receiver_id`), INDEX `idx_gift_id` (`gift_id`), INDEX `idx_create_time` (`create_time`), INDEX `idx_is_deleted` (`is_deleted`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='礼物赠送记录表'; ``` --- ## 🔧 技术实现 ### 1. 文件上传实现 **核心类**: - `UploadService` - 上传服务接口 - `UploadServiceImpl` - 上传服务实现 - `UserUploadController` - 前端上传控制器 **技术特点**: - 支持多种文件格式验证 - 文件大小限制 - 自动生成唯一文件名 - 按日期分目录存储 - 支持本地存储和云存储(七牛云、OSS、COS等) ### 2. 观众列表实现 **核心类**: - `LiveRoomOnlineService` - 在线服务接口 - `LiveRoomOnlineServiceImpl` - 在线服务实现 - `LiveRoomController` - 直播间控制器 - `LiveRoomOnlineUser` - 观众信息实体 **技术特点**: - 基于WebSocket实时连接 - 使用ConcurrentHashMap保证线程安全 - 支持用户去重(同一用户多标签页只计1人) - 实时更新在线状态 ### 3. 礼物赠送实现 **核心类**: - `GiftRecordService` - 礼物记录服务接口 - `GiftRecordServiceImpl` - 礼物记录服务实现 - `GiftRecord` - 礼物记录实体 - `SendGiftRequest` - 赠送请求对象 - `SendGiftResponse` - 赠送响应对象 **技术特点**: - 使用事务保证数据一致性 - 余额检查和扣除 - 主播收益分成(70%) - 完整的错误处理 - 礼物记录持久化 --- ## 🧪 测试建议 ### 1. 视频上传测试 ```bash # 测试正常上传 curl -X POST http://localhost:8080/api/upload/work/video \ -F "multipart=@test_video.mp4" \ -F "model=works" \ -F "pid=0" # 测试大文件(应该失败) curl -X POST http://localhost:8080/api/upload/work/video \ -F "multipart=@large_video.mp4" # 测试错误格式(应该失败) curl -X POST http://localhost:8080/api/upload/work/video \ -F "multipart=@test.txt" ``` ### 2. 语音上传测试 ```bash # 测试正常上传 curl -X POST http://localhost:8080/api/upload/chat/voice \ -F "multipart=@test_voice.mp3" \ -F "model=chat" \ -F "pid=0" ``` ### 3. 观众列表测试 ```bash # 获取观众列表 curl -X GET "http://localhost:8080/api/rooms/123/viewers?limit=50" ``` ### 4. 赠送礼物测试 ```bash # 赠送礼物 curl -X POST http://localhost:8080/api/rooms/123/gift \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_TOKEN" \ -d '{ "giftId": 1, "giftCount": 5, "receiverId": 100 }' ``` --- ## 📝 注意事项 ### 1. 安全性 - ✅ 视频和语音上传接口建议添加登录验证 - ✅ 赠送礼物接口已添加登录验证 - ⚠️ 建议添加限流防刷(特别是礼物接口) - ⚠️ 建议添加文件内容安全检查 ### 2. 性能优化 - 视频上传建议使用分片上传 - 大文件上传建议使用云存储 - 观众列表建议添加缓存 - 礼物记录建议异步处理 ### 3. 扩展性 - 所有实体类都预留了5个扩展字段 - 支持后续功能扩展 - 使用JPA自动建表,便于维护 --- ## 📊 接口统计 ### 完成情况 | 模块 | 接口数量 | 完成度 | |------|---------|--------| | 文件上传 | 2 | ✅ 100% | | 直播间功能 | 2 | ✅ 100% | | **总计** | **4** | **✅ 100%** | ### 新增文件 | 类型 | 文件数量 | 说明 | |------|---------|------| | 实体类 | 2 | GiftRecord, LiveRoomOnlineUser扩展 | | 请求对象 | 1 | SendGiftRequest | | 响应对象 | 2 | SendGiftResponse, LiveRoomViewerResponse | | DAO层 | 2 | GiftRecordDao, GiftRecordDao.xml | | Service层 | 2 | GiftRecordService, GiftRecordServiceImpl | | Controller层 | 2 | LiveRoomController扩展, UserUploadController扩展 | | **总计** | **11** | - | --- ## 🎯 后续优化建议 ### 短期优化(1-2周) 1. **添加限流**: 使用@RateLimit注解保护接口 2. **添加日志**: 完善操作日志记录 3. **添加监控**: 接入监控系统 4. **性能测试**: 压力测试和优化 ### 中期优化(1个月) 1. **分片上传**: 实现大文件分片上传 2. **云存储**: 集成七牛云/OSS/COS 3. **CDN加速**: 视频和语音文件CDN加速 4. **缓存优化**: Redis缓存观众列表 ### 长期优化(3个月) 1. **实时推送**: WebSocket推送礼物动画 2. **数据分析**: 礼物消费统计和分析 3. **活动系统**: 礼物活动和促销 4. **AI审核**: 视频和语音内容审核 --- **文档版本**: v1.0 **最后更新**: 2024-12-29 **维护人员**: Kiro AI Assistant