尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

SpringBoot3+Vue3学生选课管理系统实战:从建库到部署全流程

发布时间:2026/9/29 21:06:19

资讯中心
01
ARTICLE

SpringBoot3+Vue3学生选课管理系统实战:从建库到部署全流程

SpringBoot3+Vue3学生选课管理系统实战:从建库到部署全流程
要做一套学生选课管理系统我见过的简历里十个Java方向候选人起码有七八个写过。它的定位很微妙既不像商城系统那样堆营销逻辑也不像OA系统那样涉及大量审批流刚好把用户角色、基础CRUD、权限控制、前后端交互这些核心技术点都串起来所以毕业设计、课程设计都喜欢拿它当题目。你拿到手的这套SpringBoot3 Vue3版本网上存货其实并不少但版本踩坑特别多。SpringBoot3一下子就要求JDK17起步Vue3的生态又和Vue2完全不同MyBatis-Plus甚至要单独引入支持SpringBoot3的starter。如果没人带着走一趟光是在环境配置上就能卡一个周末。这篇教程就把我从建库、写后端接口、搭前端页面到最终跑通部署的完整路径拆给你看同时把源码目录、数据库脚本、配套文档和答疑平台怎么配合使用也一并讲清楚。1. 为什么选这个项目需求、场景和整体拆解1.1 选题定位与功能需求学生选课管理系统的核心场景非常直观学校每个学期要开很多门课学生要在规定时间内选课教师要维护自己开设的课程并录入成绩管理员则负责管理用户和基础数据。三端角色一划分项目规模就变得可控了不会像企业级系统那样牵扯到支付、消息队列、分布式事务这些复杂概念又能覆盖毕业后工作里最常用的开发模式。我建议把系统拆成三种角色来梳理需求。管理员端需要维护学生和教师账号、重置密码、查看全校选课情况教师端需要管理自己的课程信息比如课程名称、学分、上课时间、容量还要能查看选课名单、为结课学生录入成绩学生端就是核心的选课退课操作能看到课程列表和剩余名额选完后能在“我的课表”里看到已选课程及成绩。1.2 技术栈选择的真实理由很多新手会纠结为什么非要用SpringBoot3 Vue3而不是回去用更成熟的SpringBoot2 Vue2我的看法是既然是当下做新项目就应该直接用新版本。SpringBoot3基于JDK17内置了Jakarta EE 9命名空间Spring Security 6那一套安全配置也重写了Vue3配合Vite构建启动速度和响应式机制都比Vue2时代舒服很多。这套组合最大的价值不在“新”而在于它目前已经是企业招聘面试中的高频技能点。写SpringBoot2的东西固然稳但面试官更想听你对新版本特性的理解。做毕业设计时把SpringBoot3 Vue3写进题目里本身也是个加分项。至于后端持久层我选MyBatis-Plus而不用原生MyBatis原因很直接通用Mapper能省下一大堆重复单表CRUD代码让精力集中在选课、退课、权限这些核心业务上。1.3 前后端项目结构怎么划分项目建议直接用两个独立工程后端叫course-server前端叫course-web不要为了省事塞到同一个工程里。前后端分离不仅是技术趋势更重要的是你部署时能分别打包调试时也能单独启动。后端标准结构按controller、service、mapper、entity分包再增加config、common、security几个包分别放配置类、统一返回和异常、JWT认证相关代码。前端则按views目录放页面router目录放路由api目录放接口请求store目录放Pinia状态utils目录放工具函数。为什么这么分因为毕业生答辩时老师极大概率会问“你这个项目结构是怎么设计的”你先能讲清楚包结构就成功了一半。2. 数据库设计与初始化脚本2.1 核心表结构与字段说明选课系统的数据库不需要刻意设计得太复杂但也不能只有一两张表。我常用的核心表就六张左右分别是用户表、角色表、课程表、选课表以及可选的教学班表。如果想让设计更完整还可以加一张学期表。用户表是最关键的一张字段可以这样设计字段名类型说明idbigint主键自增usernamevarchar(50)登录账号唯一passwordvarchar(100)BCrypt加密后的密码real_namevarchar(30)真实姓名rolevarchar(20)角色admin/teacher/studentstudent_novarchar(20)学生学号教师可空teacher_novarchar(20)教师工号学生可空课程表包含id、course_name、teacher_id、credit、capacity、selected_count、class_time、classroom字段。teacher_id关联用户表表示开课教师capacity是容量selected_count是当前已选人数。选课表是业务核心建议只存student_id、course_id、status、score和create_time。status可以表示已选、已退、已结课等状态score字段用于教师录入成绩。这里要注意用户表用role字段区分角色就不需要再单独做RBAC多表关联了复杂度会下降一个量级。2.2 选课表的冗余设计与数据一致性这里有个值得细讲的点课程表里为什么要有selected_count这个冗余字段如果每次查询剩余名额都去统计选课表里有多少条记录数据量大了以后性能会明显变差。保留一个维护好的冗余字段列表页直接展示capacity - selected_count性能好代码也简单。代价就是每次选课、退课成功后都必须同步更新selected_count而且必须在同一个数据库事务里完成。稍微懂点开发的人都会发现这里有并发风险两个学生同时抢最后一个名额都判断当前名额还剩1个然后都插入成功就超选了。解决办法是加乐观锁或者用原子更新语句。我比较推荐第二种更新课程表时直接用这么一句SQLupdate course set selected_count selected_count 1 where id ? and selected_count capacity。影响行数为0说明没抢到为1说明这次更新成功再往选课表插记录。这样就不需要先把selected_count查出来再判断也就从根源上解决了并发超选问题。2.3 SQL初始化脚本的注意事项数据库脚本一定要放在项目根目录的sql文件夹里命名用init.sql或者course_system.sql都行。脚本里至少要包含建库语句、建表语句、初始数据导入这三块。建库时建议写成create database if not exists course_system default character set utf8mb4 collate utf8mb4_general_ci。为什么强调utf8mb4因为如果不指定MySQL默认字符集在部分地区可能是latin1存中文会乱码。初始数据至少要造一个管理员账号、几个教师账号、十几个学生账号和一批课程数据。密码不要明文存用BCrypt加密后的字符串。还有一个很实用的点把外键约束加上是建表设计的一部分但不要在业务代码里用物理外键去关联删除。物理外键在并发高、分表时会变成性能瓶颈。用普通索引加逻辑关联就够了表设计文档里可以说“用索引替代外键约束保证灵活性”。3. SpringBoot3后端从零搭建3.1 JDK17和Maven环境准备pom文件避坑先检查你的JDK版本SpringBoot3强制要求JDK17及以上。很多新手项目跑不起来第一反应是代码问题结果一看JDK还是1.8直接没法编译。建议直接装JDK17然后IDEA的Project Structure里把Project SDK、Project language level都改成17。创建一个Spring Boot工程有两个常用方法一是用IDEA的Spring Initializr直接生成二是在Spring官网下载初始工程再导入。无论哪种方式生成后的pom.xml里parent版本会是3.x。我用的是SpringBoot 3.2.5版本整体稳定。此处有个大坑MyBatis-Plus在SpringBoot3里不能使用老版本mybatis-plus-boot-starter必须引入专门适配的依赖dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-spring-boot3-starter/artifactId version3.5.5/version /dependencyJWT相关依赖也建议使用jjwt 0.12.x系列老教程里的0.9.1版本已经过时还会和模块化JDK冲突。日志方面SpringBoot3默认用的还是Logback通过logback-spring.xml可以灵活控制控制台和文件输出这部分不用过度投入能输出及时信息就行。3.2 统一返回、全局异常与参数校验后端接口如果东一套返回格式西一套前端对接会非常崩溃。我习惯定义一个Result 类包含code、message、data三个字段。成功时code为200业务失败时code可以是500或者自定义的4001这样前端只需要根据code判断统一处理。全局异常处理用RestControllerAdvice正常开发会有业务异常BizException、参数校验异常MethodArgumentNotValidException和兜底的Exception。业务异常返回给前端友好提示未知异常不要直接把堆栈抛出统一记日志后返回“系统繁忙”。参数校验直接用Spring Validation在DTO字段上加NotBlank、NotNull、MaxController参数上写Valid。举个简单例子新增课程时courseName不能为空capacity必须大于0这种在校验层写死省去后续大量手工判断。校验不过时全局异常处理器会拿到错误信息返回给前端具体字段提示。3.3 登录认证JWT Spring Security 6登录接口是系统的入口。我建议用户登录后用JWT令牌做状态管理而不是用传统的HttpSession。前后端分离项目天然适合JWT因为后端不需要维护会话Token自带过期时间前端存到localStorage或者内存里每次请求放在Authorization请求头里发过来。Spring Security 6的写法相比旧版本变化很大。之前要继承WebSecurityConfigurerAdapter现在已经废弃了。正确写法是定义SecurityFilterChain的BeanBean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf(csrf - csrf.disable()) .sessionManagement(session - session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth - auth .requestMatchers(/api/auth/login).permitAll() .anyRequest().authenticated()) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); }JWT过滤器要做的事并不复杂从请求头解析Token验证签名和有效期如果合法就把用户信息塞进SecurityContextHolder这样接口里就能拿到当前登录人。登录密码校验用BCryptPasswordEncoder数据库存的也是BCrypt密文。要注意的是登录接口本身要放行但其他接口统一走认证切忌每个接口各自写一遍Token校验。3.4 选课、退课、成绩录入的后端实现细节在设计后端核心接口时我建议先列出最基础的几个URL。认证接口有/api/auth/login学生端接口有选课、退课、查询可选课程、查询我的课表教师端接口有创建课程、修改课程、查询选课名单、录成绩管理员端有用户管理和全校课程管理。选课Service是这套系统里最值得写细的。先把课程查出来校验是否存在、是否已选过、容量是否满了这些基础校验不能省。接下来用事务和原子更新来解决并发抢选问题这一步不能偷懒。完整逻辑大概是Transactional public void selectCourse(Long studentId, Long courseId) { StudentCourse exist studentCourseMapper.selectOne(...); if (exist ! null) throw new BizException(你已经选过该课程); int rows courseMapper.increaseSelectedCount(courseId); if (rows 0) throw new BizException(课程已选满请选择其他课程); StudentCourse sc new StudentCourse(); sc.setStudentId(studentId); sc.setCourseId(courseId); sc.setStatus(SELECTED); studentCourseMapper.insert(sc); }退课逻辑要反过来先删除选课记录再把课程表的selected_count减一。注意这里不能先减再删除防止删除失败导致名额被多减。成绩录入就更简单了教师根据选课记录id把score字段更新到指定值。4. Vue3前端开发实录4.1 用Vite创建工程并安装组件库前端部分既然用了Vue3构建工具就直接上Vite不要再绕回Webpack。创建一个新工程到指定目录npm create vitelatest course-web -- --template vue cd course-web npm install装好后立刻安装几个必备依赖vue-router用于页面路由pinia用于全局状态管理axios用于请求后端element-plus是组件库sass是样式预处理器。一条命令可以装完npm install vue-router pinia axios element-plus sassElement Plus是Vue3生态里非常成熟的组件库表格、表单、弹窗、分页都有现成组件。建议按需引入而不是全量引入不过零基础阶段为了方便直接在main.js里use(ElementPlus)也不影响跑通。学习时先求能用再追求按需优化。4.2 Axios封装、跨域代理和Token携带前端请求绝不能在每个页面里裸写axios那样后期改接口地址或处理Token会累死人。封装一个src/utils/request.jsimport axios from axios import { ElMessage } from element-plus const service axios.create({ baseURL: /api, timeout: 10000 }) service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) config.headers.Authorization Bearer ${token} return config }) service.interceptors.response.use(response { const res response.data if (res.code ! 200) { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res }, error { ElMessage.error(error.message || 网络异常) return Promise.reject(error) }) export default serviceToken手动塞到请求头后端Security过滤器就会自动读取。登录成功后把token存到localStorage同时把用户角色、用户名、真实姓名存到Pinia里这样不同页面就能根据角色控制显示内容。开发环境下最容易被跨域卡住。前端的地址是localhost:5173后端的地址是localhost:8080端口不一致就是跨域。最简单的方法不是在SpringBoot里写CrossOrigin而是直接配置Vite代理在vite.config.js里加一段server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }这样前端请求/api/auth/login时Vite开发服务器会把它转发到后端的8080端口请求头里Host也会被改写跨域问题就消失了。4.3 登录、选课和后台管理页面的实现要点登录页是所有页面里最简单的一个用户名输入框、一个密码输入框、一个登录按钮。点击登录后调登录接口成功后保存token和用户信息然后根据角色路由到不同首页。student角色跳到“可选课程”teacher角色跳到“我的课程”admin角色跳到“用户管理”。可选课程页面核心是一个Element Plus表格表格里展示课程名称、教师、学分、容量、剩余名额、上课时间和地点后面加一个“选课”按钮。选课时调用后端接口成功就刷新表格和已选列表。剩余名额为0或者已选过的课程按钮要置为禁用状态。我建议这些判断在前端也做一遍虽然后端才是安全底线但前端提前给用户反馈体验好很多。我的课表页面展示当前学生已经选上的课程并可显示成绩。如果成绩还没录入就显示“未录入”已录入就正常显示。教师端页面用课程管理表格每个课程可以展开选课学生名单也可以在列表行里直接点“录成绩”弹出对话框。管理员页面相对简单用户管理用表格加新增、修改、删除、重置密码课程管理可以复用教师的课程表接口。4.4 前端常见问题刷新404、菜单权限、样式失效前端踩坑点其实比后端更密集。最常见的是部署后刷新某个子页面变成404这是因为Vue Router默认是history模式在静态服务器上没有对应路径。解决办法要么在后端Nginx配置try_files要么把createWebHistory改成createWebHashHistoryhash模式更省事但URL里会带个#。做毕设建议直接用hash模式演示时不容易出问题。第二个问题是按角色渲染菜单和路由。不要把所有菜单写死建议在路由表里给对应路由加上meta.roles字段在路由守卫里判断当前用户角色是否在允许列表里。没有权限直接跳转登录页或403页面。路由守卫代码不算复杂但它是一个高频答辩考点。第三个问题是样式莫名失效或者组件样式冲突。这通常是因为没有按规范引入Element Plus样式或者全局样式覆盖了组件样式。Vite项目中重置全局样式时尽量用:root或特定class作用域避免直接给body里的元素写太多全局覆盖。5. 把项目跑起来运行、打包和部署全流程5.1 拿到源码后的启动步骤很多人在网上拿到的源码没附详细启动说明最后都是卡在环境或者配置上。拿到这套源码后建议严格按下面顺序操作。先看README或者doc目录找到数据库脚本用Navicat或命令行在MySQL里执行建库脚本确认course_system数据库存在且表都建好了。然后打开后端工程检查application.yml里的数据库账号密码是否和你本地一致。注意MySQL版本如果是MySQL 8driverClassName需要是com.mysql.cj.jdbc.Driver时区参数建议写成serverTimezoneAsia/Shanghai不然连接时会报时间差异常。接着启动后端。直接运行主类里的main方法观察控制台日志是否显示Tomcat started on port 8080。之后再启动前端npm install安装依赖npm run dev启动开发服务器浏览器访问localhost:5173。登录时用脚本里预设的账号比如管理员admin、教师teacher01、学生student01。5.2 前后端部署到服务器如果只是本地演示前后端分离跑起来就够了。但答辩时老师可能会问“你怎么部署的”所以最好知道打包流程。后端打包前先确认application.yml里的数据库地址是否改成云服务器地址然后执行mvn clean package生成target目录下的jar包。用java -jar course-server.jar就能运行也可以配合systemd或守护进程工具。前端打包更简单npm run build后会生成dist目录把dist整个丢到Nginx的html目录再配置一个反向代理把/api前缀请求转发到后端地址。如果你有云服务器就用一台Nginx同时代理前端静态文件和后端接口。Nginx配置核心就这几行root指向dist目录try_files $uri $uri/ /index.htmllocation /api/ { proxy_pass http://127.0.0.1:8080; }。这一套配置讲出来答辩老师会觉得你是真懂部署不是只会跑本地。5.3 数据库连接与备份建议项目做完了数据库数据要保护好。可以在项目根目录写一个backup.sql的备份说明常用操作是mysqldump导出。毕设阶段不用搞什么主从复制、高可用简单保留一个可恢复的备份脚本已经比大多数人强。另外密码等敏感配置尽量不要写死在代码里可以放到环境变量里读取。SpringBoot的application.yml支持${DB_PASSWORD:root}这种格式默认值能给到root。这样做不是为了上生产而是让代码看起来更规范答辩时能说清楚“我没有把敏感信息硬编码”。6. 源码、文档和答疑配套怎么用6.1 源码阅读顺序和二次开发技巧你手头的源码不是给你复制粘贴完就交作业的而是拿来理解、改造、二次开发的。我建议阅读顺序是先看数据库脚本理清表关系再看前端后端接口调用关系最后看核心的登录和选课业务代码。二次开发时不要一上来就大改先跑通一套最简单的流程比如学生登录、选课、查看课表。跑通后再逐步加功能。比较适合扩展的点有给管理员增加课程审核功能给学生选课增加验证码用Redis缓存课程列表给选课开一个预选加抽签的流程。这些扩展不大但写在论文里能让系统从“基本的CRUD”升级成“有一定业务复杂度”。6.2 毕业设计文档怎么写配套文档通常包含需求规格说明书、概要设计、详细设计和答辩PPT。写文档最忌讳把代码全贴进去老师要看你“为什么这么设计”而不是看你“复制了多少行”。需求文档就写清楚三个角色的用例字段表格、功能枚举、业务流程。设计文档要画清楚系统架构图、功能模块图、数据库ER图这里可以用工具绘制文档里放图不仅能加页数还能展示你的设计能力。详细设计重点放在选课并发处理、JWT认证流程、前端路由守卫这几个核心点上把一个点讲透比罗列十个点有用得多。6.3 答辩常见问题与回答思路答辩老师通常不会让你当场写代码但会针对核心业务和技术选型连续追问。我总结几个高频问题你先想好怎么用自己的话回答。第一问为什么选SpringBoot3和SpringBoot2有什么区别你可以回答JDK17、Jakarta命名空间、Spring Security 6的配置变化、MyBatis-Plus需要用新starter。能提到这些就足以证明你确实做过。第二问选课并发问题是怎么解决的这是最容易被问到的也是最能展示水平的点。你就讲原子更新selected_count的SQL以及事务保证选课表和课程表的一致性顺便提一下为什么不用先查再改。第三问Vue3和Vue2有什么区别可以从Composition API、响应式原理Proxy、Vite构建、Fragment支持、Teleport组件几个方向展开。答两三点即可不要背概念。第四问系统有哪些可以改进的地方这是开放性提问千万不要说“已经很完善了”。你可以说当前是单机部署后续可以引入Redis做热数据缓存用消息队列处理选课高峰这些改进方向合理且不浮夸。6.4 答疑遇到报错先按这个顺序排查答疑群里问得最多的就是环境类和配置类问题。遇到报错我建议你先别急着截图发群里按顺序自查一遍。第一看数据库是否连接成功用户名密码、host、端口、时区是否都对了第二看前端控制台和后端日志报错信息里通常直接写着原因第三看端口是否被占用8080或5173被占用时换端口就能解决第四看是否没导SQL表缺失的话接口一调必报错。如果大家的问题比较集中比如Maven依赖下载慢、Element Plus表格组件怎么用、打包后接口404这些都是规律性问题API文档里都有答案也可以先查文档再提问。我在实际操作中最想提醒你的其实是心态但凡做毕设第一次跑不通是常态不要因为一个报错就怀疑源码有问题。绝大多数问题都是版本、路径、配置层面的。把SpringBoot3后端、Vue3前端、MySQL数据库这份三角关系理顺这套选课系统不说能做出多高大上的效果但至少能让你在答辩台上逻辑清晰地讲上十分钟。你后续想把项目做得更亮眼给选课加个时间轴可视化、给管理员加个数据统计大屏这些扩展也都有现成的路可走关键是把这条主流程先真正走通。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。