
最近有位读者在后台问我基于 Spring Boot 的大学生选课系统代码写到一半卡住了论文更是一腔空白。我回了一句你先别急着写代码回到题目本身把这个标题拆开看一遍答案其实就出来了。这标题拆到最后是两件事——你要交付一套能跑的选课系统同时要交付一篇能通过评审的毕业论文。前者看工程量后者看设计思考和文字表达而大多数人的误区恰好是想把“写系统”和“写论文”当成两段独立任务处理。这篇文章我会把整条路线完整走一遍怎么拆解题目、怎么定技术栈、怎么设计数据库、怎么写选课核心逻辑、怎么把开发过程变成一篇合格的毕业论文。适合还在观望选题的人也适合已经开工、做到一半回头补文档的人。只要有其中一条能帮你少熬一个夜那这篇就没白写。1. 题目拆解一篇论文加一套系统交付物到底是什么1.1 为什么选课系统是毕业设计里的常青树很多同学选这个题目是因为“听着不那么难身边也有人做过参考资料多”。但真正把它做完的人会告诉你这个题目往下挖其实完全能撑起一篇中等以上质量的毕业设计。第一业务贴近大学生活。选课、退课、容量限制、课表冲突这些场景你自己就经历过需求认知门槛极低不用花大量时间去理解一个陌生领域。需求分析章节写起来顺手访谈谁都能做问卷也能发得出去论证材料一抓一大把。第二规模适中独立可完成。一个选课系统通常就三类角色学生、教师、管理员。核心链路是“开课—审核—选课—录成绩—查看”不需要对接复杂的第三方系统一个人从数据库设计到前端页面收尾两三个月是完全可以实现的。相比那些动不动就要对接支付、短信、物流的电商类题目选课系统的工程量对本科阶段更友好。第三它具备足够的“技术挖掘点”。表面看选课就是在课程表里插入一条记录但实际展开会发现选课并发会不会超员同一学生两门课时间怎么判断冲突不同学期数据怎么隔离权限怎么控制这些问题每一个都能在论文里单独拿出来讲清楚。尤其是“并发超选”和“时间冲突检测”是非常典型的论文加分点后面我会展开说。1.2 题目里的隐藏要求一个完整软件工程闭环论文题目里既然有“毕业论文”三个字就说明交付物不是一个项目源码而是完整的软件工程流程需求分析系统要给谁用要解决哪些业务痛点功能边界在哪。可行性分析技术上有无风险时间上是否可控经济成本是否可接受。系统设计整体架构、模块划分、数据库设计、接口设计。系统实现编码结果、页面截图、核心代码讲解。系统测试功能用例、边界用例、简单并发测试。文档与答辩论文全文、演示环境、答辩PPT。我见过太多人把代码写完才发现论文一个字没写最后突击一周把“技术介绍”从网上复制粘贴一篇把截图随便截几张结果导师一眼就看出来系统是真做了论文是假的。应对办法只有一个别把开发和论文拆开。开发过程中要随手记录关键决策、保存页面截图、标记版本变化。这些细碎素材最后都会变成论文里的核心论据。1.3 技术栈怎么定才能让系统不重也没那么难现在做 Java 方向毕业设计主流方案已经非常收敛。我的建议是后端 Spring Boot持久层 MyBatis-Plus数据库 MySQL前端按个人基础在 Vue 和 Thymeleaf 里选一个。Spring Boot 几乎是目前 Java 后端项目的“默认起点”。毕业生选它理由其实特别现实项目启动快依赖用 starter 一键引入内嵌 Tomcat 不用单独配置Spring 生态里的东西它全兼容。相比传统 SSM 框架手写一堆 XML 配置Spring Boot 能把你从环境配置的泥潭里拽出来让你更快进入业务逻辑本身。MyBatis-Plus 则是 MyBatis 的增强工具单表 CRUD 基本不用手写 SQL自带分页插件和逻辑删除支持。对毕设来说效率非常重要它有明显优势。也有些学校偏好 JPA如果你指导老师指定了那就按老师要求来论文里写清楚规范。前端选型这里有一个很关键的取舍。如果你对 Vue、前端工程化有一定基础项目剩余时间又还有余量建议上前后端分离后端提供 REST API前端用 Vue 或者前端框架搭界面论文里能写“前后端分离架构”内容更丰富。但如果你 Java 是主课、前端基本靠复制那我建议用 Thymeleaf 做服务端渲染模板页搭配 Bootstrap系统完整度照样很高开发难度低很多。选型没有绝对高低关键看你能不能把每一块都讲明白。这里我要明确劝一句不要为了简历好看把一个选课系统做成微服务。拆分多个服务、引入注册中心、服务网关、分布式事务看起来技术含量上去了但本科阶段的论文根本驾驭不了这套复杂度答辩现场只要被追问一个“分布式事务如何保证一致性”就很容易暴露漏洞。单机 Spring Boot MySQL把并发控制这个点做扎实比堆一堆名词有用得多。2. 地基设计角色、流程与数据库表结构2.1 三种角色一个核心业务闭环选课系统的角色权限其实不需要复杂建模把它拆开就是三张脸谱学生查看学期课程、选课、退课、查看个人课表、查看成绩。教师提交开课申请、查看自己课程的学生名单、录入成绩、导出名单。管理员维护学期、院系、专业等基础数据管理学生和教师账号审核课程查看统计报表。核心流程是一个闭环管理员维护基础数据教师提交开课申请管理员审核后课程进入可选状态学生在选课期间内选课系统做冲突检测和容量控制选课结束后教师录入成绩学生查看成绩最后管理员归档本学期数据。这里要特别注意“课程状态”的设计。比如草稿、待审核、已发布、选课中、已结束、已归档。很多同学会把状态做成字符串直接存什么“审核中”“审核通过”“已结束”写起来随意后面判断逻辑到处是魔法值容易乱。我建议用整数状态加枚举类或者至少统一用常量定义。这个点在论文数据库设计小节里也可以专门写一段叫“课程生命周期状态管理”。权限模型方面毕设里常见的是拦截器配合 JWT或者干脆用 Spring Security。如果你对 Spring Security 很熟用它当然没问题论文里分量足如果不是很熟我建议用拦截器加 JWT 自己实现代码量不大但正因为是自己写的论文里能讲得更透彻答辩时也能说清楚每个环节的作用。2.2 核心数据模型从 ER 图到建表语句数据库设计直接决定了系统能撑到哪一步。很多初学者就是喜欢把所有字段塞进一张大表或者一门课的时间就存一个字符串“周一第三节”查询全靠 like这样写到冲突检测那一步基本就写不下去了。我按常见方案给一版核心表你可以在此之上按自己的业务增删表名说明关键字段user账号表id, username, password, role, statusstudent学生档案表id, user_id, student_no, name, college, major, class_nameteacher教师档案表id, user_id, teacher_no, name, college, titlesemester学期表id, semester_name, start_date, end_date, statuscourse课程表id, course_code, course_name, credit, teacher_id, semester_id, capacity_limit, selected_count, week_day, start_section, end_section, week_start, week_end, statuscourse_selection选课记录表id, student_id, course_id, select_time, status, score关于 user 和 student / teacher 要不要分表我的建议是分。理由很简单user 表只存登录必需的账号凭据和角色学生要存的学号、班级、专业教师要存的工号、职称这些都是差异很大的字段混在一张表里会让 user 表变成一个臃肿的信息集合而且以后扩展其他角色也很别扭。ER 图画出来也清晰一个账号对应一个档案一对一的关联关系在论文里也很好讲。选课记录表要关注一个点联合唯一索引。比如 (student_id, course_id) 建唯一索引可以有效阻止程序漏洞导致的重复选课。即便你代码里已经做了判断数据库层面再加一道保险永远是值得的。课程表这里明显在时间的表达上做了结构化设计。week_day 表示星期几start_section 和 end_section 表示从第几节到第几节week_start 和 week_end 表示从第几周到第几周。后面讲冲突检测时你会发现这种设计不是自找麻烦而是为了让“区间重叠判断”变成可计算的逻辑。2.3 选课时段的区间重叠判断最容易被追问的地方这是选课系统里真正的算法核心我在答辩现场被问的问题最后都绕到了这里。先想清楚一个问题两门课什么时候算时间冲突很多人第一反应是“上课时间相等”这是错的。真实情况是一门课周二第1-2节另一门课周二第2-3节其实也冲突因为第2节重叠了。如果一周还是单双周交替那还得考虑周次。所以正确的思路是把时间拆成三个维度去判断星期是否相同week_day。节次区间是否重叠一门课的 [start_section, end_section] 与另一门课的同名区间是否有交集。周次区间是否重叠week_start 到 week_end 之间是否有交集。三个条件同时满足才算冲突。判断两个闭区间是否有交集其实是一个经典数学公式不一定要写循环当且仅当 A 的起点小于等于 B 的终点且 A 的终点大于等于 B 的起点。套用过来就是private boolean isTimeConflict(Course c1, Course c2) { boolean sameDay c1.getWeekDay().equals(c2.getWeekDay()); boolean sectionOverlap c1.getStartSection() c2.getEndSection() c1.getEndSection() c2.getStartSection(); boolean weekOverlap c1.getWeekStart() c2.getWeekEnd() c1.getWeekEnd() c2.getWeekStart(); return sameDay sectionOverlap weekOverlap; }为什么要写成这样而不是用字符串去比较因为字符串相等只能解决“完全一样”的情况解决不了“交叉重叠”的情况。比如“周一第1-2节”和“周一第2-3节”字符串不同但实际时间重叠学生不可能同时上。这类逻辑在论文里单独成节重点描述区间交集算法是很标准的算法设计内容。如果你的系统里还有单双周的情况可以在课程表加一个字段比如 weekType1 表示单周2 表示双周0 表示每周都上。判断时把单双周不匹配的课程排除掉即可算法主体不变但论文的“系统设计”部分又能多一段可说的内容。3. 编码主线先跑通核心链路再补花哨功能3.1 项目初始化、目录分层和统一接口约定动手写代码最重要的一条先从核心链路跑通不要一上来就琢磨“消息通知”“导出Excel”“在线聊天”这些外围功能。核心链路指的是管理员发布课程 → 学生选课 → 教师录成绩 → 学生查成绩。这条链路通了系统就立住了其他功能才有往上面挂的资格。项目初始化的时候我建议用 Spring Initializr 这类工具生成基础工程依赖选上 spring-boot-starter-web、mybatis-plus-boot-starter、mysql-connector-j、lombok、validation。JWT 库可以手动引入比如 jjwt。密码加密我用的是 spring-security-crypto 里的 BCrypt只引入这一个模块不用整个 Spring Security。包结构建议这样分controller接收请求做参数绑定。service业务逻辑事务边界在这里。mapper数据访问对应 MyBatis-Plus 的 Mapper 接口。entity实体类对应数据库表。dto请求和响应的数据传输对象。common统一返回结果、公共常量、异常类。config配置类比如跨域、拦截器、MyBatis-Plus 分页插件。utils工具类比如 JWT 的封装。统一返回结果也是必做项。定义一个 R 类里面放 code、msg、data 三个字段成功返回 code200业务异常返回 code400 或自定义值。全局异常处理器切住所有抛出的 BusinessException统一转换成 JSON 返回这样前端无论用什么框架处理逻辑都是一套。数据库连接配置我直接放到 application.yml 里但要注意密码、账号这些实际部署时要用环境变量或者配置文件外部化避免把明文写进代码。论文里可以针对这一点写一段“系统安全设计”不是空喊口号有实际落地点。server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/course_system?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: yourpassword mybatis-plus: 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分页插件也需要在 config 里配置一下。MyBatis-Plus 自带 PaginationInnerInterceptor一个 Bean 的事但你要是忘了分页查询会查全表然后内存分页课程列表数据一多就卡。配置好之后选课列表这种需要分页的场景直接调用 Page 对象即可。3.2 登录认证方案JWT 比 Session 好在哪登录认证我几乎都会建议 JWT。它本身不复杂流程就三步登录成功签发 token前端每次请求带上 token后端拦截器校验 token 并解析出当前用户身份。相比 Session 方案JWT 是无状态的后端不需要维护会话适合前后端分离也方便以后扩展。更关键的是论文里你可以把认证流程画得非常清晰签发、存储、传递、校验、过期处理。拦截器的逻辑大概是先放行白名单比如登录接口、注册接口其余接口从请求头里拿 token拿不到直接返回 401解析失败返回 401通过后把用户 ID 放进去同时建立当前线程的一次性上下文方便 Service 层随时取到操作人。密码存储方面明文密码是不可原谅的。用 BCrypt 加密验证时调用 BCryptPasswordEncoder 的 matches 方法。答辩时老师很可能问一句“密码怎么存的”你回答“BCrypt 加盐哈希”并把验证逻辑说清楚这几分就稳了。3.3 选课功能的 Service 层事务、冲突检测、容量扣减一起解决选课是整个系统的“心脏”也是并发问题最集中的地方。我直接给你看核心方法的大致结构Transactional(rollbackFor Exception.class) public void selectCourse(Long studentId, Long courseId) { Course course courseMapper.selectById(courseId); if (course null || course.getStatus() ! CourseStatus.PUBLISHED) { throw new BusinessException(课程不存在或不在选课时间内); } ListCourseSelection selections selectionMapper.selectByStudentId(studentId); for (CourseSelection selection : selections) { if (isTimeConflict(course, selection.getCourse())) { throw new BusinessException(该课程与已选课程时间冲突); } } int affected courseMapper.decreaseCapacity(courseId); if (affected 0) { throw new BusinessException(课程容量已满选课失败); } CourseSelection selection new CourseSelection(); selection.setStudentId(studentId); selection.setCourseId(courseId); selection.setSelectTime(LocalDateTime.now()); selection.setStatus(SelectionStatus.SELECTED); selectionMapper.insert(selection); }这里的每一个步骤都有它的道理我拆开讲事务注解放在整个方法上保证“扣容量”和“插入记录”同生共死。如果插入失败容量要回滚回去不然就会出现没选上但名额少了一个的情况。时间冲突检测放在容量扣减之前。先看清楚这门课跟学生已选课是否冲突再动手占名额。把校验放在 Service 而非前端是因为前端校验很容易被绕过系统最终的正确性必须依赖后端。最关键的是courseMapper.decreaseCapacity(courseId)这个操作。它在 SQL 层面做的事是UPDATE course SET selected_count selected_count 1 WHERE id ? AND selected_count capacity_limit。这不是“先查出来再改回去”而是一条原子 SQL数据库会针对这条 UPDATE 加行锁两个请求同时执行时只有一个成功。这是解决“超选”问题的核心也属于乐观锁思想的一种体现。论文里能把这个解释明白比你堆十个接口都加分。选课记录插入后联合唯一索引也能兜底。哪怕代码哪一步漏判断了数据库层面也不会让同一个人重复选同一门课。一道双保险这是工程设计里非常重要的思维不要把正确性完全寄托于代码逻辑。退课逻辑反过来要先检查这条选课记录是否真实存在并且处于已选状态改成退课状态或用逻辑删除然后把课程的 selected_count 回减。回减也要注意并发问题同样是原子 UPDATE防止选课和退课同时发生时数量错乱。4. 三大角色的功能落点与页面形态4.1 学生端选课列表、退课策略与课表展示学生端的核心页面就是三个课程列表页、我的选课页、我的课表页。课程列表页要支持按学期筛选、按课程名称或教师名称搜索因为课程数据一旦多起来纯滚动加载会非常痛苦。这时候 MyBatis-Plus 的分页就派上用场了后端接收 pageNum 和 pageSize返回分页结果给前端。列表里的课程卡片或表格行要清楚展示课程容量和已选人数比如“已选 45 / 名额 50”给学生一个直观的余量判断。选课按钮的状态需要细分已选、可选、已满、时间冲突、未开始、已结束。前端可以根据后端返回的字段做禁用处理但真正的逻辑校验必须在后端重新做一遍。退课策略要注意时间窗口。有些学校规定选课期间可以随意退选课结束后开学的调课阶段也能退但成绩录入开始后必须锁定。这个可以在系统里做成一个“选课开关”管理员控制。不要让学生随时都能退课那样会出现大量“先占坑、后观望”的行为。课表展示是一个典型的前端逻辑题。把一周看成横轴 7 天一天看成 12 节或者你们学校的具体节次把学生已选课程按星期和节次填入表格单元格。后端返回一维课程列表前端转成二维数组用 Vue 或者 Thymeleaf 渲染。跨节课程要合并单元格否则效果会很丑。4.2 教师端开课申请、名单管理、成绩录入教师端的功能要围绕“门课”展开。教师提交开课申请时要填课程名称、学分、容量、上课时间。这里后端必须做教师授课时间冲突检测不能出现一个老师同一时间提交两门课。判断算法和学生的冲突检测完全一样只是对象从“学生已选课程”换成了“教师已开课程”代码几乎可以复用。这一点写完可以在论文里提一句“算法复用”有建模意识是加分项。课程列表页每个教师只能看到自己的课程。课程状态不同对应的操作也不同待审核的可以撤销审核通过的可以查看学生已结束的可以打印成绩单。注意权限控制不是只靠前端隐藏按钮后端在查询时就要拼上 teacher_id 条件。学生名单管理是从 course_selection 表关联 student 表查出来的可以展示学号、姓名、专业。导出 Excel 属于扩展功能有时间的就做一个。用 EasyExcel 写一个导出方法给前端一个下载链接答辩时展示一下效果不错。但我的建议是先保证核心功能稳定再去加这些。成绩录入是教师端最有操作性的功能。一门课的学生名单要在页面上逐行展示每行有平时成绩、期末成绩、总评三个输入框。总评最好由后端计算规则可以做成可配置。比如平时成绩占 30%期末占 70%提交时统一计算总评并存进选课记录表。批量更新时不要用 for 循环逐条 update可以直接收集所有待更新对象用 MyBatis-Plus 的批量更新方法数据库压力小很多。成绩提交之后应该有一个“锁定成绩”的操作锁定后学生端就能看到成绩教师不能再随意修改除非管理员重置。4.3 管理端数据维护、课程审核、统计报表管理端是系统里“看起来不起眼但工作量不小”的部分。基础数据维护包括学期、院系、专业、班级。很多学生做毕设时会忘记做学期管理导致所有课程堆在一起分不清是哪个学期的。加一张 semester 表所有课程都关联学期 ID就非常干净。账号管理包括学生和教师的维护。需要提供两种录入方式手动添加和批量导入。批量导入用 Excel 模板填写学号、姓名、专业、班级后上传后端逐行解析并创建默认密码默认密码可以统一为学号或身份证后六位首次登录强制修改。这个功能答辩时很好展示而且解决了一个真实管理场景。课程审核是管理员的核心业务动作。教师申请开课后管理员可以看到待审核列表查看课程信息后选择通过或驳回驳回要填写原因教师端能看到。审核通过的课程才会出现在学生的可选课程列表里。这里的状态转换逻辑就是我在第二章里说的“课程生命周期”代码不复杂但设计思想要清晰。统计报表是管理端最容易出效果的部分。选课人数统计、热门课程 Top10、各院系选课率、教师开课数量排行都用 ECharts 画出来。数据来源就是几行简单的 GROUP BY 查询。我见过有不少项目在这一块选择性放弃觉得不是核心功能但实际上它是一块很大的“论文截图资产”一页图表贴上去系统完成度立刻上一个档次。5. 毕业论文写作把项目“翻译”成合格文档5.1 先搭论文框架再决定开发节奏我个人的经验是写论文不是从“写完代码之后”开始的而是从你确定题目的那天就开始。正确做法是先搭一个论文的二级标题框架就像一个书架后面开发到哪儿就往对应章节里填内容。这样可以避免最后两周集中写作的高强度焦虑。一个标准本科毕业论文大致可以这样组织章节参考篇幅写作重点第1章 绪论800-1200字研究背景、意义、国内外现状、主要工作第2章 相关技术1200-2000字Spring Boot、MyBatis-Plus、MySQL、JWT、前端框架第3章 需求分析2000字左右可行性分析、功能需求、用例图、非功能需求第4章 系统设计2500字左右架构设计、模块设计、数据库设计、接口设计、算法设计第5章 系统实现3000字以上分角色展示页面截图、核心代码讲解、运行结果第6章 系统测试1000-1500字测试环境、功能测试用例表、并发测试、结果分析第7章 总结与展望500-800字总结工作内容、指出不足、提出后续改进方向这里“相关技术”章节最容易写砸。很多论文把 Spring Boot 的介绍从官网或者博客上抄一段充满了“简化开发”、“提高效率”这种空话。技术章节的正确写法是把技术讲清楚之后立刻接一句“在本次系统中我使用该技术的哪个特性解决了哪个问题”。比如写 JWT要落到本系统的登录认证流程写 MyBatis-Plus要落到课程分页查询和批量更新成绩。5.2 关键技术和系统设计章节怎么写才有得分点系统设计章节是整篇论文含金量最高的地方。不要只贴一个架构图就完事要把关键决策和取舍过程写出来。比如并发控制。你可以在设计章节描述选课场景下的并发问题选课系统上线短时间内会有大量学生同时提交如果采用“先查后更新”的方式极容易出现超员。然后给出你的方案也就是UPDATE course SET selected_count selected_count 1 WHERE id ? AND selected_count capacity_limit。为什么用原子更新因为它在数据库层面保证了读改写三个操作不会被并发请求割裂。这个解释往论文里一放设计逻辑非常清晰。再比如时间冲突检测。论文里可以先用一个小表格描述课程时间字段的设计再给出区间重叠判断的公式配合核心代码。这就是一个完整的算法设计小节有输入、有输出、有复杂度分析。老师看到这里基本就能确认这个系统是你自己做出来的。需求分析章节不能只停留在“系统分为三个模块”这种描述。要站在用户视角写场景学生进入选课页面系统需要展示什么选课高峰期系统应该控制什么教师开课时如果时间和已有课程冲突系统应给出什么提示。每一条功能需求最好对应一个用例图或用例描述表显得规范化。5.3 测试章节与截图规范差距往往拉在这里论文里的测试章节很多人的做法是列一个表功能名称、预期结果、实际结果、是否通过。这没错但太单薄了。要注意完整性和层次感。第一要写测试环境。操作系统、JDK 版本、MySQL 版本、浏览器、测试工具一条条列清楚说明有几次结果是在一个固定环境下产生的。第二功能测试要有异常和边界用例。正常用例之外至少要覆盖几个典型异常场景选一个名额已满的课程、选一个与自己已选课程时间冲突的课程、重复选同一门课、未登录直接访问选课接口。把这些用例写进去测试章节的信息量立刻不一样。第三如果做了并发测试一定要在论文里写出数据。用 Jmeter 模拟 100 个用户同时选同一门只有 20 个名额的课程测试结果应该是选课成功人数恰好等于 20失败人数为 80系统不产生超选记录。这个结果表一放你说“系统具备选课防超员能力”的时候底气是完全不一样的。截图规范上我见过太多系统实现章节的截图带着浏览器收藏栏、桌面图标、甚至是微信聊天框的缩略图观感很差。建议是准备一个专门截图目录按章节编号组织文件每一张截图都提前裁好边界只保留系统界面本体。展示数据时使用“张三”、“李四”这类代称不要出现真实姓名和学号避免隐私问题。一张干净的截图抵得上千字描述。6. 踩坑复盘与答辩准备提前把老师可能想听的话准备好6.1 从开发到论文的常见问题速查表我把这一路最常见的坑整理成一个清单按开发类和论文类分开你对着自查就好。类别现象或问题原因解决方案开发项目启动报端口被占用上次运行残留进程换端口或杀掉占用进程开发前端请求接口报 401token 过期或未携带前端请求拦截器统一加 token后端放行白名单开发前后端分离项目跨域报错后端未配置跨域配置 CORS 或前端开启代理转发开发选课记录重复插入代码没有防重校验数据库 (student_id, course_id) 建联合唯一索引开发选课超员先查询再更新并发空隙改用原子 UPDATE 扣减容量开发时间冲突判断漏判用字符串比较上课时间拆解星期、节次、周次做区间重叠判断开发分页查询返回总条数不对分页插件没有配置配置 MyBatis-Plus 分页拦截器开发密码明文存储被老师批评偷懒没加密使用 BCrypt 加盐哈希论文相关技术章节全是空话直接抄官方简介结合项目场景重新描述论文图表编号混乱最后集中补图开发时顺手编号保存避免后期返工论文查重率过高大面积复制网络资料用自己的语言复述降低连续相同字符答辩老师问数据库为什么这么设计没有准备设计理由从查询效率、数据冗余、可扩展性三个角度准备这里面“查重率过高”我要单独说一句。对付查重最有效的不是到处找降重工具而是建立自己的表达方式。比如介绍 Spring Boot网上都在说“简化开发配置”你可以换成“我在项目中通过 Spring Boot 的多环境配置能力统一管理了本地环境和服务器环境不同的数据库连接参数”。别人写过一万遍“简化配置”你写的是自己的场景查重自然低。6.2 答辩前的准备清单与临场表达答辩本质上是一次“技术讲解”不是念论文。老师最想确认的是这个系统是不是你做的关键设计你懂不懂如果让你明天加一个功能你有没有思路。高频问题基本上躲不开这几个为什么选 Spring Boot选课系统如何防止超选时间冲突检测的算法是什么JWT 认证流程怎么走数据库为什么这么设计这个系统还能怎么扩展。以上每一个我在前面各章都已经给了答案逻辑你顺着那个思路准备即可。建议你准备一份 5 分钟的演示脚本按这个顺序走登录系统 → 展示三种角色的界面 → 重点演示一次完整选课流程 → 展示时间冲突提示 → 展示容量满员提示 → 展示统计报表。演示时不要干点每操作一步用一句话说明这一步背后的设计意图比如“这里选课会实时校验时间冲突”。如果被问到不会的问题不要慌也不要硬编。诚实地讲“这个点我之前没有深入考虑但我当前的实现中是这样规避的后续可以这样改进……”比不懂装懂强得多。老师要的是你的思考链路不是百科全书。最后我再分享一个实操上的小技巧在答辩前一天把数据库、后端、前端完整地重新部署一遍从零开始跑通。为什么因为很多同学在开发机上依赖 IDE 的隐藏配置才能启动换一台干净机器立刻原形毕露。提前演练一遍部署过程相当于给自己的系统做了一次最好的兼容性测试。这套选题最打动我的地方是它把一个教学场景里最常见的矛盾——课程资源有限、学生选择多样——用工程化方式落到了系统里。如果你正准备动手我的建议是别把目标定成“写一个系统”而是“用技术回答一个业务问题”。围绕公平选课、时间不冲突、容量不超员这几个真实问题去做设计和写论文你会发现整个节奏都是顺的代码不会烂尾论文也不会空。