每年到这个节点总有同学在群里问宿舍管理系统怎么做。市面上的教程要么只有零散代码要么数据库脚本和实体类对不上要么压根跑不起来。我去年完整做了一套基于SpringBootVueMySQL的学生宿舍管理系统从设计数据库到写接口、做页面、最后打包部署、写论文一条龙走完也拿了个不错的成绩。这篇就按“一个完整交付物”的标准把源码结构、数据表设计、前后端核心实现、部署流程和论文写作要点全部拆开讲希望能帮到正在做类似题目的同学。无论你是刚接触SpringBoot的全栈新手还是需要参考一套完整毕业设计工程的同学这篇文章里的思路和坑都值得你看完。1. 项目整体设计思路与需求拆解1.1 宿舍管理系统的业务边界学生宿舍管理系统一听名字很普通但它是典型的“业务边界清晰、角色分明、CRUD齐全”的项目非常适合毕业设计。我建议先把角色和业务流程想清楚再去谈技术。我设计的系统分了三种角色管理员负责宿舍楼、房间、床位的维护管理学生入住退宿发布公告处理水电费录入分配维修单。宿管员可以查看管辖楼栋的入住情况处理学生发起的报修登记来访或者日常检查结果。学生查看公告、查看自己宿舍信息、提交报修、查询水电费、查看个人资料。这样划分之后每张表、每个接口的归属都非常清楚。比如报修单的流程是“学生提交 - 宿管员查看 - 管理员指派维修 - 学生确认完成”整条链路串起来既有状态流转又能体现业务逻辑比单纯的增删改查更有东西可写。1.2 为什么选SpringBootVueMySQL这套组合选型这事我在论文里也花了不少篇幅解释。当时备选方案有几套最简单的可以用JSPServlet最“花哨”的可以上前后端分离加Redis加消息队列。但毕设不是生产环境讲究的是“技术覆盖面和实现成本的平衡”。SpringBoot的优点在于快速搭建、约定优于配置、内置Tomcat写一个接口从新建到跑起来可能只要几分钟。Vue则让前端具备组件化开发能力尤其是配合Element UI之类组件库几行代码就能渲染出一个像样的管理后台表格页面。MySQL是应用范围最广的关系型数据库网上教程、资料、报错解决方案几乎全覆盖遇到问题不至于孤立无援。这套组合下导出的交付物非常明确后端是SpringBoot工程源码前端是Vue工程源码数据层是SQL脚本再加上论文和部署文档正好对应题目里的“源码数据库论文部署文档”。毕设答辩时老师只要问“为什么用SpringBoot不用SSM”“前后端怎么交互的”“数据库为什么这么设计”都能有清晰答案。2. 数据库设计从需求到表结构数据库是整套系统的地基。我见过太多同学先写代码再补表结果实体类跟字段对不齐联调时各种报错。正确顺序应该是先梳理实体关系再落地表结构最后用代码生成或者工具同步。2.1 核心表的设计细节我的库名定为dormitory_db核心表大概这些表名用途关键字段sys_user用户账号表id, username, password, role, statusstudent学生信息表id, student_no, name, gender, phone, building_id, dorm_id, bed_no, statusbuilding宿舍楼表id, building_name, floors, managerdormitory宿舍房间表id, building_id, room_no, floor, bed_count, current_count, statusrepair报修表id, student_id, title, content, create_time, status, handlernotice公告表id, title, content, publish_time, publisherfee水电费表id, dorm_id, water_fee, electricity_fee, year_month, statuscheck_record查寝记录表id, student_id, date, status, inspector学生表和宿舍的关系我刻意在student表里冗余了building_id和dorm_id两个外键字段。为什么冗余因为查学生列表时要频繁展示“住在几号楼几零几”如果每次都join三张表虽然也能查但逻辑分散而MyBatis-Plus查出来直接映射就行。为了应对极端情况我又在student表建了联合唯一索引(building_id, dorm_id, bed_no)防止同一张床被安排两个人入住这个索引后面可以写进论文的“数据库完整性设计”部分。2.2 表设计里的几个关键取舍首先是用户表到底要不要单独放。我的做法是sys_user只存账号密码和角色学生表单独存详细信息通过student_id关联sys_user。好处是登录模块只关心sys_user不需要把学生表的字段全部加载进来密码字段也不会在查询学生信息时被无意暴露。角色这块我没用spring security那套复杂的RBAC直接用一个role字段区分毕业设计足够还能少写不少配置。其次是逻辑删除字段。我在每张核心业务表都加了deleted字段默认值为0删除数据时改为1。这样做的好处是论文里可以写“采用逻辑删除保留历史数据便于追溯”而且面试官问起来也能解释清楚。但坑也有逻辑删除会让表的唯一索引失效比如一个学生被“删除”后再重新录入如果唯一索引还是(student_no)第二次插入就会冲突所以我后来把唯一索引调整成了(student_no, deleted)确保删除后的记录不会阻挡新数据插入。3. 后端开发SpringBoot核心实现3.1 工程结构与分层设计我的后端工程结构是标准的四层结构包路径大致如下com.example.dormitory ├── controller // 接口层 ├── service // 业务层接口实现 ├── mapper // MyBatis-Plus的Mapper接口 ├── entity // 实体类对应数据库表 ├── dto // 接收前端参数的DTO ├── vo // 返回前端数据的VO ├── config // 配置类跨域、拦截器、MyBatisPlus分页插件 ├── common // 公共类统一返回结果、异常处理 ├── utils // 工具类JWT工具等分层的目的不是为了好看而是为了让业务逻辑复用。比如宿管员查询学生列表和管理员查询学生列表其实底层都是同一个service方法只是在controller层做了权限校验加了不同参数。如果全写在controller里后面改个排序规则就要改两个地方非常容易漏。3.2 登录鉴权与JWT实现登录这块我用的JWT方案流程是前端把用户名密码POST到/auth/login接口后端校验通过后生成一个token返回前端后续所有请求都在请求头里带上Authorization: Bearer token后端通过拦截器解析token获取用户信息。JWT工具类里有三个方法需要重点关注生成token、解析token、判断token是否过期。token里我放了userId、username、role三个信息过期时间设置成24小时。这样拦截器里只要把token解析出来把用户信息塞进ThreadLocal后续业务代码就能随时取当前登录人。这里要提醒一个坑SpringBoot版本不同JWT依赖的引入方式也不同。如果你用的是SpringBoot 3.xjavax.servlet要换成jakarta.servlet老教程里的代码直接复制过来会报找不到包。我当时用的SpringBoot 2.7.x配合JDK8依赖冲突最少各种教程也都兼容。所以如果你对版本敏感度不高建议直接上SpringBoot 2.7.18别去追新稳定最重要。3.3 业务接口与统一返回格式所有接口我都遵循RESTful风格列表查询用GET新增用POST修改用PUT删除用DELETE。返回格式统一封装成Result对象结构是code、message、data三个字段前端axios拦截器统一处理public class ResultT { private Integer code; private String message; private T data; // 省略getter/setter }这样前端拿到后端返回的数据后不用对每个接口单独判断成功失败。我做了全局异常处理器RestControllerAdvice业务异常直接抛自定义BusinessException全局处理器统一封装成Result返回不会让异常堆栈直接暴露给前端。这个设计在论文里能单独写一节“统一异常处理机制”答辩时很好讲。分页查询用的是MyBatis-Plus的分页插件。特别注意SpringBoot 3.x下需要加Configuration配置分页拦截器而且MyBatis-Plus版本要匹配。我用的MP版本是3.5.3.1兼容性刚好。分页参数我固定用pageNum和pageSize前端表格组件正好对应。4. 前端开发Vue页面与接口对接4.1 环境搭建与项目初始化前端我用的是Vue 2 Vue CLI 4 Element UI这套组合虽然不如Vue 3新但网上资料海量而且Element UI的表格、表单、弹窗组件对管理后台来说特别顺手。如果你选Vue 3搭配Element Plus也可以但要注意组件API有差异比如插槽用法和事件名变化别混着看教程。环境搭建时最容易翻车的是node版本。Vue CLI 4对Node版本要求是10~14你在Windows上如果装了Node 18以上npm install会报各种ECONNRESET或者openssl错误。我当时折腾了很久最后装了nvm来切Node版本用12.22.12跑Vue CLI 4项目一次通过。这个建议写在部署文档里能帮别人少走很多弯路。4.2 路由与权限控制前端路由用了vue-router在路由配置里给需要登录的页面配上meta: { requiresAuth: true }。全局前置守卫里每次跳转先判断有没有token没有就跳登录页有就放行。然后根据用户角色动态决定显示哪些菜单比如学生端只显示公告、报修、水电查询不显示宿舍管理。菜单这块我用的是侧边栏加路由表联动的方式先定义一个菜单数组菜单项的path和路由的path保持一致然后v-for渲染。这样有个好处同一套代码管理员登录看到的菜单和学生看到的菜单不一样视觉效果上就变成了“两个系统”实际代码却完全兼容。答辩时老师问“多角色怎么处理”这段就是现成的答案。4.3 页面实现与接口联调我先做的是登录页登录成功存token和用户信息到localStorage然后跳转到首页。首页是一个layout框架左侧菜单、顶部导航、右侧内容区。模块页面基本套路都一样进入页面调列表接口表格渲染点击新增弹表单提交后重新加载列表。axios封装这块也要说下。我在utils/request.js里创建axios实例配置baseURL为后端的地址比如http://localhost:8080/api然后加请求拦截器往header里塞token响应拦截器里判断result.code是否为200不是就弹Message.error。这样业务代码里只需要关注数据本身不用每个页面都写一遍状态判断。跨域问题我在后端的config里配置了CorsFilter允许本地开发的前端端口访问上线后交给Nginx做反向代理就彻底不用管跨域了。5. 项目部署本地运行与服务器上线5.1 本地环境部署流程部署文档我写成了一份可以直接照做的步骤分三部分数据库导入、后端启动、前端启动。数据库部分在MySQL 5.7以上版本执行dormitory_db.sql脚本注意字符集要设置成utf8mb4否则中文全变问号。我见过很多同学直接双击运行sql文件结果因为文件编码是UTF-8而客户端默认GBK出现乱码甚至语法错误。正确做法是用Navicat或命令行source执行执行前先执行SET NAMES utf8mb4;。后端启动修改application.yml里的数据库账号密码和端口直接运行DormitoryApplication主类。SpringBoot内置Tomcat默认端口8080如果被占用就改成8081。这里要注意如果MySQL装在Windows上并开启了大小写敏感配置表名和字段名对不上就会报Table not found最好保持表名统一用小写。前端启动进入vue目录安装依赖npm install再npm run serve默认跑在8080端口。开发模式下通过Vue CLI的proxyTable代理把/api开头的请求转发到后端8080这就能正常联调。5.2 生产环境部署方案生产环境我用的是一台Linux服务器加宝塔面板。后端打包成jar包前端打包成dist目录最终访问架构是Nginx监听80端口静态文件直接由Nginx托管/api开头的请求反向代理到SpringBoot的8080端口。Nginx里关键的配置就是location /api { proxy_pass http://127.0.0.1:8080; }注意proxy_pass后面的URL不要带路径否则转发时前缀会被改写。我把这套配置写成了一节面向完全没有服务器经验同学的“傻瓜式部署”包括怎么开放安全组端口、怎么用JDK17跑jar包、怎么把前端dist目录上传到指定站点目录。部署文档的作用不是展示自己多会用Linux命令而是让拿到这套资料的人能真的把项目跑起来。5.3 打包过程中的教训打包最大的坑是前端请求地址写死了。如果你在axios里写了http://localhost:8080/api那么部署到服务器后用户浏览器会在自己电脑上找localhost接口全挂。正确做法是用相对路径/api开发时靠proxy转发线上靠Nginx转发这样无论在哪个环境都不用改代码。后端的坑是打包时resources目录下的配置文件如果用了外部配置覆盖jar包启动会报找不到配置。我的做法是配置文件全部放在resources里用maven打包打包后先在本机java -jar启动一遍确认没问题再传到服务器。上传之后用nohup java -jar dormitory.jar log.txt 21 启动日志输出到文件排错也有依据。6. 常见问题与排查实录6.1 后端常见报错报错信息原因解决方案Access denied for user rootlocalhostMySQL账号密码不对或host限制检查application.yml配置确认密码和MySQL授权hostUnknown column deleted in where clause实体类用了逻辑删除但表没该字段建表SQL补上deleted字段并设为默认0Failed to determine a suitable driver class驱动或数据源配置不完整检查pom.xml是否包含mysql-connector-java检查url格式Cannot load driver class: com.mysql.cj.jdbc.Driver老版本驱动类名错误用mysql-connector-java 8.x版本驱动类名用com.mysql.cj.jdbc.DriverHikariPool-1 - Exception during pool initialization数据库服务没启动或密码错误先去命令行测试mysql -u root -p能否登录再检查配置时间字段总是比北京时间早/晚8小时时区配置问题JDBC url加serverTimezoneAsia/Shanghai6.2 前端常见报错前端最头疼的问题是npm install那一关。千万不要一上来就跑npm install先确认三件事Node版本是否匹配、是否设置了npm镜像源、项目目录下有没有package.json。如果报错信息里有gyp ERR基本都是node-gyp编译原生模块失败要么换Node版本要么升级node-sass为dart-sass。Vue项目还有一类经典问题页面能打开但接口全403。排查思路是打开F12看网络请求如果请求头里没有Authorization字段就是axios拦截器没生效如果有token但后端报401/403那就是后端的JWT拦截器把登录接口也拦截了。正确做法是在拦截器排除配置里把/login和/error排除掉。6.3 数据库相关常见问题MySQL这块的坑比较隐蔽。比如中文乱码要找三个位置数据库字符集、表字符集、连接字符串里的characterEncodingutf8mb4。三个地方必须一致否则总有一个环节会出错。还有一次我把导入SQL脚本放到宝塔上执行提示Unknown collation后来发现是SQL文件里写了utf8mb4_0900_ai_ci这是MySQL 8.0才有的排序规则MySQL 5.7下根本不认识。解决办法是把排序规则改成utf8mb4_general_ci。7. 论文写作与答辩准备7.1 论文结构怎么搭论文的章节安排直接影响答辩印象分。我的论文章节是绪论、相关技术介绍、系统需求分析、系统设计、系统实现、系统测试、总结与展望。很多同学把重点放在技术介绍上罗列一堆SpringBoot和Vue的官方文档内容这其实很浪费篇幅。老师真正想看到的是“你做了什么决策、为什么这么决策”而不是“Spring Boot是什么”。在系统设计章节我把ER图、用例图、功能模块图都画得非常细致数据库设计里每一张表都配上字段说明表格。答辩现场老师翻开论文看到表格比看到大段文字更愿意认真看对你的好感度提升非常明显。7.2 答辩准备的核心问题答辩时极大概率被问到的问题我提前整理了出来登录流程怎么实现的为什么密码要加密加密方式是什么前后端如何实现跨域访问数据库为什么这么设计是否有缓存报修单的状态是怎么流转的如果数据量大了怎么办这些问题都需要能从自己的代码里举例子而不是背概念。比如“数据量大了怎么办”我的回答是当前系统用MySQL单机存储通过分页查询限制单次返回条数如果后续数据量增长可以在student和repair表上按时间加索引也可以引入Redis缓存热点数据比如公告列表和宿舍空闲房量。这个回答既承认了工程的局限又给出了可扩展的方向比硬吹自己用了分布式架构要诚实且有逻辑。在论文里我还专门加了一节“系统测试”写了测试环境、测试用例表、功能测试结果、性能测试摘要。性能测试我只用了JMeter简单压了一下登录接口100并发下平均响应时间在80ms以内这个数据虽然不复杂但足以证明系统的基础稳定性。最后补充几个忍不住想说的经验第一别太追求代码量。宿舍管理系统这种题目核心功能做到完整、界面做到整洁、文档做到规范基本就是优秀区间。那些动不动堆几万行代码的同学反而容易在答辩时说不清楚自己写的是什么。第二版本选择上要克制。SpringBoot 2.7.18加Vue 2加MySQL 5.7是经过大量验证的稳定组合新手能避开很多版本坑。如果你身边有人用SpringBoot 3.0踩了一周坑最后把JDK、各种依赖全换了一遍那纯属自己给自己挖坑。第三部署文档一定要自己照着完整走一遍再交付。我认识很多人写完部署文档后从没试过从零部署结果发给别人后第一步就卡住。你自己实际操作一遍把每一步执行命令的真实输出、每个配置项的位置都截图确认拿到手的人才能真正跑起来这一点比写多少字都有用。用心把这些细节补齐不管你是自己用还是要参考这套思路去重新做都不会亏。