前言

领课教育(roncoo-education)是一套基于 Spring Cloud 微服务架构的分布式在线教育开源系统。本文聚焦其核心模块——课程功能,从数据模型、业务流程到前后端实现,做一次完整的拆解,帮助开发者快速理解系统设计思路,也为二次开发提供参考。


一、整体架构

课程功能涉及三端协作:

  • 管理后台(Vue 3 + Element Plus):课程创建、章节管理、资源上传、数据统计
  • 用户门户(Nuxt 3 SSR):课程浏览、购买、在线学习
  • 后端服务(Spring Boot 3.5 / Spring Cloud 微服务):roncoo-education-service-course 独立服务,通过 Feign 与用户服务、系统服务交互

接口按访问权限分为三层:

前缀 说明
/course/admin/... 管理后台专用,需管理员 Token
/course/api/... 公开接口,无需登录
/course/auth/... 用户接口,需用户登录 Token

二、数据模型设计

课程功能的核心数据模型呈层级结构:课程 → 章节 → 课时 → 资源

2.1 课程(Course)

课程是最顶层的实体,主要字段包括:

courseName     课程名称
courseLogo     封面图
lecturerId     讲师ID(跨服务,通过 Feign 获取讲师详情)
categoryId     分类ID
isFree         是否免费
rulingPrice    划线价(原价)
coursePrice    售价
isPutaway      是否上架
countBuy       购买人数
countStudy     学习人数
speedDouble    是否允许倍速播放
speedDrag      是否允许拖动进度条
introduce      课程介绍(富文本 HTML)

值得注意的是 speedDoublespeedDrag 两个字段——倍速和拖动的权限控制直接在课程级别配置,会透传给前端播放器,这是防止用户"快进刷课"的常见手段。

2.2 章节与课时

章节(CourseChapter)和课时(CourseChapterPeriod)各自都有 isFree 字段,形成三级试看控制:

课程级别:isFree = 1  →  整门课免费
章节级别:isFree = 1  →  该章节下所有课时可试看
课时级别:isFree = 1  →  单独该课时可试看

课时还有 periodType 字段区分点播资源(=10)和直播(=20),同一套结构同时支持录播和直播课程。

2.3 资源(Resource)

资源独立管理,与课时通过 resourceId 关联,支持四种类型:

  • 视频(resourceType=1)
  • 音频(resourceType=2)
  • 文档(resourceType=3,PDF 等)
  • 图片(resourceType=4)

视频资源有单独的 videoStatus 字段记录转码状态(转码中 / 成功 / 失败),转码完成前课时无法学习。

2.4 学习记录(UserStudy)

每个用户对每个课时都有一条 UserStudy 记录:

courseId / chapterId / periodId   精确定位到课时
currentDuration                   当前播放时长(秒,音视频)
currentPage                       当前页码(文档)
progress                          完成百分比(0-100)

这条记录是断点续播、进度条展示的核心依据。


三、核心业务流程

3.1 课程发布流程

管理员在后台按以下步骤操作:

① 创建课程基本信息(名称、封面、价格、讲师、分类)
② 添加章节(可排序、可单独设免费)
③ 章节下添加课时(绑定资源或直播)
④ 上传视频等待转码完成
⑤ 设置上架(isPutaway = 1)

管理后台的课程列表支持拖拽排序,底层通过 courseSort 接口批量更新 sort 字段实现。

3.2 购买流程

用户查看课程详情
  └── 未登录 → 弹窗引导登录(保存当前页URL,登录后跳回)
  └── 已登录
        ├── 免费课程 → 直接进入学习
        └── 付费课程 → 调用 /user/auth/order/pay/create 创建订单
                         └── 支付宝 / 微信支付
                               └── 回调写入 UserCourse 记录

免费课程的 UserCourse 记录不在浏览详情时创建,而是在用户第一次点击学习、调用 sign 接口时才写入,buyType 标记为 FREE。这样只有真正发生学习行为的用户才会产生记录,避免浏览未学习的用户污染数据。

3.3 学习鉴权(sign 接口核心逻辑)

这是整个课程功能中最关键的接口,位于 AuthCourseBiz.sign()

// 购买权限校验优先级
① 已购买(UserCourse 存在)         → 允许
② 课程标记免费(isFree=FREE)       → 自动创建 UserCourse,允许
③ 章节标记免费(isFree=FREE)       → 允许试看
④ 课时标记免费(isFree=FREE)       → 允许试看
⑤ 以上均不满足                      → 返回"请购买该课程"

通过鉴权后,根据资源类型返回不同的播放配置:

  • 音视频:调用保利威(Polyv)或领课云 API 生成带签名的播放 Token(VodPlayConfig),有效期有限,防止 URL 泄露后被直接下载
  • 文档/图片:生成 OSS/MinIO 的预签名预览 URL,有效期 300 秒
  • 直播:调用直播平台 API 获取直播观看地址,并校验直播状态(未开始 / 直播中 / 回放可用)

3.4 学习进度上报

前端采用轮询 + 事件触发双机制上报进度:

// 播放开始后,每 3 秒上报一次
progressInterval = setInterval(() => {
  handleStudyRecordForVod(1)  // studyStatus=1 学习中
}, 3000)

// 暂停时立即上报
polyvPlayerClient.on('s2j_onVideoPause', () => {
  handleStudyRecordForVod(2)  // studyStatus=2 暂停
})

// 播放完成时上报
polyvPlayerClient.on('s2j_onPlayOver', () => {
  handleStudyRecordForVod(1)
  showing.value = false  // 显示"下一节"引导
})

上报数据包含 currentDuration(当前播放秒数),后端据此计算 progress 百分比并更新 UserStudy 记录。


四、前端实现亮点

4.1 课程详情页(SSR 渲染)

用户门户基于 Nuxt 3 服务端渲染,课程详情页使用 useAsyncData 在服务端获取数据:

const { data: courseInfo } = await useAsyncData('course-detail' + id, async () => {
  if (getToken()) {
    // 已登录:获取含购买状态的详情
    return courseApi.userCourseDetail({ courseId: id })
  } else {
    // 未登录:获取公开详情
    return courseApi.courseDetail({ courseId: id })
  }
})

同一个页面,根据登录状态走两个接口——未登录走公开接口有利于 SEO,登录后的接口会额外返回 allowStudy(是否可直接学习)和 courseCollect(是否已收藏)。

4.2 学习页布局

学习页采用沉浸式全屏布局,左侧播放器占满主区域,右侧侧边栏可切换课程目录评论,侧边栏点击同一 tab 时收起,保证观看区域最大化。

章节目录中每个课时都有进度条展示,periodProgress > 99 时显示绿色完成状态,方便用户快速定位未完成的课时。

4.3 权限按钮控制

管理后台通过自定义指令 v-permission 控制按钮级权限:

<el-button v-permission="'course:save'" type="primary">添加课程</el-button>
<el-button v-permission="'course:edit'" text>编辑</el-button>
<el-button v-permission="'course:delete'" text>删除</el-button>

权限码由后端菜单树下发,前端根据用户角色动态控制按钮可见性。


五、扩展性设计

几个值得关注的扩展性设计:

多视频平台支持Resource.vodPlatform 字段区分视频平台(1=领课云,2=保利威),播放配置通过策略模式封装在 VodUtil.getPlayConfig() 中,新增平台只需扩展枚举和对应实现。开源版支持领课云和保利威,商业版进一步扩展支持阿里云点播、腾讯云点播、获得场景、百家云,可根据业务需求灵活选型。

多存储平台支持Resource.storagePlatform 区分存储平台,通过 Map<String, UploadFace> 注入不同实现,预览 URL 生成逻辑对上层透明。开源版支持阿里云 OSS 和 MinIO,商业版额外支持腾讯云对象存储、华为云、七牛云,基本覆盖国内主流存储服务。

直播回放无缝衔接:直播结束后,Live.resourceId 指向回放视频资源,sign 接口检测到 liveStatus = COMPLETION 时自动切换到资源播放逻辑,录播和直播在学习流程上完全统一。商业版在此基础上支持更完整的直播功能,包括多直播平台接入、直播互动等场景。

在线考试商业版还支持考试功能,可在课程学习后配置考试,形成"学习 → 考试 → 结业"的完整闭环,适合对学习效果有考核要求的企业培训、职业教育等场景。


总结

领课教育的课程功能设计清晰,三级免费控制按需写入学习记录播放 Token 防盗链断点续播等细节处理都体现了实际在线教育场景下的工程经验。整体代码结构分层明确(Controller → Biz → Dao),适合作为学习微服务架构和在线教育业务建模的参考项目。

如果你也在做类似的教育类产品,可以直接参考其中的鉴权流程和进度上报机制,这两块是最容易踩坑的地方,领课的实现相对成熟。

开源版覆盖了录播、直播的核心流程,如果需要对接更多视频云平台(阿里云点播、腾讯云点播、获得场景、百家云)、更多存储平台(腾讯云对象存储、华为云、七牛云)、完整的直播互动能力,或者在线考试功能,可以了解领课教育商业版,在开源版基础上提供了更完整的功能支持和商业级服务保障。


源码地址

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐