尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
SpringBoot+Vue+MySQL选课系统全栈开发实战:从设计到部署
前几天一个学弟找我说学校课设要求做个信息管理系统他选了“学生选课系统”这个题但网上翻了一堆源码不是缺胳膊少腿就是跑不起来。我直接给他发了一套SpringBoot Vue MySQL的完整项目解压、配置、启动前后端加起来十几分钟就跑起来了。他后来问我能不能把思路写出来这篇就是基于那套源码整理的一份实操复盘从技术选型、数据库设计到前后端联调、部署踩坑全部摊开讲。我平时接类似的外包小项目也不少选课系统这种属于“看着简单做起有细节”的典型。学生、教师、管理员三种角色登录认证、课程管理、选课退课、名单统计业务闭环清晰正好覆盖了一套管理系统该有的核心模块。用SpringBoot做后端接口、Vue做前端页面、MySQL存数据这个组合也是目前国内中小型项目和课设最常用的技术栈既有代表性又不会太复杂。这篇文章主要面向两类人一是拿这个题目做课设或毕业设计的学生二是想快速上手SpringBoot Vue全栈项目、但不想从零搭框架的开发者。我会从项目设计思路、数据库表结构、后端核心接口、前端页面实现、本地启动步骤到常见问题挨个梳理尽量做到你照着文章也能把整套系统跑起来。1. 项目整体设计与技术选型思路1.1 为什么是SpringBoot Vue MySQL先说选型。很多人在做选课系统这类项目时纠结到底用Servlet JSP还是SpringBoot。我的看法很直接除非老师硬性规定必须用JSP否则能上SpringBoot就上SpringBoot。SpringBoot最大的优势是“约定大于配置”内置Tomcat不用自己折腾Web容器。以前SSH或者SSM项目要写一堆XML配置SpringBoot一个启动类加上几个注解就全搞定了。对于课设和中小型项目来说开发效率是第一位的。而且SpringBoot自带的spring-boot-starter-data-jpa或者MyBatis Starter连数据库操作都帮你封装好了真正要写的业务代码其实没多少。前端选Vue的理由也类似。国内前端圈子Vue的使用率一直很高文档中文友好、上手曲线平缓而且Vue的双向数据绑定在做表单类交互时特别顺手。选课系统的核心操作是“查看课程列表 - 勾选课程 - 提交”这种场景用Vue的v-model 列表渲染代码量比原生JavaScript少一半不止。MySQL更不用多说了开源、稳定、资料多配合Navicat或者MySQL Workbench管理数据非常方便。选课系统这种量级的数据MySQL 5.7或者8.0都绰绰有余。1.2 业务需求与角色权限梳理选课系统不是简简单单搞个课程表让学生点一下就行。一套合规的选课系统至少要覆盖三类角色和一条完整的业务闭环。学生角色关心的是能看到当前学期开放了哪些课程能查看课程详情任课老师、上课时间、学分、容量能选课、退课能查看自己已经选中的课程列表和总学分。教师角色关心的是能查看自己名下开设了哪些课程能看到每门课选了哪些学生能统计选课人数甚至导出名单。有一些还涉及学生成绩录入不过这个要看具体需求范围。管理员角色的权限最大负责课程信息管理增删改查、学生和教师账号管理、开设学期管理还可以看到全局的选课统计报表。业务闭环就是管理员开课 - 学生选课 - 教师看名单 - 管理员统计分析。这个闭环跑通系统的大框架就算立住了。我见过很多同学做选课系统前端页面做得花里胡哨但业务上连“选课后要减库存”这个基本逻辑都没实现这属于本末倒置。提示做项目之前先把角色和核心业务流程画清楚。哪怕只是草稿纸上画几个框和箭头也比直接动手写代码强。2. 数据库设计与后端核心实现2.1 数据表设计与建表SQL数据库设计是整个项目的根基。表结构设计得合理后面写代码会非常顺畅反之后面每写一个功能都要在SQL上打补丁。我在这套系统里用了六张核心表用户表user、学生表student、教师表teacher、课程表course、选课表select_course、专业/班级表可选择。考虑到不同学校院系结构差异大有的还需要学院表我这里按最通用的情况处理。先看用户表这是登录认证的关键CREATE TABLE user ( id INT NOT NULL AUTO_INCREMENT, username VARCHAR(50) NOT NULL COMMENT 登录账号, password VARCHAR(255) NOT NULL COMMENT 密码(加密存储), role TINYINT NOT NULL DEFAULT 2 COMMENT 角色(0管理员,1教师,2学生), status TINYINT NOT NULL DEFAULT 1 COMMENT 状态(1启用,0禁用), create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;学生表和教师表是用户表的扩展存放各自的详细信息CREATE TABLE student ( id INT NOT NULL AUTO_INCREMENT, user_id INT NOT NULL COMMENT 关联用户表, student_no VARCHAR(20) NOT NULL COMMENT 学号, name VARCHAR(50) NOT NULL COMMENT 姓名, major VARCHAR(100) COMMENT 专业, grade VARCHAR(10) COMMENT 年级, phone VARCHAR(20) COMMENT 联系电话, PRIMARY KEY (id), UNIQUE KEY uk_student_no (student_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT学生信息表;课程表的核心字段除了基本信息还有两个“隐藏关键点”课程容量capacity和已选人数selected_count。这两个字段直接决定了选课时的容量控制逻辑。CREATE TABLE course ( id INT NOT NULL AUTO_INCREMENT, course_no VARCHAR(20) NOT NULL COMMENT 课程编号, name VARCHAR(100) NOT NULL COMMENT 课程名称, teacher_id INT NOT NULL COMMENT 任课教师(关联教师表), credit DECIMAL(3,1) NOT NULL DEFAULT 2.0 COMMENT 学分, capacity INT NOT NULL DEFAULT 60 COMMENT 课程容量, selected_count INT NOT NULL DEFAULT 0 COMMENT 已选人数, schedule VARCHAR(100) COMMENT 上课时间, location VARCHAR(100) COMMENT 上课地点, status TINYINT NOT NULL DEFAULT 1 COMMENT 状态(1开放,0关闭), PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT课程表;选课表是业务发生的主战场这里加了一个联合唯一约束这个在后面讲并发时还要细说CREATE TABLE select_course ( id INT NOT NULL AUTO_INCREMENT, student_id INT NOT NULL COMMENT 学生ID, course_id INT NOT NULL COMMENT 课程ID, select_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 选课时间, status TINYINT NOT NULL DEFAULT 1 COMMENT 状态(1正常,0已退课), PRIMARY KEY (id), UNIQUE KEY uk_student_course (student_id, course_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT选课记录表;2.2 选课接口的并发控制方案这是整个系统最有技术含金量的地方也是面试官最喜欢问的点多个学生同时抢同一门课怎么保证不会超选很多初学者写的选课逻辑是这样的先查一下selected_count是否小于capacity然后执行insert选课记录再update课程表让selected_count加1。这种写法在单用户测试下一切正常但一旦并发量上来两个学生同时读到selected_count59都判断还有名额然后都执行insert和update课程容量就会变成61超选。我在这套系统里用了三层保障第一层是SQL层的原子操作。把“判断 更新”合并成一条带条件的UPDATE语句UPDATE course SET selected_count selected_count 1 WHERE id #{courseId} AND selected_count capacity这条SQL的返回值是受影响的行数。如果影响行数为0说明容量已满直接返回“课程已满”提示。这一步就用数据库自身的行锁保证了更新过程的原子性不用手动写同步锁。第二层是事务。把减容量和插入选课记录放在同一个事务里要么都成功要么都失败Transactional public boolean selectCourse(Long studentId, Long courseId) { int rows courseMapper.increaseSelectedCount(courseId); if (rows 0) { return false; // 容量已满 } SelectCourse selectCourse new SelectCourse(); selectCourse.setStudentId(studentId); selectCourse.setCourseId(courseId); try { selectCourseMapper.insert(selectCourse); } catch (DuplicateKeyException e) { // 该学生已经选过这门课抛出异常触发事务回滚 throw new BusinessException(不能重复选课); } return true; }这里用了Transactional注解如果插入选课记录时出现异常前面的UPDATE操作也会回滚避免了“课程人数加了、选课记录没插上”这种数据不一致的问题。第三层是数据库层面的唯一约束。就是2.1里提到的uk_student_course联合唯一索引从数据库硬层面保证同一个学生不能重复选择同一门课即使代码逻辑有漏洞数据库也能兜底拦住。提示很多企业级项目在极端高并发下会用Redis分布式锁或者消息队列削峰但选课系统这种量级用数据库事务和唯一约束完全够用不用过度设计。2.3 后端项目分层与核心接口清单后端代码结构我按标准的Controller-Service-Mapper三层来做。实体类entity对应数据库表Mapper负责SQL操作Service写业务逻辑Controller暴露接口给前端调用。核心接口清单如下接口方法路径作用登录POST/api/auth/login账号密码登录返回JWT Token获取当前用户信息GET/api/auth/info根据Token获取用户信息和角色课程列表GET/api/course/list分页查询课程列表支持搜索课程详情GET/api/course/{id}查看单门课程信息选课POST/api/course/select学生选择课程退课POST/api/course/cancel学生退掉已选课程我的课程GET/api/student/myCourses学生查看已选课程列表教师课程列表GET/api/teacher/courses教师查看自己的课程课程学生名单GET/api/teacher/course/{courseId}/students教师查看某门课的学生名单课程管理POST/PUT/DELETE/api/admin/course管理员增删改查课程选课统计GET/api/admin/stats全局选课数据统计JWTJSON Web Token做登录认证是现在比较通用的方案。用户登录成功后后端生成一个Token返回给前端前端在请求头里带上这个Token后端通过拦截器验证身份和权限。相比Session方案JWT天然适合前后端分离的项目。我用的依赖是jwt或spring-boot-starter-security如果嫌Security配置麻烦也可以只用Interceptor JWT代码量小很多。3. 前端Vue设计与交互实现3.1 前端项目结构与路由设计前端我用的Vue搭配Vue Router做路由管理UI组件库选的Element UI。整套项目用Vue CLI或者Vite创建目录结构如下vue-frontend/ ├── public/ ├── src/ │ ├── api/ # 所有后端接口请求的封装 │ │ ├── auth.js │ │ ├── course.js │ │ └── user.js │ ├── router/ # 路由配置 │ │ └── index.js │ ├── store/ # Vuex状态管理 │ │ └── store.js │ ├── views/ # 页面组件 │ │ ├── Login.vue │ │ ├── StudentHome.vue │ │ ├── TeacherHome.vue │ │ └── AdminHome.vue │ ├── utils/ # 工具函数 │ │ └── request.js # axios封装 │ ├── App.vue │ └── main.js └── package.json路由设计上除了登录页/login主界面采用布局组件 子路由的嵌套模式。比如学生端和教师端各自有自己的布局侧边栏菜单不同。这里有一个关键点路由守卫。未登录用户直接访问首页会被重定向到登录页不同角色访问不属于自己的页面也会被拦截。router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (!token to.path ! /login) { next(/login); } else if (token to.path /login) { next(/); } else if (to.meta.role to.meta.role ! store.state.userInfo.role) { next(/403); } else { next(); } });这个路由守卫非常重要不能用“登录了就放行”这种粗放逻辑必须结合角色判断权限。不然学生把URL改成/admin就能看到管理页面虽然接口层也有校验但前端体验很不好。3.2 axios封装与页面交互逻辑axios封装应该是每个Vue项目的第一步。我在utils/request.js里统一配置了baseURL、请求超时时间、请求拦截器和响应拦截器。请求拦截器统一添加Token响应拦截器统一处理异常码。比如Token过期返回401时自动清除本地Token并跳转登录页。这样页面代码里就不用每个请求都写一套错误处理逻辑非常省事。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) { Message.error(res.message); return Promise.reject(new Error(res.message)); } return res.data; }, error { if (error.response error.response.status 401) { localStorage.removeItem(token); router.push(/login); } Message.error(error.message); return Promise.reject(error); } );页面交互的经典场景是学生选课。选课页面是一个课程列表表格每一行有“选课”按钮。点击按钮后前端调用选课接口后端返回成功或失败。这里的交互细节要注意选课成功后要把表格里该课程的“已选人数”刷新同时把按钮置灰防止学生反复点击。3.3 前后端联调与跨域处理前后端分离开发最常见的坑就是跨域。前端开发服务器默认在localhost:8080后端在localhost:8081端口不同就存在跨域问题。我在项目里用了两种方案开发环境用Vue CLI的proxy代理生产环境用后端配置CORS。代理方式是在vue.config.js里配置module.exports { devServer: { port: 8080, proxy: { /api: { target: http://localhost:8081, changeOrigin: true } } } };这样前端请求/api/auth/login时开发服务器会自动把请求转发到http://localhost:8081/api/auth/login浏览器的视角里就是同源请求了不会触发跨域限制。提示changeOrigin: true一定要设置不然代理转发后Host头不对后端在验证来源时可能出错。4. 本地运行与部署实战4.1 环境准备清单“可直接运行”这套项目对开发环境版本还是有一定要求的。很多同学跑不起来不是代码问题是环境版本对不上。我整理了一份经过验证的版本组合工具版本要求说明JDK1.8或11SpringBoot 2.x建议JDK8SpringBoot 3.x要求JDK17注意区分Maven3.6后端依赖管理可替代方案IDEA自带MavenNode.js14Vue CLI项目建议Node 14及以上Vite项目建议Node 16MySQL5.7或8.08.0以上注意驱动名变化Navicat/Workbench任意版本可视化数据库管理工具非必须后端我用的SpringBoot版本是2.7.x对应JDK8。如果你机器装的是JDK17建议直接改用SpringBoot 3.x或者重新安装JDK8因为SpringBoot 2.7.x放在JDK17上运行会有兼容性问题。4.2 数据库初始化步骤第一步是创建数据库。打开Navicat或命令行执行CREATE DATABASE IF NOT EXISTS course_selection DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;这里有个关键点字符集一定要选utf8mb4。有些同学用默认的utf8在插入生僻字或者表情符号时会报错选utf8mb4能彻底避开这个问题。第二步是导入项目里带的course_selection.sql文件。这个SQL文件里包含了建表语句和初始数据包括默认的管理员账号admin/admin123、测试学生账号2021001/123456和测试教师账号T001/123456。导入后务必自己登进去看一下数据是否完整。4.3 后端启动步骤后端启动前先改配置文件application.yml。核心配置有两处spring: datasource: url: jdbc:mysql://localhost:3306/course_selection?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 你自己的密码 driver-class-name: com.mysql.cj.jdbc.Driver第一处是数据库连接串。如果你的MySQL是8.0版本driver-class-name必须写成com.mysql.cj.jdbc.Driver如果是5.7及以下写成com.mysql.jdbc.Driver。这里很多同学容易搞混导致启动时报ClassNotFoundException或者连接失败。第二处是serverTimezoneAsia/Shanghai。中国程序员的一个经典痛点是MySQL 8.0默认时区与本地不同不设置时区会报“The server time zone value is unrecognized”的错误。加了这一段基本就能解决。改完配置后打开项目根目录执行mvn spring-boot:run或者在IDE里直接运行主类上的main方法。看到“Started Application in xxx seconds”这样的日志说明后端启动成功了。4.4 前端启动步骤前端启动步骤相对固定在项目根目录打开终端npm install npm run servenpm install阶段是一个高损操作经常有人卡在这里半天。如果网络不好建议提前配置淘宝镜像源npm config set registry https://registry.npmmirror.com装完依赖后npm run serve启动默认端口是8080。如果你同时跑了后端后端接口是localhost:8081前端是localhost:8080浏览器打开http://localhost:8080登录页就能正常展示了。用测试账号登录学生端能看到可选课程列表点击选课刷新后“我的课程”里就有了记录。到这里整套系统就算完整跑通了。5. 新手最容易踩的坑与排查技巧5.1 启动阶段常见报错速查表我把实际运行中最高频的几类报错整理成了一个速查表每一条都对应一个真实场景报错信息原因解决方案ClassNotFoundException: com.mysql.jdbc.Driver驱动名写错更改为com.mysql.cj.jdbc.DriverServer time zone value unrecognized时区配置缺失连接串加serverTimezoneAsia/ShanghaiAccess denied for user rootlocalhost数据库密码不对检查application.yml的password配置Port 8080 was already in use之前启动过某个服务占用8080换端口或改后端server.portnpm ERR! network request to https://registry.npmjs.org failed未配置镜像/网络差配置淘宝镜像源后重试Failed to bind properties under spring.datasourceYAML配置文件格式错误检查缩进YAML不允许Tab5.2 功能运行中的典型问题排查项目能启动不等于功能没问题。运行过程中的排查才是最锻炼人的环节。第一个常见问题是登录成功但请求接口时提示未授权。这通常是Token校验环节没有正确读取请求头。我在项目里统一约定前端在Authorization头里带“Bearer 空格 Token”后端拦截器解析时必须保持完全一致的格式。格式稍有出入就会认证失败排查时先打印后端收到的完整请求头比对一下格式。第二个常见问题是CORS跨域报错。这个问题的排查思路是看请求是从哪个端口发起的目标是哪个端口。开发环境优先用代理方案不要直接在SpringBoot里配CrossOrigin因为代理方案更接近生产环境的部署形态。第三个常见问题是选课成功后“已选人数”没变。这个多半是前端没有重新加载数据。选课成功后的刷新逻辑我一般用两种方式一是调用查询接口刷新列表数据二是前端本地维护一个selectedCount变量选课成功后进行1更新。但要注意前端本地维护的变量在页面刷新后会丢失最终还是要以后端数据为准。5.3 我的几条实操心得最后分享几段经验。做选课系统这类管理系统有几个点是我反复踩坑后总结出来的第一数据库表设计和接口设计一定要先于前端页面。很多同学喜欢先把页面画出来再反推接口这个顺序在个人项目中其实问题不大但一旦涉及前后端分开写还是建议先定接口文档前后端并行开发效率最高。第二事务和并发控制不要偷懒。选课系统的“超选”问题看似只有并发场景才会触发但哪怕你的系统只有几十个人用也建议用事务 条件UPDATE 唯一约束这套组合代码量不增加多少但数据安全等级完全不同。第三日志一定要打。我在Service层几乎所有方法都加了一行日志记录入参和执行结果。选课这种核心接口日志里能直接还原出“谁在什么时间选了什么课、成功还是失败”排查问题会轻松很多。第四前端页面别过度设计。我见过很多学生把管理系统的UI做成营销落地页风格各种动画、渐变、大图轮播。管理系统就该有自己的样子——表单清晰、表格易读、操作反馈明确比花哨的视觉效果重要一万倍。这套代码我前前后后跑了不下二十遍各个模块都验证过。如果你照着文章操作还是有问题优先检查自己的环境版本和配置大多数问题都出在这两个地方。选课系统本身就是一个很适合练手的题目麻雀虽小五脏俱全把这一套吃透SpringBoot Vue前后端分离开发的整个链路基本就能打通了。
RELATED

相关推荐

十字封箱机选型分析:什么时候该选、怎么选、有哪些坑

十字封箱机选型分析:什么时候该选、怎么选、有哪些坑

一、现状:十字封箱机的市场定位与行业基本面1. 封箱机市场持续增长,十字封箱机需求占比高据行业公开运营数据显示,2025年国内智能封箱机市场规模同比增长约11.7%,其中十字封箱机/折盖封箱机/封箱机的需求占比超62%(来源…

📅 2026/9/9 15:22:19
ROS2入门实战:环境搭建与三种核心通信模型全解析

ROS2入门实战:环境搭建与三种核心通信模型全解析

很多刚开始接触 ROS2 的同学,最常遇到的一个困境并不是“看不懂代码”,而是不知道整套开发流程应该从哪里下手:装环境时遇到unable to locate package,创建功能包时搞不清目录结构,写节点时又把话题、服务、动作三种通…

📅 2026/9/9 15:22:19
照片误删别慌!8个恢复方案与黄金恢复期详解

照片误删别慌!8个恢复方案与黄金恢复期详解

删照片这件事,几乎人人都干过。当时觉得“这图没用”,手指一滑扔进回收站,过两天要用的时候翻遍相册找不着,才明白什么叫“删得快,悔得深”。我见过太多人在这时候病急乱投医,花大价钱买软件、连夜刷教程&a…

📅 2026/9/9 15:22:19
MORE NEWS

更多资讯

📰

STM32软件资源全解析:从开发环境搭建到调试烧录避坑指南

简介:面向STM32嵌入式开发者的综合资料包,聚焦STM32与FreeRTOS实时操作系统、LCD屏幕驱动的工程实践,适合学习多任务编程与人机交互显示的开发者,也可作为课程设计或毕业设计的参考资料。包内共324个文件,以C源码和头文…

📰

2025前端技术排行:从夯实地基到前沿技术的进阶路线

1. 为什么我敢在2025年做一张“夯到拉”的前端排行榜 2025年还在纠结“前端到底学什么”的人,我劝你先别急着买课,先把这张图看明白。最近很多读者私信我,问的都是同一个问题:“前端还值不值得入?面试题怎么越来越偏&a…

📰

FFmpeg与ANativeWindow:Android自研播放器渲染实践

简介:一套面向安卓开发者的视频播放器项目源码,演示如何通过开源多媒体框架完成视频解码,并将解码后的画面帧渲染到安卓原生窗口,实现流畅的原生播放。项目采用C/C混合编写,属于安卓原生开发的高级主题,适合…

📰

从零搭建私有化语音控制中枢:智能家居离线识别与意图解析实战

简介:基于树莓派与Python实现的智能家居语音控制系统,面向物联网、嵌入式及语音交互方向的开发者和学生,解决家居场景中用自然语音指令完成门禁、聊天、生活指南、待办提醒等日常操作的问题。压缩包共107个文件,大小仅1.67MB&…

📰

LED矩阵像素屏制作全攻略:从单片机扫描到反向电压防护

简介:围绕像素艺术与LED矩阵结合的入门资源,适合电子爱好者、创客及对复古8位图形感兴趣的开发者。内容系统梳理了像素艺术的设计理念、颜色编码与图像编辑工具的使用方法,涵盖像素艺术编辑软件的操作要点与常见调色板选择建议,并…

📰

冬季电脑防静电与低温防护全指南:从原理到实操

冬天一到,我家的电脑就开始“耍脾气”。前几天一个朋友抱着笔记本找我,说开机瞬间屏幕黑掉,电源灯亮着但完全没反应。拿到店里拆开一看,主板南桥芯片上有个焦黑的点,典型的人体静电放电击穿。这事儿在干燥的冬季真不罕…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬