首页 / 资讯中心 / 文章详情

基于SpringBoot+Vue的宿舍管理系统设计与部署全流程解析

基于SpringBoot+Vue的宿舍管理系统设计与部署全流程解析 ★ FEATURED ARTICLE
如果你最近正在为毕业设计选题发愁学生宿舍管理系统大概率已经躺在你的备选清单上了。这个题目不惊艳但它特别稳业务需求贴近真实生活角色划分清晰前后端分离的主流技术栈正好能展示而且从数据库建模到界面交互每个环节都有充足的素材写进论文。我完整跟过一套 SpringBoot Vue MySQL 的宿舍管理系统从源码结构、数据库脚本、论文初稿到部署文档全程走下来今天就把这个过程踩过的点、绕过的坑一一掰开讲。这个题目的价值不在于“新”而在于“全”做完它你对后端的接口设计、前端的权限路由、数据库的表关系都会有一个非常扎实的体感。1. 为什么选这个题目以及系统整体是怎么搭起来的1.1 这个选题的价值在哪毕业设计最怕的不是题目难而是题目空。有的题目看起来高端结果光是环境搭建就折腾一个月有的题目过于简单答辩的时候老师问两句就露怯。学生宿舍管理系统恰好避开了这两个极端。它的业务场景足够具体学生要入住、调宿、退宿宿舍楼里有报修、有访客、有归寝检查管理员要分配床位、发布公告、统计入住率。这些都是宿舍日常管理的真实动作需求分析的时候能写出一大堆用户故事论文里也不愁没有素材。从技术角度看它又是一个非常标准的 CRUD 项目加业务流项目登录鉴权、角色权限、多表关联查询、事务处理、文件上传、数据统计这些后端基本功全部覆盖前端则对应登录页、布局框架、列表页、表单页、统计图表前后端所有常规组件都能练一遍。更重要的是它的业务复杂度可控不会让一个毕业生在两个月内陷入无限改 bug 的泥潭。1.2 技术栈与整体架构我最终采用的组合是 SpringBoot 2.7 Vue 3 MySQL 5.7ORM 用 MyBatis-Plus前端构建用 ViteUI 组件库用 Element Plus状态管理用 Pinia。这套组合在一线开发里非常常见招聘要求里的出现频率也很高拿出来讲不会被认为是“玩具项目”。架构上是标准的前后端分离后端单独启动一个 SpringBoot 服务提供 RESTful API端口 8080前端单独启动一个 Vue 项目开发环境访问 5173通过代理转发/api请求到后端MySQL 单独存储所有业务数据生产环境用 Nginx 托管前端打包后的静态文件同时反向代理后端接口。这里我要重点说一个很多人会搞混的概念前后端分离并不是“两个项目互相独立就行了”而是前端只管页面渲染和交互后端只管数据接口和业务规则。前端不能直接连数据库后端不能返回一堆 HTML 页面。这样分工之后学生端、宿管端、管理员端其实共用一套后端接口只是前端根据角色控制能看到的菜单和能点击的按钮。1.3 交付物清单一个能打高分的毕业设计交付物绝对不是“代码能跑”四个字。我建议大家按这份清单准备完整源码包括前后端两个目录且要求代码可以直接编译运行不要留一堆 TODO数据库初始化脚本包含建库、建表、初始化管理员账号、示例数据毕业论文一般学校要求不低于 8000 字包含需求分析、系统设计、数据库设计、系统实现、系统测试部署文档重点写清楚环境要求、每一步操作命令、常见问题演示视频5 分钟左右的录屏从头登录到核心功能操作一遍答辩放这个非常加分。很多同学把源码当成唯一交付物数据库脚本放在项目里的某个角落部署文档懒得写。等答辩当天老师让你现场部署你才发现自己连数据库连接串都记不清楚这就非常被动。所以下文我会详细展开每一部分怎么做尤其是数据库设计和部署文档这两个容易被轻视的部分。2. 数据库设计才是宿舍管理系统的真正核心2.1 核心业务表有哪些宿舍管理系统听着简单但真正开始整理表结构的时候你会发现业务实体比想象中多得多。我把一套完整的表设计拆出来供参考表名用途关键字段t_user登录账号username, password, role, statust_student学生基础信息student_no, name, gender, college, dorm_id, bed_not_building宿舍楼栋name, floor_count, manager, phonet_dorm宿舍房间building_id, room_no, bed_num, current_num, statust_repair报修工单dorm_id, student_id, category, description, statust_visitor访客登记student_id, visitor_name, phone, in_time, out_timet_attendance归寝记录student_id, date, status, check_timet_notice公告title, content, create_timet_transfer调宿申请student_id, from_dorm_id, to_dorm_id, reason, status这里每一张表都有存在的意义。t_user 和 t_student 为什么要分开因为一个学生账号可以被停用但学生的住宿信息还在管理员的账号和学生根本不在同一个信息维度里。如果不分开后期改密码、加权限的时候会非常别扭。2.2 宿舍、床位、学生三者怎么建模宿舍分配是这个系统里最容易出错的点。很多新手会把“床位数”直接当字段存在宿舍表里然后学生入住的时候手动改一下数字。这样确实简单但它没办法解决一个问题宿舍一共有 4 个床位1 号床、2 号床分别是谁如果不建模到“床位”这个级别你根本无法直观地看到某个宿舍哪张床是空的。所以我建议至少在业务逻辑上把床位看成一个虚拟实体学生表里的bed_no字段就代表这张床属于哪个宿舍、是几号床。分配宿舍的时候要做两步校验宿舍状态必须是“未满”床号在当前宿舍内必须是唯一的。这两步校验要在后端事务里同时完成否则会出现两个学生分配到同一张床的严重并发问题。我在初版实现里就踩过这个坑后来在宿舍分配接口上加了Transactional并且用数据库唯一索引兜底才算真正解决。CREATE TABLE t_student ( id bigint PRIMARY KEY AUTO_INCREMENT, student_no varchar(32) NOT NULL, dorm_id bigint NOT NULL, bed_no int NOT NULL, UNIQUE KEY uk_dorm_bed (dorm_id, bed_no) );这个联合唯一索引就是最后的防线。逻辑上就算代码漏判断数据库也会直接拒绝同一宿舍插入两条相同床号的记录。2.3 状态字段与枚举值的设计宿舍管理系统里有大量状态字段比如宿舍状态、报修状态、归寝状态。状态值我强烈建议用tinyint整数不要直接用中文或者英文字符串。举个例子宿舍状态可以定义为0空置1部分入住2已满3维修中用整数存的好处是查询快、存储小而且前端可以用状态码映射成标签显示。缺点是直接看数据库时不直观所以你要在项目里建一个枚举类统一管理后端返回给前端的时候转成字典值。报修状态我分成“待受理、处理中、已完成、已评价”四个阶段。每一步都有对应时间字段提交时间、受理时间、完成时间。答辩时老师问“你怎么保证报修流程的完整性”你就可以说我是通过状态机加时间戳来记录的。2.4 初始化数据脚本里容易忽略的细节数据库初始化脚本不是随便建几张表就完事。我见过很多同学的init.sql只建表不插入任何数据导致系统一登录就是空的看不到任何效果。正确的做法是准备三部分数据必填的基础字典数据管理员账号、角色菜单、状态枚举说明示例业务数据5 栋楼、每栋楼若干宿舍、20 个学生分布在部分宿舍里、若干条报修和归寝记录边界测试数据一个已满的宿舍、一个维修中的宿舍、一个没有任何学生的空楼栋。有了这些数据前端页面不用费劲造数据就能直接展示效果论文里的功能性测试也能直接跑起来。另外要注意 MySQL 5.7 和 8.0 的建表语法差异如果脚本里用了DEFAULT CURRENT_TIMESTAMP8.0 对同表多个时间戳字段的默认值要求更严格环境切换时容易报错。3. SpringBoot 后端从登录鉴权到业务闭环3.1 目录分层别偷懒后端项目结构直接影响你后面写论文和答辩的流畅度。我用的分层是com.example.dorm ├── controller // 接口层只负责参数接收和结果返回 ├── service // 业务逻辑层 ├── mapper // 数据访问层 ├── entity // 数据库实体 ├── dto // 前端传输对象 ├── common // 统一返回结果、异常处理 └── config // 配置类、拦截器controller 里不要写业务逻辑。有的同学把查询、判断、更新全都堆在 controller 里一个方法写几十行看似省了很多类实际上维护起来非常痛苦。你只要记住一句话controller 只做三件事——接收参数、调用 service、返回结果。业务逻辑全部下沉到 service数据访问全部交给 mapper。3.2 登录鉴权JWT 拦截器方案毕业设计项目我不建议引入 Spring Security 全家桶配置量大学习成本高答辩的时候反而说不清楚。更好的选择是 JWT 加自定义拦截器代码量小原理也容易讲明白。思路是这样的登录成功后后端把用户 id、角色、姓名等信息加密成一个 token 返回给前端。前端每次请求在请求头里带上Authorization: token。后端定义一个拦截器对所有非登录接口校验 token解析成功后把用户信息放进请求上下文。Component public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); if (token null || !JwtUtil.verify(token)) { response.setStatus(401); return false; } request.setAttribute(userId, JwtUtil.getUserId(token)); request.setAttribute(role, JwtUtil.getRole(token)); return true; } }角色权限怎么控制很简单在每个 controller 方法上做个RequireRole(ADMIN)注解拦截器里再判断当前角色是否满足要求。这样做的好处是权限规则直接写在接口旁边可读性很高。3.3 典型业务入住、报修、归寝的后端闭环宿舍管理系统里的业务不只是“增删改查”有几条业务流必须要在后端形成一个闭环这是答辩时的加分点。第一个是学生入住。流程是管理员选择学生和宿舍 → 判断宿舍是否未满 → 判断床号是否唯一 → 给学生写入宿舍和床号 → 宿舍当前人数加一 → 若住满则更新宿舍状态为已满。这五个动作必须在一个事务里完成。我建议你把这一段整个写在 service 方法里用Transactional标注。第二个是报修。学生提交报修后由宿管员受理并生成处理记录维修完成后状态改为已完成学生可以查看处理结果。后端接口至少要提供三个提交报修、处理报修、查看历史报修。这三个接口对应三种角色身份正好能体现权限设计的价值。第三个是归寝管理。传统做法是宿管在后台按宿舍楼、按日期录入归寝情况系统后台生成当天未归名单并提供补录和请假接口。统计未归人数时可以用一个聚合查询按日期分组统计这个 SQL 写进论文里也很有说服力。3.4 事务、异常与查询性能我在实际调试中发现最容易出现事务失效的场景是Transactional加在了私有方法上或者在同一个类内部进行方法调用。SpringBoot 的事务是通过代理实现的同类内部调用根本不会经过代理所以事务就失效了。正确做法是要么把需要事务的方法放到不同类里要么直接将事务方法定义为 public。异常处理这块我统一封装了一个ResultT返回体正常返回code200业务异常返回code500并带错误信息。在后端加一个RestControllerAdvice全局异常处理器任何未捕获的异常都会转成统一结构前端就不用疯狂解析各种奇形怪状的报错格式了。查询性能方面学生列表默认要分页并且必须使用连表查询返回宿舍号和楼栋名。MyBatis-Plus 的分页插件配置很简单但要注意在多表关联时不要用Page直接包一个自定义 SQL容易导致 count 查询出错。4. Vue 前端动态菜单、权限路由和页面复用4.1 技术选型为什么用 Vue3 Element Plus前端我用的是 Vue 3 Vite Element Plus Pinia。Vue 3 的组合式 API 写起来比 Vue 2 的选项式更清晰尤其是处理表格查询、分页、弹窗这类业务逻辑的时候setup里所有状态一目了然。Element Plus 的表格、表单、分页、弹窗、标签、上传组件非常齐全几乎覆盖了宿舍管理系统的全部页面需求。你不需要手写复杂的 CSS 布局把精力放在业务逻辑上更重要。4.2 axios 统一封装前端必须封装一个 axios 实例统一处理 baseURL、请求头、超时时间和错误提示。我的做法是创建src/utils/request.js在请求拦截器里自动把 token 从 localStorage 取出来加进请求头在响应拦截器里判断后端返回的 code如果是 401 就跳转登录页如果是业务错误就弹出统一的错误提示。import axios from axios import { ElMessage } from element-plus 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 } ElMessage.error(res.msg || 请求失败) return Promise.reject(new Error(res.msg)) }, error { if (error.response error.response.status 401) { router.push(/login) } else { ElMessage.error(网络异常请稍后重试) } return Promise.reject(error) } )注意开发环境要用 Vite 的代理转发在vite.config.js里配置/api指向http://localhost:8080这样前端代码里就不会写死后端地址后期部署迁移也方便。4.3 一个标准 CRUD 页面怎么写宿舍管理系统里大多数页面都是“表格 搜索表单 弹窗表单 分页”的组合。你会发现这个模式只要写熟练一个后面全都能照葫芦画瓢。以“报修管理”页面为例核心代码逻辑是searchForm保存查询条件比如宿舍楼栋、报修状态每次查询调用getRepairPage接口传当前页码和搜索条件表格绑定tableData分页组件绑定total和pageNum/pageSize点击“处理”按钮弹出携带当前行数据的抽屉或对话框。这里有个小经验凡是带状态的列前端不要直接显示数字应该用一个statusMap对象映射成中文标签再用 Element Plus 的el-tag渲染不同颜色。比如“待受理”用 warning 色“处理中”用 primary 色“已完成”用 success 色。这样视觉上立刻就能区分业务状态不用查数据库看含义。4.4 几个加分的小交互基础 CRUD 谁都会写但以下几个功能能让你的系统在答辩时明显超出预期第一个是仪表盘统计。首页展示总学生数、总宿舍数、当前入住率、今日未归人数用 ECharts 画一个柱状图和饼图。这些数据来自后端一个聚合接口把几行 SQL 统计结果聚合返回技术含量不高但效果非常直观。第二个是导出 Excel。列表页加一个“导出”按钮点击后直接把当前搜索结果全部导出为 Excel 文件。用 EasyExcel 在后端实现代码量很少但在教研室演示时很实用。第三个是公告自动滚动。系统首页轮播最新公告用 Element Plus 的el-carousel组件就行。这个小功能看起来不起眼却能让系统“活”起来而不是一堆死表格。5. 部署交付从本地跑通到写出能照着做的部署文档5.1 环境准备与版本匹配部署文档的第一章必须写清楚环境要求不要默认读者什么环境都装好了。宿舍管理系统最常用的环境是软件版本建议备注JDK1.8 或 11项目 pom.xml 中指定Maven3.6 以上用于打包Node.js16 或 18Vite 5 对 Node 版本有一定要求MySQL5.7 或 8.0注意驱动差异Nginx1.20 以上生产环境托管前端版本坑是最多的。比如某同学本地 MySQL 是 8.0项目里驱动还写着com.mysql.jdbc.Driver启动直接报错必须改成com.mysql.cj.jdbc.Driver并在连接串里加上serverTimezoneAsia/Shanghai。这些坑踩一次就够了文档里一定要提前写好。5.2 前后端打包和启动后端的打包命令非常简单在项目根目录执行mvn clean package -DskipTests打包成功后会在target目录生成一个dorm-server.jar。本地启动就用java -jar dorm-server.jar如果你是在 Linux 服务器上部署别忘了先检查防火墙和端口占用。我遇到过项目在本地跑得好好的一到服务器就报端口被占用结果发现是以前启动的进程没杀掉。前端打包更简单npm install npm run build执行完会在dist目录生成静态文件这就是部署时 Nginx 要指向的目录。要强调一点打包之前一定确认有写后端接口地址的地方是不是用了相对路径api开头如果你在 axios 里写死了http://localhost:8080/api打包后部署到服务器上就全废了。5.3 Nginx 反向代理的配置Nginx 在这套部署里的作用有两个托管前端页面代理后端接口。完整配置可以这样写server { listen 80; server_name your-server-ip; root /usr/share/nginx/html/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }这里最关键的是try_files $uri $uri/ /index.html;。Vue 是单页应用路由在浏览器端控制你直接访问某个子路由时 Nginx 必须把所有未匹配路径都回退到index.html否则一刷新就 404。5.4 部署文档该怎么写部署文档不是给懂行的人看的是给“什么都不知道”的答辩老师或者下一个接手的同学看的。我的建议是写给傻瓜也能照着做每一条命令单独一行执行结果是什么样也写清楚遇到什么报错应该怎么处理也列出来。部署文档结构可以这样组织环境要求表数据库初始化步骤包括直接用 navicat 新建数据库、执行 sql 脚本的过程application.yml 里需要改的配置用截图圈出来后端打包启动命令前端打包步骤Nginx 配置和启动常见问题排查表。我当时还做了一件小事把部署过程中所有的命令整理成一个.sh脚本服务器上直接执行就能一键发布。虽然毕业设计不要求这么细但在项目展示时拿出来讲老师对工程化能力的认可度会明显提高。6. 论文写作与答辩准备的四个关键细节6.1 论文结构怎么排论文结构按学校模板来内容逻辑上我建议务必覆盖这七块绪论、相关技术介绍、需求分析、系统总体设计、数据库设计、系统详细实现、系统测试。很多同学容易犯的错是把相关技术介绍写成名词解释大杂烩。正确的做法是每一段技术介绍都要紧跟“本系统如何用它”。比如介绍 Vue 时不要只写 Vue 是什么还要写“本系统采用 Vue3 构建学生管理模块利用组件化开发封装了宿舍分配弹窗”等具体内容。这样答辩老师才会觉得你是真做了而不是抄了一堆概念。6.2 图表怎么截论文里的图表是整个分数的直接体现。首先是 ER 图用 ER 图把 t_student、t_dorm、t_building 之间的关系画清楚。然后是系统架构图前后端分离的这个架构图一定要画很直观。最后是系统功能结构图按角色分树形结构画出模块。截图的时候不要直接把整个浏览器窗口截下来身边的杂色和标签页都会影响观感。建议用干净的浏览器窗口把地址栏隐藏掉只截内容区域。每个截图旁边一定要加图表编号和文字说明不能用裸图应付。6.3 答辩现场会被追问的问题我把这次毕设展示中可能遇到的问题提前列出来你可以提前准备问题参考回答思路为什么不用 Vue2 用 Vue3组合式 API 逻辑更集中生态逐步迁移新项目选 Vue3 合理JWT token 过期怎么办前端通过 401 识别跳转登录页并清除本地 token可扩展 refresh token 机制报修流程怎么保证数据一致后端在关键环节开启事务状态流转用显式赋值并带时间戳宿舍分配时并发怎么办联合唯一索引加事务先更新再查询系统如何应对数据量变大列表分页加索引统计接口按日汇总后续可引入缓存每个问题都要先讲清楚自己的设计思路不要背答案最好结合系统里的具体界面说明这样更容易让老师相信是你自己做的。6.4 演示 Demo 的注意事项答辩展示环节最忌讳的就是现场“翻车”。我的建议是在答辩前一天把系统的核心功能录一段视频按顺序操作登录、分配宿舍、报修处理、归寝统计这几个场景。演示的时候先用录好的视频放一遍再现场登录系统操作一遍双重保险。另外现场演示一定要用真实数据库里的示例数据不要用空库。如果宿舍列表里一片空白就算代码没有问题也给老师留下“没做完整”的印象。所以init.sql里的演示数据一定要精心准备模拟出一个真实的宿舍楼使用场景。最后补一句个人体会这套项目最花时间的地方不是前端页面的花活也不是后端接口的堆叠而是数据库设计是不是真的贴合业务、部署文档是不是真的能让人照着跑通。很多同学都把数据库脚本放到最后草草补一个结果自己项目换台电脑都跑不起来。宿舍管理系统看起来简单但把简单的事情做到闭环、可展示、可部署本身就是毕业设计最该有的样子。
阅读完成 · 觉得有帮助?
咨询建站