做课程设计那会儿,我翻遍了各种项目选题,最后敲定了“基于Spring Boot的在线教育平台”——这个题目在当年算热门,放到现在依然是课设和毕设里的常青树。为啥?因为它的技术栈足够主流,业务场景贴近真实互联网产品,而且数据模型、权限控制、文件上传、订单支付这些模块,每一个都能单独拿出来讲出东西来。更关键的是,Spring Boot面试问得多,简历上写一笔加很多分。
这篇文章我就以自己完整做过的这套在线教育平台为例,把从选题拆解、数据库设计、核心代码实现,到文档撰写和答辩避坑的全部过程,尽量用大白话讲清楚。不管你是刚开始动手,还是已经写完卡在Bug里,这篇都能给你一个能直接照做的路线。
1. 项目整体设计与技术选型
1.1 技术栈为什么是这套组合
很多人在开题时会陷入一个误区,觉得技术越新越好、中间件越多越好。实际上课程设计和毕业设计的评分重点,从来不是“你用没用过生僻技术”,而是“你这个系统逻辑是否完整、工程是否规范、答辩能否自圆其说”。
我选的这套技术栈,核心组合是:
- 后端:Spring Boot 2.x
- ORM框架:MyBatis-Plus(也可以原生MyBatis,但课设阶段用Plus效率高一截)
- 数据库:MySQL 8.x
- 缓存与Token校验:Redis(可选,但用了加分)
- 权限方案:Spring Security + JWT(或简化版拦截器 + JWT)
- 前端:Vue 2 / Element UI(如果主攻后端,也可以用Thymeleaf模板引擎完成基础页面)
为什么不是Spring Cloud微服务?原因很实际:在线教育平台虽然业务看起来多,但作为课设,单体应用完全够用。刻意引入微服务会让项目复杂度暴涨,Eureka、Gateway、Feign这些组件排查起来非常耗时间。我见过好几个同学在毕设里上了微服务,最后答辩时自己的代码都已经看不懂了,纯属给自己挖坑。
为什么选MyBatis-Plus而不是JPA?因为在中国技术社区里,MyBatis系的使用率更高,面试聊起来更容易对上话。Plus的好处是单表CRUD不用写SQL,但复杂的多表联查你还是要会手写。这个度正好适合课设。
Spring Boot 2.x和3.x选哪个?我建议选择2.7.x。3.x虽然已经出了很久,但部分依赖和文档还处在过渡期,课设阶段没必要冒这个兼容性的风险。后期如果有需要,升级也不是难事。
1.2 项目目录结构与分层思路
很多课设项目代码写得像一锅粥,Controller里塞SQL,工具类散落各处,这种代码就算功能全跑通,答辩老师打开工程目录也会皱眉。我的习惯是严格按照分层架构来组织代码:
code复制com.example.eduplatform
├── controller // 接收请求,处理参数
├── service // 业务逻辑层
│ └── impl
├── mapper // 数据访问层
├── entity // 数据库实体
├── dto // 数据传输对象(用于接口参数校验)
├── vo // 视图对象(用于返回给前端)
├── config // 配置类(跨域、拦截器、Redis配置等)
├── utils // 工具类(JWT工具、文件上传工具等)
├── common // 通用返回结果、异常处理、常量
└── EduApplication.java
先说一个最重要的原则:Controller层永远只做参数接收和结果封装,业务逻辑全放Service层。比如用户注册时,需要校验用户名唯一性、密码加密、初始化角色,这些逻辑如果写在Controller里,后期一旦需要被其他接口复用,你只能复制粘贴,然后就越改越乱。
Service接口和Impl分开写,这在课设里看似多余,但老师普遍吃这一套,因为这是最标准的Spring工程结构。等你去实习了会发现,公司项目清一色接口加实现类的组织方式,学校养成这个习惯受益很久。
DTO和VO也要有意识地区分。DTO是前端传给你的参数,VO是你返回给前端的数据。拿用户模块举例:前端注册时传的是RegisterDTO(用户名、密码、确认密码),而你返回给前端的是UserVO(脱敏后的用户信息),不是直接把数据库实体丢回去。这样做的好处有两个:一是防止密码等敏感字段泄露到前端网络请求里;二是让接口语义清晰,不怕前端拿到多余字段来推断你的表结构。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心细节解析与实操要点
2.1 数据库表设计与关系
在线教育平台的核心业务其实不复杂,但表设计要照顾到“课时购买”和“在线学习”这两个关键场景。我最终落地的数据库一共12张表,核心表如下:
| 表名 | 用途 | 关键字段 |
|---|---|---|
| user | 用户表(学生/教师/管理员三合一) | id, username, password, role, avatar, status |
| category | 课程分类表 | id, name, parent_id, sort |
| course | 课程表 | id, teacher_id, category_id, title, cover, price, status, sale_count |
| chapter | 章节表 | id, course_id, title, sort |
| lesson | 课时表(视频信息存在这里) | id, chapter_id, title, video_url, duration, is_free |
| cart_item | 购物车表 | id, user_id, course_id, add_time |
| orders | 订单表 | id, order_no, user_id, total_price, status, pay_time |
| order_item | 订单明细表 | id, order_id, course_id, course_title, price |
| user_course | 已购课程表(学习资格表) | id, user_id, course_id, create_time |
| learn_record | 学习记录表 | id, user_id, lesson_id, last_time, progress |
| comment | 课程评论表 | id, course_id, user_id, content, create_time |
| banner | 首页轮播图表(可选,用于充实功能) | id, image, course_id, sort |
这个表设计是基于很多次修改后确定的。说说几个关键取舍:
第一,用户表用一个角色字段区分三类身份,而不是建三张表。在线教育平台的学生、教师、管理员虽然功能不同,但基础属性完全一样——用户名、密码、头像、手机号。硬拆成三张表会带来大量冗余字段,而且后续做登录认证时逻辑会绕弯子。用一个role字段,取值STUDENT、TEACHER、ADMIN,登录后根据角色路由到不同菜单即可。
第二,课时表里is_free字段很重要。做课设时可以用它实现“试看”功能:未购买的用户只能看免费课时,购买后放开所有课时。这个设计虽然只是多了一个字段,但它体现的是你对在线教育业务的理解,答辩时能主动讲出来,会加分不少。
第三,订单表和订单明细表一定要分开。因为一个订单可能包含多门课程(购物车合并下单),如果不拆明细表,订单表的字段会非常尴尬。而且订单明细里的course_title和price是冗余存储,你应该在生成订单时就把课程名称、价格快照存进去,免得以后课程改价导致历史订单对不上账。
第四,learn_record表是很多课设缺失的。我建议一定要加上,因为它让系统摇身一变具备了“学习进度记录”功能。虽然实现上就是在用户点击某个课时时插入一条记录,实际上这是面试时展示业务思维的好材料:你不仅完成了CRUD,还思考了用户学习路径。
数据库设计其实就两条心法:先画业务流程图,把“用户从注册到学完一门课的完整路径”走一遍,你自然会知道哪些表需要;然后用Excel把每个表的字段先列出来,你会发现很多边界问题在写代码前就被暴露了。千万别一上来就打开Navicat建表,改来改去会浪费很多时间。
2.2 权限模块与登录态设计
权限是课设答辩中最容易“被突击提问”的部分,也是最值得做扎实的模块。很多同学只会用Shiro或者Spring Security的默认配置,真被问到“Token过期了怎么办”“接口怎么拦截的”就卡壳。我建议你在课设这个阶段把权限机制真正吃透,它同时也是面试高频问题。
我最终使用的是JWT + 自定义HandlerInterceptor的组合,没用Spring Security。理由很简单:课设的权限模型只有三种角色,用拦截器判断请求头里的Token再解析角色,逻辑直白、代码量小、出了问题你能快速定位。Spring Security虽然功能强大,但概念非常多,滤器链、认证管理器、UserDetailsService,整套走通至少要两周,课设时间经不起这么耗。
具体实现思路是:
- 用户登录成功后,使用JWT工具类生成一个Token,里面包含用户ID、用户名、角色,有效期设为24小时。
- 后端在响应头
Authorization里返回Token给前端。 - 前端每次请求在请求头带上
Authorization: Bearer 你的token。 - 后端写一个
AuthInterceptor,在preHandle方法里校验Token,并往ThreadLocal里写入当前用户信息。 - 注册拦截器时,排除登录、注册、课程列表、课程详情等公开接口;对需要教师权限的接口(如发布课程、上传视频),在处理方法或注解上判断
当前用户角色 != TEACHER返回403。
这里有一个容易踩的坑:JWT的密钥(secret)一定要放在配置文件里,不要硬编码在代码中,更不要提交到公开仓库。另外,JWT是无状态的,服务端无法主动让某个Token失效,所以如果你实现了“修改密码后强制下线”的功能,需要在修改密码后改一下JWT的加密密钥,或者把Token版本号塞进负载里,存到Redis做校验。我在课设里采用的是增加Redis校验层,把“用户名+用户ID”作为Key,把Token作为Value存入Redis,拦截器里先查Redis,Token不存在或者不一致就直接拒绝。这套方案能在答辩时讲出“安全加固”的故事。
密码存储必须用哈希加密,不要存明文。我用的BCryptPasswordEncoder,它内置盐值随机逻辑,每次加密的结果都不同,但校验时能正确判断。Spring Security的加密工具可以单独抽出来用,不需要因此引入整套Security。
还有登录失败次数限制,这个也可以考虑加上。用Redis的INCR命令,同一个用户名连续输错5次密码就锁定15分钟。虽然课设老师不一定问,但这是网上几乎找不到现成轮子但实际项目非常常见的需求,写进简历面试时能聊很久。
2.3 课程视频上传与存储方案
在线教育平台与普通商城系统的最大区别,就是订单卖的不只是信息,还有视频资源。视频上传和播放也是答辩时老师最容易追问的点。我的实现方式是这样的:
如果只是在本地环境跑,直接把视频放到项目的static/upload/videos/目录下就行,用Nginx或者Spring Boot的静态资源映射来访问。但要注意一点:Spring Boot默认上传单文件大小限制是1MB,直接传视频几乎必被拦截。你需要在application.yml里修改配置:
yaml复制spring:
servlet:
multipart:
max-file-size: 500MB
max-request-size: 500MB
如果你用Tomcat部署,还需要改Tomcat的连接器参数,尤其maxSwallowSize,这个经常被忽略导致文件上传时连接被打断。
但本地存储有个致命问题:重启或重新部署时,上传的文件很容易丢(Spring Boot的resources目录一般打包进JAR,运行时是只读的)。所以更好的方案是把上传路径配置到外部目录,比如:
yaml复制file:
upload-path: /Users/xxx/edu-platform/upload/
然后用一个配置类将本地路径映射为虚拟路径/files/**,这样视频可以通过http://localhost:8080/files/videos/xxx.mp4直接访问,同时上传的文件不依赖项目打包。
如果你愿意折腾一点,可以接入阿里云OSS或七牛云对象存储。课设阶段用OSS有好处也有坏处:好处是代码里关于文件校验、路径拼接、访问控制这些逻辑都是真实工业界写法;坏处是OSS需要实名认证、创建Bucket、配AccessKey,而且线上访问需要外网,答辩现场如果没网容易翻车。我的建议是,本地存储作为默认方案,代码里预留OSS工具类,如果学校环境允许、个人时间充足,再切换为OSS。这样你论文里能写“本系统支持扩展到对象存储”,答辩时也是一处亮点。
视频播放器方面,我用的Vue集成video.js播放器,视频格式转成MP4(H.264编码),大多数浏览器能直接播放。如果课程里要放录屏视频,建议先使用格式工厂或FFmpeg统一转码成H.264编码的MP4,再上传,不要直接传MOV或AVI,否则前端播放体验极差。另外,免费课时和付费课时的视频权限判断要细化:未登录用户播放免费课时需要看客状态;已登录未购买的播放免费课时,显示“试看”标识;已购买用户播放全部课时,才允许调出播放器。这些权限逻辑放在后端接口里做,前端只是按返回结果显示或隐藏播放器。
3. 实操过程与核心环节实现
3.1 从零搭建项目骨架
我会分阶段来演示,所有命令和配置都以Mac/Linux环境为参考,Windows下思路完全一样。
第一步,用IDEA的Spring Initializr创建Spring Boot项目。Group填com.example,Artifact填edu-platform,Java版本选8或11,依赖先勾选:Spring Web、MyBatis Framework、MySQL Driver、Lombok、Validation。Redis和Spring Security建议先不勾,后面按需手动添加,避免生成一堆不需要的自动配置,对新手来说这会让启动报错排查难度增加。
第二步,在pom.xml中追加MyBatis-Plus和JWT依赖。以我用的2.7.x版本为例,推荐使用以下坐标:
xml复制<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
MyBatis-Plus的版本和Spring Boot版本之间的兼容性要注意,3.5.x的Plus对Spring Boot 2.x全家桶支持得很稳。
第三步,配置application.yml。最核心的几个配置项如下:
yaml复制server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/edu_platform?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 你的密码
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
map-underscore-to-camel-case必须设为true,这个配置的作用是将数据库字段course_title自动映射到Java属性courseTitle。否则你写实体类时要么给每个字段加@TableField注解,要么手写一大串驼峰别名,费力不说还容易出错。
logic-delete-field是MyBatis-Plus的逻辑删除配置,我建议所有表都加上deleted字段,删除操作变成更新操作,数据不真正丢。这个设计在真实项目中几乎是标配,放在课设里也很出彩,因为论文中“系统设计”部分可以多写一节“数据安全设计”。
第四步,运行项目,看到Spring Boot启动成功的日志后,再开始写业务代码。很多人第一步就卡在起不来项目,记住把报错信息先看明白。最常见的几个原因,无非是数据库没建、连接地址写错、端口占用、依赖冲突这四类。
3.2 核心业务代码实现(课程模块为例)
我以课程模块作为示例来展示代码结构,因为它的业务复杂度最合适:既涉及分类多级查询,又要处理教师发布课程和用户分页查询。
先定义实体类,对应数据库表。以Course为例:
java复制@Data
@TableName("course")
public class Course {
@TableId(type = IdType.AUTO)
private Long id;
private Long teacherId;
private Long categoryId;
private String title;
private String cover;
private BigDecimal price;
private Integer status; // 0 未上架,1 已上架
private Integer saleCount;
private String intro;
private LocalDateTime createTime;
private LocalDateTime updateTime;
@TableLogic
private Integer deleted;
}
这里要注意两点:主键策略使用IdType.AUTO,表示依赖数据库自增;@TableLogic加在deleted字段上,后续执行delete方法时会自动变成UPDATE course SET deleted=1 WHERE id=?。
Mapper层就是继承BaseMapper,什么都不用写,分页和单表CRUD全有了:
java复制@Mapper
public interface CourseMapper extends BaseMapper<Course> {
IPage<Course> selectCoursePage(Page<Course> page, @Param("query") CourseQuery query);
}
因为课程列表需要展示教师名和分类名,这是多表联查的场景,所以单独写一条XML SQL,放在resources/mapper/CourseMapper.xml里:
xml复制<select id="selectCoursePage" resultType="com.example.eduplatform.vo.CourseVO">
SELECT
c.id, c.title, c.cover, c.price, c.status, c.sale_count,
u.name AS teacherName,
cat.name AS categoryName
FROM course c
LEFT JOIN user u ON c.teacher_id = u.id
LEFT JOIN category cat ON c.category_id = cat.id
<where>
<if test="query.categoryId != null">
AND c.category_id = #{query.categoryId}
</if>
<if test="query.keyword != null and query.keyword != ''">
AND c.title LIKE CONCAT('%', #{query.keyword}, '%')
</if>
AND c.status = 1
AND c.deleted = 0
</where>
ORDER BY c.create_time DESC
</select>
在Service里调用时,要注意MyBatis-Plus的分页插件需要单独配置,直接使用selectPage不会生效。这个坑会在第4章细说。
Controller层写接口时,返回结构统一用我定义的Result类:
java复制@Data
public class Result<T> {
private Integer code;
private String msg;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMsg("success");
result.setData(data);
return result;
}
public static <T> Result<T> error(String msg) {
Result<T> result = new Result<>();
result.setCode(500);
result.setMsg(msg);
return result;
}
}
统一返回结构最直接的好处是前端处理逻辑简单,只需要判断code是否为200,而不用从各种字段里猜错误原因。写论文时,“通用返回结果类”也是接口设计章节的亮眼素材。
3.3 数据库脚本与初始化数据
数据库初始化脚本是这次项目质量的一个分水岭。很多同学交了项目之后,老师一导入数据库,发现分类是空的、测试账号没有,只能自己手动造数据,印象分直接降低。我建议你在sql/目录下同时提供三个文件:
schema.sql:建库建表语句,不含数据。data.sql:初始化的基础数据(分类、管理员账号、一个测试教师账号、一个测试学生账号、几门完整课程和课时)。init.sql:上面两个文件合体,方便老师一条龙执行。
初始化数据里必须包含的内容:
- 三个角色的测试账号,统一密码为
123456,但存储的必须是BCrypt加密后的哈希值,不要直接存123456。 - 至少3个课程分类,比如“编程开发”“设计创意”“职场技能”。
- 每个分类下至少一门课程,每门课程至少2个章节、每章节2个课时,其中一个课时标记为免费(
is_free=1)。 - 首页轮播图数据,图可以用占位图,但URL要能访问。
- 给测试学生预先购买一门课程,方便演示“我的课程”页面。
这些数据会让你在演示时非常从容:每演示一个功能,你都能直接调用出数据,而不是现场敲。
另外,我强烈建议你在Word文档里把“数据库设计说明”写详细一点,并且配上ER图和字段说明表。ER图可以用draw.io画,或者直接用PowerDesigner逆向生成,再粘贴进文档。答辩时,老师翻数据库设计章节的概率非常高。
3.4 文档撰写与答辩准备
这里分享一下跟我一起做毕设的同学最终论文的章节结构,几乎就是模板级别的:
- 绪论
- 1.1 选题背景与研究意义
- 1.2 国内外研究现状
- 1.3 本文主要工作
- 相关技术介绍(Spring Boot、MyBatis-Plus、MySQL、Redis、JWT)
- 需求分析
- 3.1 可行性分析
- 3.2 功能需求分析
- 3.3 非功能需求分析(安全、性能、可维护性)
- 系统设计
- 4.1 系统总体架构设计
- 4.2 系统功能模块设计
- 4.3 数据库设计(含E-R图和表结构)
- 系统实现
- 5.1 用户注册与登录模块
- 5.2 课程管理模块
- 5.3 选购与订单模块
- 5.4 视频播放与学习记录模块
- 5.5 评论与公告模块
- 系统测试
- 6.1 测试环境
- 6.2 功能测试用例
- 6.3 性能测试与结果分析
文档写的最大误区是“把代码粘贴一遍当实现”,正确做法是:先说“本模块实现的功能是什么”,再说“采用的方法是什么”,最后配上核心代码片段和截图。每段配至少一张运行截图,这是最直观的。
答辩PPT的话,个人建议掌控在10分钟以内:讲项目背景花1分钟,技术选型讲2分钟,功能演示4分钟,创新点/难点3分钟。不要念代码,而是主动讲你遇到的坑和解决办法,比如“视频上传限制了1MB导致大视频传不上去,通过修改配置文件参数和调整上传目录解决了”,这种具体问题比任何空洞的“提升了用户体验”都更让老师认可。
4. 常见问题与排查技巧实录
4.1 典型问题速查表
这一节,我把做项目过程中自己和周围同学踩过的坑集中整理成一个速查表。每个问题都是真实遇到过的,排查方法也可以直接照做。
| 问题现象 | 原因分析 | 解决方案 |
|---|---|---|
| 启动失败:端口8080被占用 | 之前的项目或进程还在监听端口 | 命令lsof -i:8080查找PID,kill -9 PID,或者在配置文件中改server.port |
| 启动失败:Access denied for user 'root' | 数据库账号密码错误 | 检查application.yml中的用户名密码,确认与MySQL账号匹配 |
| 启动失败:Unknown database 'edu_platform' | 没有创建数据库 | 执行CREATE DATABASE edu_platform DEFAULT CHARACTER SET utf8mb4; |
| 中文乱码 | 数据库连接URL没有指定编码,或表字段不是utf8 | 在JDBC URL增加useUnicode=true&characterEncoding=utf8;建表时统一使用utf8mb4 |
| 查询结果只有一条记录没了 | 逻辑删除字段被误置为1 | 检查MyBatis-Plus的逻辑删除配置,确认deleted字段默认值为0 |
| 上传视频报错“文件大小超出限制” | Spring Boot默认单文件1MB限制 | 修改multipart.max-file-size和max-request-size |
| 静态资源图片404 | 虚拟路径映射没配置或路径拼错 | 检查WebMvcConfigurer中的addResourceHandlers映射 |
| MyBatis-Plus分页无效,查全表 | 缺少MybatisPlusInterceptor分页插件配置 | 注册PaginationInnerInterceptor,注意拦截器加载顺序 |
| 跨域报错 | 前后端在不同端口,后端没开启跨域 | 配置CorsFilter或实现WebMvcConfigurer的addCorsMappings |
| JWT解析报错 | JJWT版本不一致或密钥太短 | 保证jjwt-api/impl/jackson三件套版本一致,HS256密钥至少32字节 |
| 日期格式化奇怪 | 返回JSON格式不是预期格式 | 在application.yml中配置spring.jackson.date-format和time-zone |
重点说下MyBatis-Plus分页插件配置,因为这个坑特别隐蔽,而且影响很大,遇到了页面数据全量返回,肉眼根本看不出问题。正确写法是:
java复制@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
paginationInterceptor.setOverflow(true);
paginationInterceptor.setMaxLimit(100L);
interceptor.addInnerInterceptor(paginationInterceptor);
return interceptor;
}
}
setOverflow(true)表示超过页码时自动回退到第一页,setMaxLimit(100L)防止一次性拉取过多数据。加上这个配置后,IPage的total字段才会有值,前端才能正确渲染分页组件。
4.2 实操心得与避坑指南
这一部分想聊点没法写进论文但非常有用的话。
第一,开发顺序不要按模块来,要按“垂直切片”来。什么意思?就是先打通一个极简的用户注册登录流程,然后在这个基础上一层层加功能。如果一个模块从数据库到后端再到前端都通了,后面的模块多半能顺畅地复用这套套路。反过来,如果你先做一个模块到100%,再做下一个,你会发现很多公共代码没法复用,返工率极高。
第二,Git从第一天就要用。哪怕你一个人开发,也要用Git管理代码。我见过太多人课设收尾时代码崩溃,没有历史版本可以回退,只能手动找回旧的备份文件。用Git至少三天提交一次,关键节点打标签,比如v1.0-login、v1.1-course,出来问题直接回退到上一个稳定版本,非常安心。
第三,前端页面不要堆现成的模板。网上那些免费后台管理模板,风格和代码质量参差不齐,而且往往带了你不熟悉的路由配置和权限逻辑,你改起来比从零写还慢。课设的前端不需要多炫酷,干净、整洁、交互合理就行。我用的Vue2+Element UI,页面结构简单,按钮和表格都是现成组件,一周就能把课程管理和后台页面全部写完。
第四,视频资源一定要提前准备好。去网上找几段公开的MP4测试视频(或者直接录屏自己的操作过程),命名成lesson01.mp4这种格式,在初始化SQL里把视频URL填好。别等到答辩前一天才想起来没有素材,到现场临时找视频传上去,网络不行就翻车了。
第五,测试数据要造得“像真的”。用户昵称、课程标题、评论内容不要都是“测试”、“123”、“aaa”,用心编辑一批有真实感的数据。老师查数据库时,看到“Java从零基础到实战”和“使用Spring Boot开发博客系统”这样的课程名称,和你看到“测试课程1”“测试课程2”的感觉,完全是两个档次。
5. 最后的叮嘱
这一整套项目做下来,我最深的体会是:课程设计真正考验的不是编码速度,而是你对业务的理解和工程的规范度。宁可功能少做一个,也不要把已有的功能做得漏洞百出、代码一锅粥。
选这个题目的同学,答辩时一定把以下几点准备透:在线教育行业的痛点(教育资源分配不均、学习时间碎片化)、系统的核心用户故事(学生找课、付费、学课,教师上传、管理课程)、数据安全方面的思考(密码加密、Token认证、逻辑删除)。
最后再分享一个小技巧:正式演示前,重启一次项目,用干净的数据从头跑一遍注册、登录、选课、下单、播放全程。这个流程如果不出岔子,答辩基本就稳了。很多翻车现场都是因为部署环境换了一台电脑、数据库密码没对上、端口变了却没改配置,提前踩一遍能避免99%的尴尬。项目做完之后,把它当作自己的作品来维护,有空可以继续加功能、重构代码,你会发现它带给你的价值远远不止一门课的成绩。
