
前后端分离的大学计算机基础网络教学系统用SpringBootVueMyBatisMySQL这套组合来落地是很多计算机类专业学生和初入行的开发者在找实战项目时最常遇到的需求。这个系统要解决的是高校计算机基础课程教学管理中一堆琐碎问题课件和视频怎么发、作业怎么收、考试怎么安排、成绩怎么统计。如果还靠U盘拷课件、Excel收作业老师和学生都被折腾得够呛所以一个完整的线上教学管理系统就成了刚需。下面我把整个项目的设计思路、数据库结构、前后端实现和部署流程拆开讲一遍给想复现或者改造成课程设计的人一个能直接抄作业的参考。这个项目的前端是Vue后端是SpringBoot数据库用MySQLMyBatis负责数据访问。它最大的特点是前后端完全分离后端只提供接口前端只关心渲染用户身份分为学生、教师、管理员三种覆盖了选课、学习、作业、考试、成绩这些核心教学场景。适合的人群很广准备做毕业设计或课程设计的学生、想上手前后端分离项目实战的后端开发者、以及学校或培训机构需要一套轻量教学管理系统的团队。1. 动手前的整体规划架构拆分与技术选型1.1 前后端分离不是炫技是这几点刚需以前很多教学系统是用JSP加后端模板渲染的写法页面逻辑和后端代码搅在一起。这次项目直接用前后端分离不是跟风而是有几个非常实际的考虑。第一并行开发效率高。前端和后端只需要约定好接口文档就可以各写各的。实际开发中前端被后端页面卡死的情况很常见后端改一个字段前端要等重新部署才能看到效果而前后端分离之后后端接口只要联调一次前端自己用Mock数据就能先跑起来。第二接口可以复用。教学系统往往不只是网页端在用学校可能还会要求手机浏览器适配、校内服务号引流甚至以后要对接教务系统。后端把接口设计成纯API未来任何客户端都能直接复用不需要改业务逻辑。这是我特别看重的一点因为改业务逻辑的成本往往比新写一个接口还高。第三部署更灵活。前端构建出来是一堆静态文件扔到任意Web服务器就行后端是一个独立进程。前端崩了不影响后端数据服务后端做版本升级也可以不停前端服务。前后端各自的发布节奏是独立的这在团队协作里非常友好。前后端分离的实际代价是增加了一次HTTP请求的拆分工作跨域、Token认证、接口联调这些都需要额外处理。这也是我在第5章会重点展开部署和排错的原因。很多人觉得跨域难其实本质就是浏览器按协议域名端口判断是不是同一个来源不是同一个来源就拦解决方案不外乎后端开CORS、前端走代理、生产环境用Nginx转发这几种。1.2 技术栈选型的4个关键决定这里先放一张我最终敲定的技术栈清单然后逐个说明为什么这么选。层次选型版本建议后端框架SpringBoot2.7.x配合JDK8前端框架Vue3 Vite Element PlusNode 16.20数据访问MyBatis可用MyBatis-Plus增强3.x数据库MySQL8.05.7也可认证方案JWTjjwt 0.11.x权限模型RBAC自定义注解 拦截器第一个关键决定是SpringBoot版本。如果是新学不要盲目追求最新版我建议直接用2.7.x配合JDK8。原因很现实SpringBoot 3.x强制要求JDK17而且包名从javax换成了jakarta网上大量教程还是基于老写法另外老版本插件的兼容性更好遇到问题更容易搜到现成答案。网上经常有人问springboot版本太高导致启动报错怎么办多半就是配了3.x却还在用JDK8。这个坑我建议开局就避开别跟版本较劲。第二个是Vue版本。Vue3配Element Plus是目前的主流Vue2配Element UI更稳定但官方维护力度已经下降。这个项目我选Vue3但要说清楚一点Vue3的安装和项目创建方式与Vue2区别不小尤其是脚手架从Vue CLI换成了Vite配置文件从vue.config.js变成了vite.config.js后面第4章专门讲环境配置照着做就行。第三个是MyBatis还是MyBatis-Plus。从学习角度纯MyBatis可以让你搞清楚SQL映射到底是怎么回事面试也爱问MyBatis的动态SQL、缓存机制从开发效率角度MyBatis-Plus的BaseMapper直接用内置方法能省大量简单CURD代码。我的建议是如果这是课程设计或毕业设计直接上MyBatis-Plus交源码时说明底层还是MyBatis如果是为了突击面试亲手写一份Mapper XML会更有底气因为面试官总喜欢追问底层细节。第四个是MySQL版本。MySQL 8.0是现在的主流功能更强但安装时有几个坑初始化账号密码、时区、默认认证插件caching_sha2_password连老版本驱动会报错。这些在常见问题表里我都写了解决方案。如果本地实在装不上8.0用5.7.44也完全能跑只是驱动和连接串稍有不同。SpringBoot 2.7.x自带的数据库驱动兼容MySQL 5.7和8.0主要是在连接串上加serverTimezoneAsia/Shanghai避免时区报错。2. 功能模块与数据库设计教学业务怎么落到表上2.1 三类用户与权限模型怎么落地教学系统的核心不是技术是权限边界。学生、教师、管理员这三种角色看到的内容和能做的操作完全不同所以权限模型要最先设计反复琢磨都不为过。我采用的是经典RBAC模型用户、角色、用户角色关联。相比直接在用户表里写一个role字段RBAC的优势是以后想加一个助教或者教务秘书角色时不用改表结构加一条角色记录再加关联关系就够了。说白了RBAC就是把用户和权限的关系解耦让权限可以组合和复配。登录认证这块用的JWT。流程是用户提交账号密码后端校验通过后生成一个TokenToken里带上userId和roleCode前端把Token存到localStorage之后每次请求都在请求头里带Authorization字段。后端用一个拦截器解析Token取到当前用户身份再结合自定义注解做权限校验。这里有个实际经验Token里不要放敏感信息只放userId、角色标识和过期时间其他信息都能在数据库里查。过期时间建议设成2小时到24小时之间太短频繁登录体验差太长又有被盗用风险。如果要求更高可以部署时加一层Redis做单点登录但本项目为了保持完整源码的本地可运行性用JWT自身过期机制足够了。密码存储一定要用BCrypt别用MD5后面代码部分会再次强调。2.2 课程与教学资源模块的设计要点课程模块是教学系统的信息主动脉。我把它拆成三级结构课程表、章节表、资源表。这个三级结构是经过实际使用验证的老师按周次上传资料学生按章节浏览非常符合计算机基础课的教学节奏。课程表记录课程基本信息比如课程名称、所属院系、授课教师、学期、课程简介和封面图。章节表挂到课程下面常见的是按周次拆分第1周、第2周这样排。资源表再挂到章节下面每一条资源就是一份课件、一个视频链接或一份练习文档。课件和文档的处理方式是上传后存到服务器本地的一个upload目录数据库里只保存文件路径。这样做的好处是源码跑起来简单不需要额外配置对象存储服务。但有个隐患这个方案只适合个人服务器或小范围使用文件多了以后要迁移到云存储。迁移时只需要把upload目录整体搬走数据库里的路径改成新地址即可所以一开始设计路径时就要用相对路径别写死绝对地址。视频资源这里有个小知识点很多课程视频是MP4格式直接用HTML5的video标签就能播放。如果遇到m3u8这种切片视频前端不安装任何浏览器插件也能处理用hls.js这个库一小段播放器代码就能搞定。后面第4章我会贴出关键代码这个方案在实际项目里验证过稳定且实现简单。2.3 作业、考试与成绩闭环作业与考试是这个系统最体现教学管理属性的部分也是答辩演示时的重头戏。作业模块的流程是教师创建作业设置截止时间学生看到未完成列表在线上传文档或填写答案学生提交后教师在线批阅给出评语和分数系统再把分数汇总进成绩表。作业表里有一个status字段区分已提交、已批阅、未提交、已逾期列表页可以直接按状态筛选体验比一个笼统的作业列表好很多。这个细节看起来小但实际用起来差别很大。考试模块分两种玩法。一种是纯客观题题库表里存选择题学生在前端作答提交后后端逐题比对自动出分。另一种是包含主观题客观题自动判主观题需要教师手动给分。考虑到毕业设计演示效果我建议考试部分至少做自动判分因为答辩现场没法等教师慢慢批改主观题。自动判分还能顺便展示出系统对数据的高效处理能力是个加分项。成绩模块要注意数据来源的多样性考试自动算出来的成绩、教师手工录入的作业分数、还有一些线下成绩需要支持手动添加。三种数据源统一汇总到一个成绩表每个学生每门课能查出明细。分数范围用0到100校验避免脏数据进入统计。2.4 核心数据库表结构速览为了不占篇幅我列出最关键的表设计这些表足够支撑前面说的全部功能。表名用途关键字段sys_user用户表id, username, password, real_name, statussys_role角色表id, role_name, role_codecourse课程表id, course_name, teacher_id, description, covercourse_chapter章节表id, course_id, chapter_name, sortresource资源表id, chapter_id, resource_name, type, urlhomework作业表id, course_id, title, content, deadlinehomework_submit作业提交表id, homework_id, student_id, content, file_url, score, commentexam考试表id, course_id, title, start_time, end_time, durationexam_question题库表id, exam_id, type, question_content, scoreexam_result考试成绩表id, exam_id, student_id, score有个设计细节容易忘所有表都建议加create_time、update_time两个字段MyBatis-Plus支持字段自动填充开发时不觉得做数据排查和统计时非常有用。另外字符集统一用utf8mb4别用utf8因为utf8在MySQL里存不下所有表情符号和生僻字将来导入数据很容易乱码。这里再给一个核心建表SQL示例方便直接跑CREATE TABLE sys_user ( id INT NOT NULL AUTO_INCREMENT, username VARCHAR(50) NOT NULL COMMENT 登录名, password VARCHAR(100) NOT NULL COMMENT BCrypt加密后的密码, real_name VARCHAR(50) DEFAULT NULL COMMENT 真实姓名, role_code VARCHAR(20) DEFAULT NULL COMMENT 角色编码, status TINYINT DEFAULT 1 COMMENT 1启用 0禁用, create_time DATETIME DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE course ( id INT NOT NULL AUTO_INCREMENT, course_name VARCHAR(100) NOT NULL, teacher_id INT NOT NULL, description TEXT, cover VARCHAR(255) DEFAULT NULL, create_time DATETIME DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里我把用户和角色的关联简化成了role_code字段工程上这叫冗余设计。正规项目我会建一张关联表课程设计里为了简化复现用一个角色编码字段也能满足需求各有取舍。3. 后端SpringBoot项目从分层到核心接口实现3.1 项目分层与配置文件一个清晰的项目结构能救命。我习惯这样分包com.example.teachingsystem ├── controller ├── service │ └── impl ├── mapper ├── entity ├── dto ├── vo ├── config ├── common │ ├── Result.java │ ├── JwtUtils.java │ └── GlobalExceptionHandler.java └── TeachApplication.javacontroller只做参数接收和结果返回service处理业务逻辑mapper做数据库交互entity对应表结构dto是接口入参vo是出参。很多初学者把业务逻辑写在controller里越写越乱。这个分层习惯一旦养成后面接手任何SpringBoot项目都不会迷路。application.yml配置里有几个重点server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/teach_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse username: root password: 123456 servlet: multipart: max-file-size: 200MB max-request-size: 200MB mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.teachingsystem.entity configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl jwt: secret: your-256-bit-secret-key-please-change expire-hours: 24password这里只是示意正式项目要用环境变量注入绝对不能把真实密码提交到代码仓库里。map-underscore-to-camel-case这个配置特别重要没开启的话数据库的course_name字段映射不到实体的courseName属性上查询结果全是null这种问题很难排查。log-impl配成StdOutImpl可以在控制台打印SQL调试阶段非常有用开发完建议关掉否则日志刷屏严重。SpringBoot默认内嵌的是Tomcat想换成Undertow或者Jetty也可以改一下starter依赖即可这个属于可选配置一般项目用默认就好。启动时控制台会打印一个SpringBoot样式的Banner想换成自定义图案的话可以找在线Banner生成工具改完只是启动日志花样变了不影响功能纯属个人趣味。3.2 统一响应、异常处理与JWT认证前后端交互最怕格式不统一。我定义一个Result类public class ResultT { private int code; private String message; private T data; // 提供 success / error 静态方法 }所有接口不管成功失败都返回这个结构。前端axios拦截器里只看codecode为200就取data其他情况统一弹错误提示。这个约定在联调阶段能省非常多沟通成本后端改了返回格式前端也不用跟着改。异常处理用RestControllerAdvice加全局异常类捕获业务上发现参数不对或者权限不足就抛自定义异常统一转成Result结构返回。这样就不会出现后端一报错就返回一堆英文堆栈、前端一脸懵的情况。全局异常处理器里还要捕获数据库唯一键冲突、字段过长这类常见异常转成用户能看懂的中文提示。JWT认证实现成两步。第一步是登录控制器根据用户名查出用户、用BCrypt校验密码然后调用JwtUtils生成Token。第二步是写一个拦截器注册进WebConfig拦截所有接口放行登录接口。拦截器里从Authorization头解析Token解析成功就把userId和角色信息放到请求上下文里方便后端业务取出当前操作人。这里有一个我实际踩过的坑拦截器校验Token通过后不要只校验是不是登录用户还要校验是不是有权限做这件事。举例一个学生拿着自己的合法Token去调教师才允许的删除课程接口如果不做第二层校验就会出严重的安全事故。简单做法是自定义一个RequireRole(teacher)注解用拦截器或AOP在进入接口前检查角色代码侵入很小。3.3 MyBatis实战动态SQL、缓存与SQL打印MyBatis是这套系统里技术含量最高也最容易被面试官追问的部分。第一要掌握的是动态SQL。典型场景是课程列表的模糊搜索可能有课程名、教师、学期三个条件。用where标签配合if标签能根据参数自动拼接查询条件避免用字符串拼接SQL导致SQL注入。这里注意一个细节在XML文件里如果用到小于号、大于号必须写成lt;和gt;否则解析会报错这就是网上说的MyBatis等于/小于号怎么写一类问题的由来。select idselectCourseList resultTypecom.example.teachingsystem.vo.CourseVO SELECT * FROM course where if testkeyword ! null and keyword ! AND course_name LIKE CONCAT(%, #{keyword}, %) /if if testteacherId ! null AND teacher_id #{teacherId} /if /where /select第二是缓存。MyBatis有一级缓存和二级缓存。一级缓存默认开启是SqlSession级别的二级缓存需要手动开启是Mapper级别的。这里有一个大坑在同一个事务里第一次查询某条课程记录然后其他会话修改了这条记录一级缓存可能返回旧数据。对实时性要求高的接口比如查询考试剩余时间就不要依赖缓存。面试里问到MyBatis缓存记住一句核心总结一级缓存是会话范围二级缓存是命名空间范围还要说清楚缓存失效的场景这个问题才算答完整。第三是SQL打印。在application.yml里配置log-impl为StdOutImpl后控制台会输出完整的SQL语句和查询参数。很多调半天不知道SQL出了什么问题的场景一看日志就明白了。比如动态SQL条件没生效打印出来的SQL一眼就能定位。3.4 两个核心接口代码解读登录接口我简化后大概是这样的PostMapping(/login) public ResultLoginVO login(RequestBody LoginDTO loginDTO) { SysUser user userService.findByUsername(loginDTO.getUsername()); if (user null || !BCrypt.checkpw(loginDTO.getPassword(), user.getPassword())) { throw new RuntimeException(账号或密码错误); } String token jwtUtils.createToken(user.getId(), user.getRoleCode()); return Result.success(new LoginVO(token, user.getRoleCode(), user.getRealName())); }这里用BCrypt而不是MD5原因很简单MD5撞库太容易BCrypt自带随机盐即使两个用户密码相同加密结果也不同攻击者拿到数据库也没法批量还原。这一点在课程设计文档里可以作为安全亮点写进去。再一个是分页查询课程列表用PageHelper插件public PageResultCourseVO listCourses(int pageNum, int pageSize, String keyword) { PageHelper.startPage(pageNum, pageSize); ListCourseVO list courseMapper.selectCourseList(keyword); PageInfoCourseVO pageInfo new PageInfo(list); return new PageResult(pageInfo.getTotal(), pageInfo.getList()); }PageHelper的本质是在执行SQL之前拦截自动拼接limit语句。用它的关键点PageHelper.startPage后面必须紧跟第一条Mapper查询中间不能有任何其他SQL操作否则分页会失效这是非常典型的坑。比如有人习惯在查询前先查一下当前用户信息分页条件就被消费掉了查出来的列表根本没有分页效果。4. 前端Vue项目环境搭建、路由与接口联调4.1 Node与Vue环境搭建前端工程化第一步是环境。网上大量vue安装及环境配置的求助帖核心原因往往是Node版本不对。我给出经过验证的版本组合Node 16.20.x或18.x搭配npm。Node版本太低Vite 5起不来版本太高又可能遇到部分原生依赖编译问题。用nvm管理Node版本是推荐做法一套命令来回切换能在不同项目间使用不同Node。项目创建我用Vitenpm create vitelatest teach-front -- --template vue cd teach-front npm install npm run dev如果网络不好npm install卡半天可以切换镜像源npm config set registry https://registry.npmmirror.com这里有个小坑Vite默认启动端口是5173后端接口是8080直接访问会跨域。解决方式推荐用Vite的代理而不是在后端开启CORS了事。在vite.config.js里配置export default defineConfig({ plugins: [vue()], server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })这样前端请求地址写成/api/loginVite会自动把请求转发到后端8080浏览器层面没有跨域问题。生产环境部署时再在Nginx里做同样的转发。注意Vue2时代常用vue.config.js加devServer.proxyVue3换用Vite后配置项变了拿着Vue2的教程配Vue3项目会踩空。4.2 路由、状态管理与登录守卫前端路由用Vue Router 4页面组织分三块登录页、公共主页、以角色区分的业务区域。这里最值得讲清楚的是路由守卫。router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (to.meta.requiresAuth !token) { next({ path: /login }); } else { next(); } });思路很简单需要登录才能访问的页面如果没有Token就强行跳走如果已经有Token还去登录页直接放回首页。再进一步可以配合路由meta里的角色信息比如teacher路由配置meta{ requiresAuth: true, role: teacher }在守卫里拿出来判断角色防止学生直接改URL进入教师管理页。这种URL级权限是前端的第一道防线但真正的权限控制后端必须再做一次这个我在第3章强调过。Vue3的状态管理推荐Pinia比Vuex轻量很多。用户登录成功后把用户信息和Token同时存到Pinia和localStorage。Pinia负责当前会话的响应式状态localStorage负责刷新后恢复。刷新时在App启动阶段从localStorage读一次并更新Pinia这叫初始化同步不做这一步一刷新页面用户就丢失了。路由传参是容易混淆的点。query方式参数会出现在URL中比如/detail?courseId1刷新页面参数还在适合不敏感、可分享的链接params方式在Vue Router 4里要配合动态路由配置比如/detail/:id刷新后参数也不会丢但取参方式不同。我建议对课程详情、作业详情这类资源跳转统一用动态路由加params参数语义更清晰分享链接也不会带一堆query串。4.3 axios封装与前后端联调接口请求统一封装是前端代码不爆炸的前提。在src/utils/request.js里做import axios from axios; import router from ../router; const request axios.create({ baseURL: /api, timeout: 10000 }); request.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers.Authorization token; } return config; }); request.interceptors.response.use( response { const res response.data; if (res.code 200) { return res; } if (res.code 401) { localStorage.removeItem(token); router.push(/login); } return Promise.reject(res); }, error { return Promise.reject(error); } ); export default request;这里把baseURL设置成/api正好对应Vite代理的路径。后端接口也统一加/api前缀联调时前后端只需要对这个前缀达成一致其余字段格式看同一个接口文档就行。401表示Token过期前端统一踢回登录页这是大部分系统都会用的策略。整个封装完成之后业务页面里就不用关心Token和错误弹窗了代码清爽很多。4.4 页面组件与视频播放的实现要点页面编码过程中有三个地方值得单独说。第一个是表格列里的操作按钮。课程列表每行都有编辑删除查看按钮如果每个按钮写成一行独立代码代码会非常冗余。Vue的插槽语法在这里很好用el-table的列里定义插槽插槽里放按钮按钮触发各自处理函数。这样同一套操作模板可以复用在作业列表、学生列表里维护时只改一处。这就是Vue插槽机制最常见的实际应用场景。第二个是视频播放。教学系统的课程资源里视频是最常见的形式。MP4格式用原生video标签解决。m3u8这类切片视频用hls.js一个很简单的封装video idplayer controls/video script import Hls from hls.js; if (Hls.isSupported()) { const hls new Hls(); hls.loadSource(videoUrl); hls.attachMedia(document.getElementById(player)); } /scripthls.js是纯前端解析不需要额外安装浏览器插件。这个方案在做课程视频模块时反复验证过稳定且实现简单。要注意的是视频请求路径要能通到后端资源目录建议后端单独做一个/resource/视频的映射接口前端拿到的就是可直接播放的URL。第三是考试页面。考试是交互逻辑最复杂的页面用倒计时组件加题目切换组件实现。倒计时用定时器每秒减一到零自动提交。这里有个坑如果直接依赖每秒减一学生切到别的浏览器标签页后台标签页的定时器会被浏览器降频甚至暂停导致倒计时变慢。稳妥做法是进入页面时记录开始时间戳倒计时用当前时间减去开始时间计算而不是傻傻地每秒减一。这个小细节能在演示时避免一场事故。5. 部署全流程与常见问题排查5.1 本地部署五步走拿到源码之后按下面顺序操作基本不会错。第一步准备数据库。先在MySQL里建一个teach_db数据库注意字符集选utf8mb4再通过source命令或者数据库客户端工具运行项目里的teach_db.sql文件把表和初始数据都导入。初始数据我会预置一个管理员账号、两个教师账号、三个学生账号方便直接登录测试。如果你在Windows上装MySQL时发现安装器没有Develop这类选项不用慌只要能装上MySQL Server并启动服务就能用选项名称因版本而异。第二步配置后端。打开application.yml改成自己本地的MySQL账号密码。在开发工具里直接运行TeachApplication启动控制台看到Tomcat started on port(s): 8080说明后端起来了。后端启动时默认会打印一个SpringBoot样式的Banner这个就是网上那些springboot banner在线制作相关的功能实际只影响启动日志观感不影响项目功能。第三步启动前端。在前端目录执行npm install安装依赖然后npm run dev看到Vite提示localhost:5173就能访问页面。如果端口被占用检查是不是开了多个前端实例或者把5173改成其他端口。第四步联调验证。用预置账号登录走一遍浏览课程、进入详情、播放视频、提交作业、查看成绩的流程。这一步能发现接口访问不到的配置问题比如代理失效、Token没带上等。第五步如果要打包上线。后端执行mvn clean package打成jar包用java -jar运行前端执行npm run build生成dist目录里面是纯静态文件扔给Nginx或者放到后端项目的static目录下都可以。5.2 部署中的高频报错速查表我把运行过程中经常出现的报错整理成表方便直接对照报错现象大概率原因解决方案数据库连不上Access denied账号密码错误或授权没开检查application.yml重新授权账号Public Key Retrieval is not allowedMySQL8驱动连库未授权连接串加allowPublicKeyRetrievaltrueInvalid bound statement (not found)Mapper XML未扫描或namespace错误检查MapperScan和XML的namespaceFailed to load tsconfig vue/tsconfig/...Vue3 TS项目模板配置缺失重装依赖检查tsconfig扩展路径npm安装node-sass失败Node版本过高或镜像源问题改用dart-sass设置npmmirror源Vite显示页面但接口404代理没生效或后端没启动检查vite.config.js代理和后端端口前端页面空白控制台CORS报错生产环境跨域Nginx配置proxy_pass或后端开启CorsFilterSpringBoot启动失败找不到主类JDK版本不匹配确认JDK8或统一JDK17上传课件超过大小限制默认限流1MB在配置里调大multipart限制页面加载慢CPU占用高数据库连接未释放检查连接池配置生产用HikariCP默认值即可这里补充两点MySQL的实战经验。第一如果之前装过MySQL后来又卸载了重装时容易初始化失败大概率是残留的数据目录和注册表服务没清理干净卸载后要把数据目录一并删掉再装。第二MySQL 8.0默认认证插件是caching_sha2_password旧版驱动会出现连不上或者Public Key Retrieval的报错连接串加参数解决。这两个问题在Windows上装MySQL时非常高频提前知道能省很多时间。5.3 服务器部署与数据备份的实用建议真正上线到服务器和本地跑通完全是两码事。我建议按下面这几点做。第一前端用Nginx托管同时做反向代理server { listen 80; server_name your-domain.com; location / { root /www/teach-front/dist; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; } }这套配置同时解决了两个问题前端路由的history模式在刷新时容易404try_files把请求统一指向index.html接口请求通过/api前缀转发到后端避免跨域。如果你用了Vue的history路由又没有配try_files刷新页面经常出现白屏或404问题就出在这里。第二数据库一定要定时备份。教学系统里成绩数据极其重要用mysqldump写个定时脚本每天凌晨备份一次mysqldump -uroot -p123456 teach_db /backup/teach_db_$(date %Y%m%d).sql第三日志文件按天滚动。SpringBoot默认只输出到控制台部署时用logging配置把日志写到文件保留最近30天出现问题时能快速排查。不要把日志和代码放在同一目录不然日志涨满磁盘会影响服务运行。最后分享一点我个人反复验证过的体会。做这种前后端分离的教学系统核心不是把某个接口写得多花哨而是把用户、课程、作业、成绩这条业务链路理顺。我第一次接触类似需求的时候先画了三张图一张权限图、一张课程资源层级图、一张成绩数据流转图然后才开始写代码。事实证明这比直接上手编码省了至少一半返工时间。如果你打算拿这个项目做课程设计或毕业设计强烈建议也先做这个动作。部署过程中如果遇到上面没覆盖到的问题把启动日志和控制台报错完整贴出来定位绝大多数的坑都能在SpringBoot和Vue这套成熟技术栈的社区问答里找到答案。这套组合最大的优势就是生态成熟别人踩过的坑基本都有前人总结关键是你得学会看日志而不是把报错整段截图就完事。耐心按日志一层层排查问题总能解决。