SpringBoot+Vue+MySQL宿舍管理系统:全栈实战与部署指南
1. 项目概述与需求分析1.1 这个系统能解决什么问题学生宿舍管理系统听名字就知道是干什么的管宿舍、管学生、管入住、管报修。但我见过太多学校的宿舍管理还在用Excel表格加微信群的方式学生报修靠接龙查个宿舍信息要翻半天聊天记录月底统计入住率更是噩梦。这套SpringBoot后端Vue前端MySQL的系统说白了就是把宿舍管理的日常操作全部搬到线上做成一个B/S架构的Web应用。项目标题里写了【可直接运行】说明作者的定位很明确——不是让你从头造轮子而是拿一套完整可跑的代码去学习、去改造、去落地。适合三类人一是计算机专业的学生拿来做毕业设计或课程设计代码结构清晰方便二次开发二是刚学完SpringBoot和Vue、想找个全栈项目练手的开发者可以从这套代码里学到前后端怎么配合、接口怎么设计、权限怎么控制三是学校或企业的信息化管理人员想了解一个完整的管理系统该具备哪些模块用来做需求预研或供应商评估。1.2 技术栈选型背后的理由这个项目选了SpringBoot Vue MySQL三件套非常典型也非常务实。SpringBoot是目前Java后端开发的事实标准简化了配置内嵌Tomcat一键启动你不用像以前用SSH框架那样写一堆XML。Vue作为前端框架组件化开发让页面逻辑清晰配合Element UI这样的组件库能快速做出像样的管理后台界面。MySQL则是最常用的开源关系型数据库免费、稳定、资料多学生和中小企业首选。我接触过不少类似的毕设项目有的用JSP Servlet有的用PHP但体验和可维护性确实差一截。SpringBoot Vue这套组合的生态太成熟了遇到问题搜一下解决方案基本都是现成的。而且前后端分离的模式也是目前企业开发的标配学这一套东西往后找工作面试也能用到。2. 后端核心设计与业务模块拆解2.1 SpringBoot工程结构与分层这套项目的后端采用经典的三层架构Controller、Service、Mapper或者叫Repository。Controller负责接收前端请求、参数校验、返回结果Service写业务逻辑Mapper层做数据库操作。三层分开的好处是职责明确、便于维护如果以后要改业务规则只需要动Service层不用动接口。代码里会看到一些基础包结构config放配置类比如跨域配置、MyBatis-Plus分页配置entity或pojo/domain放数据库实体类dto放数据传输对象比如登录时接收用户名密码、注册时接收学生信息vo放返回给前端的视图对象common或util放统一返回结果类、异常处理类、工具类。这里有个很值得学习的点统一返回结果。项目里通常会定义一个Result类里面包含code状态码、msg提示信息、data数据三个字段。前端拿到响应后先判断code是否为200再做后续操作。这样做的好处是前后端接口联调时有统一的规范不至于一个接口返回一个样。2.2 核心业务模块梳理一个完整的宿舍管理系统通常包含以下模块第一是登录认证模块。系统里至少有三种角色管理员、宿管员、学生。管理员能管所有东西宿管员管理自己负责的楼栋学生只能看自己的宿舍和报修记录。所以在设计接口时需要做权限控制比如学生角色的请求不能访问管理员接口。第二是基础信息管理。包括宿舍楼栋管理楼栋号、楼层数、每层房间数、宿舍类型、宿舍房间管理房间号、可住人数、已住人数、是否满员、学生信息管理学号、姓名、院系、班级、联系方式、辅导员。第三是入住与退宿管理。学生入住时要选择一个宿舍房间系统自动更新该房间的已住人数退宿时释放床位。这里有一个关键逻辑一个学生同时只能有一条有效的入住记录。为了避免数据混乱代码里通常会在业务层查一下该学生是否已有未退宿的记录如果有则提示“该学生已入住”。第四是调宿管理。学生从一个房间调到另一个房间系统需要同时处理原房间和新房间的人数变更。如果两个房间属于同一楼栋还好如果跨楼栋还得考虑宿管员权限问题。第五是报修管理。学生提交报修工单比如灯坏了、水管漏水填写位置和描述管理员或宿管员查看工单派工处理完成后标记为“已处理”。这个模块虽然简单但涉及状态的流转待处理、处理中、已完成。第六是考勤/归寝管理。这个是宿舍管理的常见需求学生晚归或不归的记录。实际项目里有的会用刷卡或人脸识别设备对接毕设项目通常就是手动记录或学生自助提交。第七是公告管理。管理员发布宿舍通知比如停水停电时间、安全检查通知学生端能看到。还有一个容易被忽略的是数据统计。管理员首页通常要展示一些统计图表宿舍总数、入住总人数、入住率、男女占比、各楼栋入住率等。这些数据不需要额外表通过SQL的group by就能统计出来。2.3 关键技术点登录鉴权与权限控制这个项目的登录鉴权方案常见的有两种一种是基于Session Interceptor拦截器另一种是基于JWT Token。老一点的项目用Session的比较多新的项目一般用JWT。JWT方案的流程是用户登录成功后后端生成一个Token返回给前端前端存在localStorage里每次发请求时通过请求头通常是Authorization带上Token后端在拦截器里校验Token是否合法、是否过期并取出用户信息放到当前请求上下文中。权限控制我建议用基于角色的访问控制RBAC数据库中设计用户表、角色表、权限表以及用户-角色、角色-权限关联表。不过对于毕设或中小型项目做一个简化版就够了用户表加一个role字段值为admin、dorm、student三个枚举值之一后端拦截器判断请求路径前缀和用户角色是否匹配。比如/admin/**开头的路径只能由管理员访问/student/**只能由学生访问。这样实现简单也够用。3. 数据库表结构设计详解3.1 核心表的设计思路MySQL部分是这个项目的地基表结构设计直接决定业务逻辑是否顺畅、SQL是否高效。我的建议是设计时要想清楚表与表之间的关系千万别做出一堆冗余字段也别贪多做一些用不上的表。用户表t_user存储所有登录账号。字段至少要有id、username、passwordMD5或BCrypt加密存储、role角色、user_info_id关联具体用户信息如学生表、status是否启用、create_time。学生信息表t_studentid、student_no学号、name姓名、gender性别、college院系、class_name班级、phone联系方式、user_id关联用户表。宿舍楼栋表t_buildingid、building_no楼栋号比如1栋A栋、name、floors楼层总数、rooms_per_floor、manager宿管员姓名、manager_phone。宿舍房间表t_dormitoryid、building_id关联楼栋、room_no房间号、type比如4人间、6人间、capacity容纳人数、current_people当前已住人数、status如启用/停用。宿舍房间与楼栋是多对一关系。判断一个房间是否可住就用current_people capacity。入住记录表t_recordid、student_id、dormitory_id、check_in_time入住时间、check_out_time退宿时间默认空、status在住/已退宿、调宿时原记录调宿状态。这是最重要的业务表能查出每个学生的住宿历史也能统计当前在住人数。报修表t_repairid、student_id报修人、content报修内容、location位置、status待处理/处理中/已完成、create_time、handle_time处理完成时间、handler_name。公告表t_noticeid、title、content、create_time、user_id发布人、is_top是否置顶。像t_user与t_student为什么要分开建表因为管理员和宿管员不需要学生信息他们也有自己的登录账号。如果强行把登录账号和学生信息放在一张表里会导致大量字段对管理员来说是空着的不优雅也不好扩展。3.2 关键SQL与索引设计宿舍入住统计是最常见的高频查询。比如要统计当前所有楼栋的入住率可以这样写SELECT b.id AS building_id, b.name AS building_name, SUM(d.capacity) AS total_beds, SUM(d.current_people) AS used_beds, ROUND(SUM(d.current_people) / SUM(d.capacity) * 100, 2) AS occupancy_rate FROM t_building b LEFT JOIN t_dormitory d ON d.building_id b.id GROUP BY b.id, b.name ORDER BY b.id;这里用LEFT JOIN保证了即使某栋楼没有房间也能在统计结果里以0的形式出现而不是把该楼栋整行丢弃。ROUND(..., 2)保留两位小数前端展示时好看一些。要给高频率查询字段建立索引。比如t_record.student_id用于查询某学生的住宿记录t_record.status用于筛选在住人员t_repair.status用于统计各种状态的工单数这些都是索引的好位置。MySQL主键默认就是聚簇索引不需要额外处理。对于联合索引比如t_dormitory(building_id, room_no)因为查询某个楼栋下的房间很频繁用联合索引能让过滤条件更精确。事务在这个项目里也派得上用场。比如调宿这个操作把学生在原宿舍的记录标记为调出再插入一条新宿舍的入住记录同时更新原房间的current_people减1、新房间的current_people加1。这几步必须保证“要么全部成功要么全部失败”所以要在Service方法上标注Transactional(rollbackFor Exception.class)。如果不加事务中途某一步抛异常数据就可能变成“学生两边都没住”或者“两边都显示在住”非常难排查。4. 前端核心实现与前后端联调4.1 Vue工程结构与页面规划Vue前端用Vue 3 Vite脚手架更现代也可以用Vue 2 Webpack要看作者怎么选。不管用哪个版本核心思路是差不多的。Vue项目里面通常有一个核心目录结构src/views放页面组件src/router放路由配置src/store如果是Pinia或Vuex放全局状态src/api放接口请求封装src/utils放工具函数。页面规划方面登录页是第一个要做的然后是管理员端的首页仪表盘、宿舍管理页、学生管理页、入住退宿页、调宿页、报修管理页、公告管理页学生端的首页和报修提交页。管理后台的布局跨时代的那一套左侧菜单栏加右侧内容区顶部一个导航栏展示系统名称、当前用户、退出按钮。左侧菜单根据角色动态渲染管理员看到完整菜单学生只看到自己的功能入口。这样权限在功能入口层面就能做到第一道隔离。4.2 Axios封装与接口对接前后端分离的项目前端所有的HTTP请求都要通过Axios发出去。直接在每个页面里写axios调用代码会很碎、重复率高、不好维护。正确做法是封装一个统一的request工具import axios from axios; import { message } from ant-design-vue; 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; } message.error(res.msg || 请求失败); return Promise.reject(new Error(res.msg || 请求失败)); }, error { if (error.response error.response.status 401) { message.error(登录已过期请重新登录); localStorage.removeItem(token); router.push(/login); } else { message.error(网络异常请稍后重试); } return Promise.reject(error); } ); export default request;这个封装做到了三件事自动附带Token、统一处理响应体、全局拦截401跳登录页。页面里只用关心拿到的数据不用每次判断状态码。另一个重要的点是baseURL: /api配合Vite的代理配置避免在开发环境出现跨域问题。在vite.config.js里这样配server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }这样开发时请求/api/login就会代理到后端http://localhost:8080/login浏览器不直接跨域。生产环境则用Nginx做反向代理把前端静态文件放到Nginx同时配置location /api { proxy_pass http://后端地址; }。4.3 权限路由与动态菜单前端动态菜单是个常见考题。后端登录接口可以返回当前用户的角色信息和拥有权限的菜单列表前端拿到后动态注册路由。但这里有个小坑不要完全依赖前端控制权限前端只是隐藏入口真正安全校验还是后端拦截器不然别人直接拼URL也能访问到接口。简单做法是路由表里写静态路由和需要动态注册的路由登录成功后根据角色过滤出可访问的菜单。Pedestrian的做法是写死三种角色的菜单比如const roleMenus { admin: [ { path: /dashboard, title: 首页 }, { path: /student, title: 学生管理 }, { path: /dormitory, title: 宿舍管理 }, { path: /record, title: 入住退宿 }, { path: /repair, title: 报修管理 } ], student: [ { path: /student-dashboard, title: 我的宿舍 }, { path: /student-repair, title: 我要报修 } ] };然后根据当前用户的角色把对应菜单渲染到侧边栏。后端接口返回的role字段就是这里判断的依据。5. 本地快速部署与运行指南5.1 环境准备与配置清单要让这套系统跑起来本地环境需要准备以下工具JDK 8或11SpringBoot 2.x用8最稳SpringBoot 3.x需要17Maven 3.6用来编译打包后端MySQL 5.7或8.0建议8.0字段限制更宽松字符集用utf8mb4Node.js 14Vue项目打包和运行需要一个趁手的IDE后端用IntelliJ IDEA或Eclipse前端用VSCode基础环境装好后做三步初始化第一步在MySQL里创建数据库比如叫dormitory_system执行项目里提供的sql目录下的初始化脚本导入表结构和基础数据。基础数据里通常包含几个测试账号比如管理员账号、宿管员账号、学生账号密码一般是经过MD5或BCrypt加密的。如果导入后发现密码不对可以用注册接口重新注册再测试或者用后端的工具类手动生成加密密码更新到数据库里。第二步修改后端application.yml或application.properties里的数据库连接信息url、username、password。注意server.servlet.context-path这个配置如果设置了前缀比如/dorm那前端的代理也要对应修改。第三步前端需要修改环境变量文件.env.development里的API地址还有Vite的代理目标地址要指向后端启动的端口。5.2 启动步骤与验证清单后端启动很简单用IDE打开项目等待Maven下载依赖第一次会比较慢然后运行DormitoryApplication主类。看到控制台输出“Started DormitoryApplication in x.xxx seconds”就代表启动成功。前端启动需要在项目根目录下执行npm install npm run devnpm install安装依赖如果网速慢或版本冲突可以换用淘宝镜像源。启动后浏览器访问http://localhost:5173Vite默认端口看到登录页就说明一切正常。验证系统功能时按这个顺序走一遍先用管理员账号登录进学生管理页面添加一个新学生再到宿舍管理页面确认房间状态然后给新学生办理入住看房间的已住人数是否加1用学生账号登录提交一条报修工单再切回管理员账号处理这条报修。如果每个环节的数据变化都符合预期说明核心流程是通的。6. 常见问题与排查技巧实录6.1 数据库连接与启动类的坑数据库相关的报错是遇到频率最高的。常见报错之一是Access denied for user rootlocalhost原因基本是密码配错或指定的账号没有远程访问权限。排查方法很简单先在Navicat或命令行里用同样的账号密码试着连一下数据库连不上的话问题在账号密码本身跟代码无关。另一个高频报错是Unknown database dormitory_system说明数据库没有创建或者名字写错了。执行语句CREATE DATABASE dormitory_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;就能解决。还有MySQL连接串时区报错也经常出现。SpringBoot连接MySQL 8.x时url里最好加上这些参数url: jdbc:mysql://localhost:3306/dormitory_system?useUnicodetruecharacterEncodingutf-8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrueserverTimezoneAsia/Shanghai解决时区问题useSSLfalse避免SSL握手警告。这条配置我每次都直接复制印象深刻。6.2 前端跨域、Token失效与打包部署问题前端明明通过代理配置了但还是报跨域请求错误浏览器控制台提示CORS这种情况最先看一眼代理是否指向了正确的后端端口。有时后端前端同时改了端口代理配置忘了同步请求打到别的地方去了。还有一种可能是后端有自己独立的CORS配置二者冲突。建议开发时只用后端全局跨域配置或者只用前端代理别混着用不然排查起来头晕。Token失效的表现症状是“点击某个功能几秒后跳回登录页”同时网络面板里能看到某个接口返回401。靠谱的处理方式就是前面写的响应拦截器里统一捕获401清除本地Token并跳转登录页。这里提醒一下不要只在单个页面处理“登录过期”否则每个接口都要写一遍重复代码。最后说说打包部署。后端打包用Maven的mvn clean package生成target目录下的jar包扔到服务器上执行java -jar dormitory-system.jar即可。前端打包执行npm run build生成dist静态目录交给Nginx托管同时配置代理到后端服务。实际部署时有个细节容易被忽略后端接口服务要监听外网可达的地址比如0.0.0.0前端Nginx代理的目标地址要写后端服务器的内网IP或公网IP。如果只写localhost部署在远程服务器上就访问不到了。还有一个小技巧前端路由用了history模式路由地址没有#号生产环境Nginx需要这样配置否则刷新页面会404location / { try_files $uri $uri/ /index.html; }不然每次用户手动刷新浏览器都会看到404 Not Found这是很多初学者部署后遇到的经典问题。实际使用中我还发现宿舍管理这类系统的数据字典量不大但各宿舍的楼栋、房间数量往往需要灵活调整。如果代码里只有基础的表结构我建议后端的管理员接口里留好楼栋编辑功能而不是每次数据库里手工改这个模块做完之后整体系统维护成本会低很多。