这些年在毕业设计圈子里,SpringBoot + Vue + MySQL 的组合几乎成了“标准答案”。我见过太多同学拿着类似的题目,一开始雄心勃勃,结果卡在环境配置、权限设计、前后端联调这些环节上,最后熬夜赶工。其实这类项目本身不复杂,难的是你对整个系统没有一个全局的把控,不知道每一步为什么要这么做。这篇文章我结合自己做过的在线课程管理系统,把从数据库设计到前后端实现、再到论文和部署文档准备的完整链路拆开揉碎了讲一遍。不管你拿到的题目是课程管理、教学平台还是学习系统,核心思路都是通的,照着这个框架走,能少踩很多坑。
1. 项目整体拆解与技术选型思路
1.1 技术栈选型背后的逻辑
选 SpringBoot + Vue + MySQL 这套组合,不是因为它最潮流,而是因为它是最稳妥、最经得起答辩追问的搭配。先看后端,SpringBoot 极大简化了 Spring 生态的配置过程,你不需要再去手写一堆 XML 配置文件,一个注解就能把 Controller、Service、Mapper 串起来。这一点对学生党特别友好,因为毕业设计的时间窗口就那么几个月,你不可能把所有精力都耗在环境搭建上。
再看前端,Vue 的响应式数据绑定和组件化开发模式,天然适合这种管理后台加用户端混合的系统。你用 Vue 写课程列表页、购物车式的选课逻辑、后台的表格管理,代码组织起来非常清晰。更重要的是,Vue 的生态足够成熟,Element UI 一挂,那些复杂的表格、表单、弹窗、分页组件直接拿来用,视觉上也不会显得廉价。
MySQL 更不用多说,关系型数据库在课程管理这种场景下依然是最优解。课程、用户、选课记录、章节内容、作业提交,这些实体之间天然存在一对多、多对多的关系,用外键和中间表就能表达清楚。面试官或者答辩老师问起来,你也能讲明白为什么不用 MongoDB——因为这里需要事务支持,选课和扣减课程名额必须保证原子性。
1.2 功能模块与角色权限的设计思路
在线课程管理系统最核心的难点不在 CRUD,而在权限控制。你至少要拆出三种角色:管理员、教师、学生。管理员负责用户管理、课程审核、数据统计;教师可以创建课程、上传章节、发布作业、批改打分;学生可以浏览课程、选课退课、观看章节、提交作业。
很多人的项目死就死在“所有角色共用一套接口,靠前端按钮隐藏来控制权限”。这是大忌。后端接口必须做角色校验,比如教师创建课程的接口,如果学生角色能直接调通,答辩时基本就凉了。我建议用 Spring Security 或者 Sa-Token 这类框架,把权限注解加到 Controller 方法上,比如@PreAuthorize("hasRole('TEACHER')"),这样前端就算把按钮显示出来,后端也会拦截。
数据库层面需要设计用户表、角色表,或者用简单的字段区分角色也行,看你的表结构习惯。我这里用的是role字段直接区分,简单直接,对于毕业设计来说完全够用,也不必为了追求“规范”强行搞五张表的 RBAC。
2. 数据库设计与核心表结构
2.1 表结构怎么设计才能不返工
数据库设计是这个项目的基石,表结构没想清楚,后面写代码就是反复推翻重来。我强烈建议你先用思维导图或者手写草稿的形式,把实体关系梳理一遍,再落到 Navicat 或者命令行去建表。核心表大概有这么几张:
user:用户表,字段包括id, username, password, real_name, role, avatar, email, create_timecourse:课程表,id, title, cover, description, teacher_id, category, status, student_count, created_atcourse_section:课程章节表,id, course_id, section_name, video_url, duration, sort_orderstudent_course:选课关系表,id, student_id, course_id, selected_time, statushomework:作业表,id, course_id, title, content, deadlinehomework_submit:作业提交表,id, homework_id, student_id, submit_content, file_url, score, submit_timecomment:课程评论表,id, course_id, user_id, content, create_time
这条设计路径里,最容易搞错的是student_course和homework_submit这种中间表,它们解决的其实都是“多对多”关系的存储问题。选课关系如果不单独建表,学生选了一门课之后,你连“这门课有哪些学生”都查不出来。
2.2 关键字段设计的经验之谈
密码字段必须加密存储,用 BCrypt,不能明文存。这个点不仅是为了安全,也是为了答辩时老师问起来你能接住话。BCrypt 每次生成的哈希都不一样,但校验能通过,原因是它内部把随机盐混进了哈希结果里,这一点你在论文里写清楚,是个加分项。
课程表里的status字段建议用0/1表示下架和上架,而不是直接删除记录。原因很简单,课程创建后可能关联了学生选课记录、章节、作业提交,物理删掉会引发一连串的孤儿数据。逻辑删除能保底,以后想恢复数据也容易。
还有一个细节是sort_order字段。课程章节的顺序如果靠创建时间排序,一旦你中间插入一个新章节,顺序就乱了。加一个排序号字段,查询时ORDER BY sort_order,需求变更时改数字就行,这是个很小但很实用的小技巧。
3. 后端核心功能实现
3.1 登录鉴权与 JWT 落地方案
登录鉴权我首选 JWT,无状态、跨域友好、部署简单。流程是这样的:用户提交用户名密码,后端校验通过后生成一个 token 返回给前端。前端拿到 token 存在 localStorage 里,每次请求在请求头带上Authorization: Bearer <token>,后端拦截器解析 token,拿到用户 ID 和角色信息,放到 ThreadLocal 或请求上下文里,后续逻辑直接用。
这里有一个非常容易踩的坑:拦截器里放行哪些路径要想清楚。登录接口、注册接口、课程列表这些基础信息接口应该放行,但选课、发布作业、修改密码这类操作必须拦截。我的做法是写一个WebMvcConfigurer,注册一个HandlerInterceptor,用白名单加黑名单的方式管理放行路径。
生成 token 时需要设置过期时间,建议 12 到 24 小时。过期时间设太短,用户用着用着就被踢下线,体验很差;设太长,安全性又有隐患。24 小时是一个比较平衡的选择,而且你在论文里也容易解释这个决策理由。
3.2 课程管理、选课与视频章节的实现要点
课程管理的核心接口无外乎增删改查加分页,但这些逻辑里藏着不少细节。分页查询我用的是 MyBatis-Plus 的Page对象,配合IPage<T>返回值,一页十条数据,前端传current和size两个参数就行。需要注意的一点是,课程列表查询经常要带上教师名字,而教师名字在用户表里,这时要么写一个 VO 对象接收连表查询结果,要么用@TableField(exist = false)标注一个非表字段,避免 ORM 映射报错。
选课逻辑务必加上事务控制,用@Transactional注解。为什么?因为选课这个动作至少包含两步操作:往student_course表插入一条记录,同时把course表的student_count加一。如果第一步成功、第二步失败,数据就不一致了。事务能保证这两步要么都成功、要么都回滚。
视频章节的上传和播放也有说头。视频文件不能直接存数据库,存的是服务器上的路径或者对象存储的 URL。上传文件用 MultipartFile 接收,校验文件类型和大小,把文件写到本地磁盘的某个目录,再把路径存到数据库。播放的话前端用<video>标签直接塞 src 就行,如果担心大视频加载慢,可以研究下切片或者懒加载,但那是加分项,不是必选项。
4. 前端 Vue 实现与交互细节
4.1 前端项目结构怎么组织才不乱
Vue 项目如果全部堆在一个views目录下,后期代码会非常痛苦。我习惯按模块去划分结构:views/admin、views/teacher、views/student三个大目录,分别放后台管理、教师端、学生端的页面;router目录配置路由;store目录放 Vuex 或者 Pinia 的状态管理;api目录按后端接口模块拆文件,比如course.js、user.js、homework.js。
路由守卫是前端的权限第一道门槛。我写了全局前置守卫:判断 localStorage 里有没有 token,没有就跳登录页;有 token 再看路由 meta 里要求的角色,如果用户角色不符就跳 403 页面。这样虽然后端已经做了接口校验,但前端先拦住一层,用户体验好很多,也不会看到一堆报错。
Axios 统一封装是必须做的一件事。拦截器里统一把 token 加到请求头,统一处理 401 时跳转登录页,统一处理错误提示信息。否则你每个页面都写一次错误处理逻辑,代码重复率极高。封装完之后,业务代码里只需要写请求、then里处理结果,清爽很多。
4.2 表格、表单、上传这些高频场景怎么处理
后台管理页面的核心就是表格加表单弹窗。Element UI 的el-table绑定数据源、列配置一下就出来,配合el-pagination做分页,注意把current-page和page-size跟后端的参数名保持一致,避免序列化时对不上。
课程创建和编辑的表单会有很多字段,封面图上传、课程简介、教师选择等。我建议表单校验规则一定要写完整,比如课程名必填、简介最大长度限制。前端校验能挡住一部分无效请求,减少后端压力,也避免用户一脸懵地看到 500 错误页面。
还有一个很多人忽视的点:按钮级权限控制。不同角色看到的操作按钮应该不一样,比如学生端只能点选课,教师端才能看到“编辑课程”“发布作业”这些按钮。这个不需要 Vue 指令,直接在模板里用v-if="role === 'teacher'"判断就行。
视频上传功能我用的是 Element UI 的el-upload组件,注意它的 action 属性指向后端的上传接口,:on-success回调里拿到后端返回的文件 URL,然后赋值给表单的videoUrl字段。还有一个细节是上传时要带上请求头 token,否则会被后端拦截器挡住。
5. 论文撰写与部署文档
5.1 论文结构怎么组织才能轻松过审
论文的核心不是长篇大论的功能介绍,而是把“需求分析 - 系统设计 - 系统实现 - 系统测试”这条逻辑主线讲清楚。很多同学喜欢把大段代码截图贴进论文,这是大忌。论文里只需要放关键代码片段,并且一定要配文字解释为什么这么写。
需求分析章节建议画用例图描述三种角色的操作流程,这个图用 PlantUML 或者 ProcessOn 画都行。系统设计章节包含总体架构图、功能模块图、数据库 E-R 图和核心表结构说明。系统实现章节按功能模块逐个展开,每个模块介绍页面样式、核心方法、关键逻辑。系统测试章节要有测试用例表格,覆盖正常流程和异常流程,比如密码错误登录、未登录访问课程详情等场景。
数据库设计部分用表格列出每张表的字段名、类型、约束、说明,比直接粘贴建表 SQL 显得更规范,老师看着也更轻松。
5.2 部署文档和答辩准备
部署文档一定要按步骤写清楚,方便老师按着文档在自己电脑上把系统跑起来。标准方案是本地运行:后端打 jar 包,前端npm run build生成 dist 静态文件,可以用 Nginx 托管,也可以直接把前端文件放到 SpringBoot 的static目录下实现单机运行。
这里有个便捷做法,很适合答辩演示场景:把前端 build 出来的文件复制到后端src/main/resources/static目录下,重新打包,启动一个 SpringBoot 应用,浏览器访问 8080 端口就能看到整个系统。这样就不用额外启 Nginx 或者前端开发服务器,部署门槛一下子就低了,老师在自己的电脑上也能很快跑起来。
答辩之前务必自己完整走一遍业务流程,从注册、登录、创建课程、上传章节、选课、提交作业到批改打分,全程演示。提前准备好一个演示账号,里面放上造好的数据,别到现场才现发现没视频、没学生、没作业。
6. 常见问题与排查技巧
6.1 前端请求报 404 和 401
404 大概率是接口路径写错了。前后端分离开发时,接口路径要约定好,建议后端统一加/api前缀,前端 Axios 的 baseURL 也对应配置成/api,这样代理配置和后期部署都好处理。
401 则是 token 问题,要么登录成功后没有存 token,要么请求时没有在拦截器里加请求头。排查思路很直接:打开浏览器开发者工具的 Network 面板,看请求头里有没有 Authorization 字段。没有就是前端问题,有但还 401,那就是 token 过期或者解析失败。
后端解析 token 失败还有一个隐蔽原因:JWT 依赖的jjwt库版本对应的 API 变化比较大,网上教程代码可能跑不通。这时候直接看官方示例,别在老旧博客里找依赖,节省时间。
6.2 数据库连接报错和中文乱码
数据库连不上的原因无外乎三种:一是 MySQL 没启动,二是账号密码或数据库名不对,三是驱动版本不匹配。SpringBoot 2.x 对应 MySQL 8.x 的驱动是com.mysql.cj.jdbc.Driver,这个是容易踩坑的点。此外要记得在连接串后面加useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai,不然中文写进数据库全是问号,时间字段的显示也会差八个小时。
时区问题的坑我印象太深了,第一次用 MySQL 8 的时候,跑出来的时间比实际时间少了八小时,找了半天原因,就是没配置 serverTimezone。这个参数是必加的,别省。
6.3 耗时问题的排查思路
如果页面响应很慢,先在后端 Controller 入口打印日志,看时间消耗在哪个环节。常见原因是数据库查询没有加索引,比如student_course表经常用student_id去查选课列表,就要在student_id字段上加索引。还有一种是 N+1 查询问题,循环查数据库,这个在连表查询或者用 MyBatis-Plus 的selectBatchIds一次性查出所有关联数据可以解决。
7. 写在最后的经验之谈
做完整个在线课程管理系统,我最深的体会是:这个题目的工作量不在“写代码”本身,而在于把每个环节的决策想清楚。你用什么做鉴权、为什么这么设计表、选课为什么要加事务、前端权限怎么控制、部署怎么简化——这些问题的答案,既是你写论文的素材,也是答辩时的底气。我强烈建议你不要只满足于把功能跑通,而是每个技术点都多问自己一句“为什么”。以这套技术栈为基础,你还能继续扩展在线考试、支付购课、直播教学这些模块,接上 Redis 做缓存、OSS 存视频,项目深度就能更上一层楼。先把基础版本彻底吃透,再往外延伸,这就是最稳的前进路线。