251 lines
7.1 KiB
Markdown
251 lines
7.1 KiB
Markdown
|
|
# 课程视频接口文档
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
本文档描述了新增的两个课程视频相关接口:
|
|||
|
|
1. 课程视频详情接口 - 所有用户都可以访问,获取课程和视频的基本信息
|
|||
|
|
2. 课程视频播放凭证接口 - 需要权限验证,根据用户会员级别控制播放权限
|
|||
|
|
|
|||
|
|
## 权限等级说明
|
|||
|
|
|
|||
|
|
系统中的用户权限等级:
|
|||
|
|
- **0 - 游客**: 未登录用户或普通游客
|
|||
|
|
- **1 - 普通用户**: 已注册的普通用户
|
|||
|
|
- **2 - VIP用户**: VIP会员用户
|
|||
|
|
- **3 - SVIP用户**: SVIP会员用户
|
|||
|
|
|
|||
|
|
课程的访问权限规则:
|
|||
|
|
- 免费课程(level=0):所有用户都可以观看
|
|||
|
|
- 普通课程(level=1):普通用户及以上可以观看
|
|||
|
|
- VIP课程(level=2):VIP用户及以上可以观看
|
|||
|
|
- SVIP课程(level=3):仅SVIP用户可以观看
|
|||
|
|
|
|||
|
|
## 接口详情
|
|||
|
|
|
|||
|
|
### 1. 获取课程视频详情
|
|||
|
|
|
|||
|
|
**接口路径**: `GET /user/course/{courseId}/video-detail`
|
|||
|
|
|
|||
|
|
**接口描述**: 获取课程的视频详情信息,包含章节和视频列表。所有用户都可以访问此接口,但会根据用户权限显示不同的播放权限信息。
|
|||
|
|
|
|||
|
|
**路径参数**:
|
|||
|
|
- `courseId`: 课程ID(必需)
|
|||
|
|
|
|||
|
|
**请求头**:
|
|||
|
|
- `Authorization`: Bearer token(可选,未登录用户也可以访问)
|
|||
|
|
|
|||
|
|
**响应示例**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "success",
|
|||
|
|
"data": {
|
|||
|
|
"course": {
|
|||
|
|
"id": 1,
|
|||
|
|
"title": "AI图像处理入门课程",
|
|||
|
|
"description": "学习AI图像处理的基础知识和实践技巧",
|
|||
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|||
|
|
"price": 29.99,
|
|||
|
|
"level": 2,
|
|||
|
|
"category": "人工智能",
|
|||
|
|
"isFree": false,
|
|||
|
|
"levelName": "VIP用户",
|
|||
|
|
"createTime": "2024-01-15T10:30:00",
|
|||
|
|
"updateTime": "2024-01-15T10:30:00",
|
|||
|
|
"creator": {
|
|||
|
|
"id": "1",
|
|||
|
|
"username": "teacher01",
|
|||
|
|
"avatarUrl": "https://example.com/avatar.jpg"
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
"chapters": [
|
|||
|
|
{
|
|||
|
|
"id": 1,
|
|||
|
|
"title": "第一章:基础概念",
|
|||
|
|
"description": "介绍AI图像处理的基础概念",
|
|||
|
|
"orderNum": 1,
|
|||
|
|
"videos": [
|
|||
|
|
{
|
|||
|
|
"id": 1,
|
|||
|
|
"chapterId": 1,
|
|||
|
|
"title": "1.1 什么是AI图像处理",
|
|||
|
|
"vodVideoId": "abc123def456",
|
|||
|
|
"durationSec": 1800,
|
|||
|
|
"durationFormatted": "30:00",
|
|||
|
|
"orderNum": 1,
|
|||
|
|
"canPlay": false,
|
|||
|
|
"lockReason": "需要VIP用户及以上权限"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"userPermission": {
|
|||
|
|
"userRole": 1,
|
|||
|
|
"userRoleName": "普通用户",
|
|||
|
|
"requiredLevel": 2,
|
|||
|
|
"requiredLevelName": "VIP用户",
|
|||
|
|
"hasAccess": false,
|
|||
|
|
"accessDeniedReason": "您当前是普通用户用户,该课程需要VIP用户及以上权限",
|
|||
|
|
"membershipExpiresAt": null
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**未登录用户响应示例**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "success",
|
|||
|
|
"data": {
|
|||
|
|
"course": { /* 课程信息 */ },
|
|||
|
|
"chapters": [ /* 章节列表,所有视频的canPlay都为false */ ],
|
|||
|
|
"userPermission": {
|
|||
|
|
"userRole": 0,
|
|||
|
|
"userRoleName": "游客",
|
|||
|
|
"requiredLevel": 2,
|
|||
|
|
"requiredLevelName": "VIP用户",
|
|||
|
|
"hasAccess": false,
|
|||
|
|
"accessDeniedReason": "请先登录,该课程需要VIP用户及以上权限",
|
|||
|
|
"membershipExpiresAt": null
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 获取课程视频播放凭证
|
|||
|
|
|
|||
|
|
**接口路径**: `POST /user/course/{courseId}/video/{videoId}/play-auth`
|
|||
|
|
|
|||
|
|
**接口描述**: 根据用户权限获取课程视频的播放凭证。需要用户登录和权限验证,只有满足课程要求权限级别的用户才能获取播放凭证。
|
|||
|
|
|
|||
|
|
**路径参数**:
|
|||
|
|
- `courseId`: 课程ID(必需)
|
|||
|
|
- `videoId`: 视频ID(必需)
|
|||
|
|
|
|||
|
|
**请求头**:
|
|||
|
|
- `Authorization`: Bearer token(必需)
|
|||
|
|
|
|||
|
|
**请求体**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"chapterId": 1,
|
|||
|
|
"authInfoTimeout": 3600
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**请求参数说明**:
|
|||
|
|
- `chapterId`: 章节ID(必需)
|
|||
|
|
- `authInfoTimeout`: 播放凭证过期时间(秒),默认3600秒
|
|||
|
|
|
|||
|
|
**成功响应示例**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "success",
|
|||
|
|
"data": {
|
|||
|
|
"playAuth": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|||
|
|
"requestId": "req-123456789",
|
|||
|
|
"videoMeta": {
|
|||
|
|
"vodVideoId": "abc123def456",
|
|||
|
|
"title": "1.1 什么是AI图像处理",
|
|||
|
|
"duration": 1800.0,
|
|||
|
|
"coverURL": "https://example.com/video-cover.jpg",
|
|||
|
|
"status": "Normal",
|
|||
|
|
"size": 104857600
|
|||
|
|
},
|
|||
|
|
"userPermission": {
|
|||
|
|
"userRole": 2,
|
|||
|
|
"userRoleName": "VIP用户",
|
|||
|
|
"requiredLevel": 2,
|
|||
|
|
"hasPermission": true,
|
|||
|
|
"checkTime": "2024-01-15T10:30:00"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**权限不足响应示例**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 403,
|
|||
|
|
"msg": "权限不足:您当前是普通用户用户,该课程需要VIP用户及以上权限",
|
|||
|
|
"data": null
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**未登录响应示例**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 401,
|
|||
|
|
"msg": "请先登录",
|
|||
|
|
"data": null
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 业务逻辑说明
|
|||
|
|
|
|||
|
|
### 课程视频详情接口逻辑
|
|||
|
|
|
|||
|
|
1. **无权限验证**: 所有用户(包括未登录用户)都可以访问此接口
|
|||
|
|
2. **基础信息展示**: 显示课程的基本信息、章节结构和视频列表
|
|||
|
|
3. **权限状态指示**: 根据用户当前权限级别,标识每个视频是否可播放
|
|||
|
|
4. **友好提示**: 对于无权限播放的视频,提供明确的权限要求说明
|
|||
|
|
|
|||
|
|
### 播放凭证接口逻辑
|
|||
|
|
|
|||
|
|
1. **登录验证**: 必须是已登录用户才能访问
|
|||
|
|
2. **权限验证**: 验证用户的会员级别是否满足课程要求
|
|||
|
|
3. **章节视频验证**: 验证视频与章节的关联关系
|
|||
|
|
4. **播放凭证生成**: 调用阿里云VOD服务生成播放凭证
|
|||
|
|
5. **权限记录**: 记录用户的权限验证信息
|
|||
|
|
|
|||
|
|
### 权限验证规则
|
|||
|
|
|
|||
|
|
- 游客(level=0):只能观看免费课程
|
|||
|
|
- 普通用户(level=1):可以观看免费课程和普通课程
|
|||
|
|
- VIP用户(level=2):可以观看免费、普通和VIP课程
|
|||
|
|
- SVIP用户(level=3):可以观看所有课程
|
|||
|
|
|
|||
|
|
## 错误码说明
|
|||
|
|
|
|||
|
|
| 错误码 | 说明 |
|
|||
|
|
|--------|------|
|
|||
|
|
| 200 | 成功 |
|
|||
|
|
| 400 | 请求参数错误或课程不存在 |
|
|||
|
|
| 401 | 未登录 |
|
|||
|
|
| 403 | 权限不足 |
|
|||
|
|
| 500 | 服务器内部错误 |
|
|||
|
|
|
|||
|
|
## 使用建议
|
|||
|
|
|
|||
|
|
1. **前端实现**: 建议先调用视频详情接口获取课程信息和用户权限状态,再根据权限决定是否显示播放按钮
|
|||
|
|
2. **用户体验**: 对于权限不足的用户,可以显示升级提示或购买链接
|
|||
|
|
3. **缓存策略**: 课程详情信息可以适当缓存,但播放凭证应该实时获取
|
|||
|
|
4. **错误处理**: 播放凭证获取失败时,应该给用户友好的错误提示
|
|||
|
|
|
|||
|
|
## 数据库变更
|
|||
|
|
|
|||
|
|
为了支持这些接口,在 `CourseVideoMapper` 中新增了 `selectById` 方法:
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<select id="selectById" resultMap="CourseVideoResultMap">
|
|||
|
|
SELECT id, chapter_id, title, video_id, duration_sec, order_num, create_time, update_time, is_deleted
|
|||
|
|
FROM course_video
|
|||
|
|
WHERE id = #{id} AND is_deleted = 0
|
|||
|
|
</select>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 新增文件
|
|||
|
|
|
|||
|
|
1. `CourseVideoDetailDto.java` - 课程视频详情响应DTO
|
|||
|
|
2. `CourseVideoPlayDto.java` - 播放凭证相关DTO
|
|||
|
|
3. `docs/course-video-api.md` - 本API文档
|
|||
|
|
|
|||
|
|
## 修改文件
|
|||
|
|
|
|||
|
|
1. `CourseController.java` - 新增两个接口端点
|
|||
|
|
2. `CourseService.java` - 新增两个服务方法接口
|
|||
|
|
3. `CourseServiceImpl.java` - 实现两个服务方法
|
|||
|
|
4. `CourseVideoMapper.java` - 新增selectById方法
|
|||
|
|
5. `CourseVideoMapper.xml` - 新增selectById查询SQL
|