YAOTU INSIGHTS

Java+Vue前后端分离学生宿舍管理系统设计与实战

Java+Vue前后端分离学生宿舍管理系统设计与实战
做宿舍管理系统这个题目其实挺有意思的。我第一次接触这类项目是好几年前帮学弟看毕设当时他拿来的还是一个 JSP Servlet 的老古董版本页面丑不说每次重启 Tomcat 都要等半天。后来我自己也陆陆续续做过几版宿舍管理系统从单体 JSP 到前后端分离的 Spring Boot Vue技术栈换了好几轮踩过的坑能写满一屏。今天咱们就借“学生宿舍管理系统”这个项目把基于 Java Vue 的前后端分离版本从头到尾拆一遍包括项目设计思路、核心模块实现、环境搭建、跑通流程、常见问题排查以及怎么在这个基础上升级成能让老师眼前一亮的作品。这个系统适合谁很明确正在做课程设计、毕业设计的计算机相关专业学生以及刚学完 Spring Boot 和 Vue、想找个完整项目练手的前端/后端初学者。它能帮你把一个经典的业务系统完整跑起来理解前后端如何联调、数据库表怎么设计、权限怎么控制。更重要的是你拿到的不只是一堆源码而是一条能把项目从零启动到交付的完整路径。1. 项目整体设计与思路拆解1.1 为什么“学生宿舍管理”是经典中的经典我见过太多人选课题什么“校园二手交易平台”“在线考试系统”“图书管理系统”说实话这些题目都不是不好而是很多人在做的过程中容易跑偏要么功能堆得太多收不住要么业务逻辑太绕做到一半就卡住了。学生宿舍管理系统之所以经典是因为它的业务边界非常清晰围绕“宿舍”和“学生”这两个核心实体展开入住、退宿、调宿、报修、卫生检查、来访登记等操作。这个业务闭环天然适合做 CRUD但又不止于单纯的增删改查——它涉及到角色权限管理员、宿管员、学生、状态流转报修从提交到完成、统计报表入住率、卫生评分这些恰好是面试官和老师最喜欢问的东西。从课程设计的评分角度来说这种项目也特别讨巧。它的功能点容易展示一打开系统就能看到宿舍楼分布、学生入住情况、待处理报修单演示过程顺畅不怕答辩时手忙脚乱。而且数据模型足够经典稍微改改就能扩展成“员工宿舍管理系统”“公寓管理系统”换皮成本极低。1.2 为什么选 Java Vue 而不是其他组合每次有人问我毕设选什么技术栈我几乎都是同一句话如果你不是对某个冷门框架特别熟选 Java Spring Boot Vue 绝对是性价比最高的。原因有三点。第一生态太成熟了。Java 后端有 Spring Boot、MyBatis-Plus 这一套组合拳社区资料多到什么程度你随便搜一个报错基本都能找到现成的解决方案。Vue 前端有 Element UI/Element Plus 这种组件库表格、表单、弹窗、分页全都现成写页面主要工作变成了“拼接组件”而不是“从零造轮子”。第二它“前后端分离”的架构很标准这在简历上是加分项。很多管理系统项目还在用 Thymeleaf 或者 JSP页面和后端逻辑耦合在一起你写起来是快但面试官一问“你们前后端怎么交互的”你就容易露怯。Java Vue 这套组合天然就是分离的前端跑在 8080 端口后端跑在 9090 端口中间通过 JSON 交互这种架构本身就是一种很标准的工业级实践。第三文档和源码质量通常有保障。像这种流传很广的管理系统项目基本都是经过多轮迭代的结构相对规范化命名也清晰适合拿来学习而不是纯粹为了跑通。1.3 模块划分角色不同看到的界面就不同这个项目的核心模块划分我建议按照“三种角色 公共功能”来理解。管理员是最高权限负责基础数据维护管理宿舍楼、宿舍房间、学生信息、宿管员账号还能查看全院的入住统计。宿管员是日常业务的主要操作者处理学生入住、退宿、换宿申请登记维修工单记录每日查寝情况录入卫生检查评分。学生是系统的最终用户登录后能查看自己的宿舍信息提交报修申请查看通知公告偶尔还能给卫生评分提意见。这种角色化设计的价值在于它让你的表结构天然是“多对多”的关系比如学生和宿舍的关系就是通过“入住记录表”来维护的而不是在学生表里加一个“宿舍ID”字段。这个细节在答辩的时候一说出来老师就知道你不是只写了几个 CRUD 页面而是思考过业务模型的。1.4 数据库设计表之间怎么关联才算合理数据库是整个系统的地基地基没打好后面全是雷。我做这个项目的时候核心表大概有这些用户表sys_user账号、密码、姓名、手机号、角色类型admin/housemaster/student宿舍楼表dorm_building楼栋名称、楼栋编号、楼层数、宿管员ID宿舍房间表dorm_room所属楼栋ID、房间号、床位数、已住人数、房间状态学生表student学号、姓名、性别、班级、联系电话、用户ID入住记录表checkin_record学生ID、房间ID、入住时间、退宿时间、入住状态报修表repair_order报修人ID、宿舍房间ID、报修内容、状态、处理人、处理时间卫生检查表hygiene_check检查人ID、宿舍房间ID、评分、检查日期、备注通知公告表notice标题、内容、发布人ID、发布时间我最想强调的是学生表和用户表为什么要分开。很多新手会偷懒直接在用户表里把学号、姓名、班级全塞进去美其名曰“简化设计”。但这样做的后果是一旦用户模块要做权限扩展或者学生信息需要批量导入就非常痛苦。分开之后用户表只管登录鉴权学生表只管学生业务信息通过 user_id 建立关联逻辑清晰得多。房间表里的“已住人数”这个字段严格来说是冗余的因为它可以由入住记录表实时统计出来。但实际开发中我建议保留这个冗余字段因为查询房间列表时你总不希望每条记录都去 count 一次入住记录表。代价就是在入住和退宿操作时记得同步更新这个字段。类似这种“用空间换时间”的设计在业务系统里很常见。2. 核心功能模块与重难点解析2.1 登录鉴权JWT 还是 Session别再纠结了刚开始做前后端分离项目的人最容易卡在登录这块。以前用 JSP 的时候登录状态靠 Session 解决浏览器自动带 Cookie后端一判断就完事。但前后端分离之后前端独立部署后端接口是无状态的这时候主流方案就变成了 JWTJSON Web Token。这个项目里如果用的是 Spring Boot Vue我强烈推荐 JWT。逻辑大概是这样用户输入账号密码后端校验通过后生成一个 token 字符串返回给前端前端把它存在 localStorage 里之后每次请求都在 header 里带上Authorization: token。后端通过拦截器解析 token获取当前登录用户的 ID 和角色就知道这个请求是谁发的、有没有权限。代码大致长这样// 登录接口核心逻辑 public Result login(RequestBody LoginDTO loginDTO) { User user userService.login(loginDTO.getUsername(), loginDTO.getPassword()); if (user null) { return Result.error(用户名或密码错误); } String token JwtUtil.generateToken(user.getId(), user.getRole()); return Result.success(token); }这里有几个细节值得注意。第一密码一定不能明文存起码要用 MD5 加盐或者直接用 Spring Security 的 BCrypt。第二JWT 的密钥不要写在代码里要放到配置文件里用Value读取。第三token 过期时间建议设置成 24 小时太短的话用户体验差太长的话不安全。2.2 学生管理批量导入是这个模块的隐形需求学生管理的本质是 CRUD但这里的“隐形需求”是批量导入。一个年级几千人你要宿管员在系统里一个个手动录入那这个系统上线第一天就会被弃用。所以我在做学生信息管理的时候一定会加一个 Excel 批量导入的功能。实现思路很简单前端用 Element UI 的 upload 组件上传 Excel 文件后端用 EasyExcel 或者 POI 解析逐行校验数据合法的插入学生表不合法的返回错误行号和原因。这个功能在答辩时特别有展示效果你可以现场演示导入一个几千行的 Excel几秒钟就能看到学生列表里刷出数据。校验逻辑要写严谨一点学号不能重复手机号格式对不对性别只能填“男”或“女”。我第一次写的时候没校验学号重复结果导入了两遍学生数据全重复了后面查数据各种混乱所以这个坑先替大家踩了。2.3 宿舍分配最体现业务逻辑的模块宿舍分配是整套系统的灵魂。如果只是给每个学生指定一个房间号那这个模块三分钟就写完了。但实际业务里你会遇到这些需求按班级分配、按性别分配、自动分配空床位、限制同班优先同楼栋。我当时的实现思路是分两步手动分配和自动分配。手动分配就是管理员选择一个学生再选择一栋楼系统自动筛掉满员的房间管理员挑一个房间点确认。自动分配就更智能一点传入一批学生系统按“同一班级尽量在同一楼栋、同一房间”的规则循环遍历房间表找到最合适的落点。这种算法不难但写出来很见水平因为它涉及到了“怎么判断最优”的思考过程。自动分配的核心伪代码for (Student stu : studentList) { // 1. 优先找和当前学生同班人数最多的房间 Room room findRoomWithMostClassmates(stu); // 2. 找不到就找同楼栋空床位最多的房间 if (room null) { room findRoomWithFreeBed(stu); } // 3. 都找不到就报错提示手动分配 if (room null) { errors.add(stu.getName() 分配失败无空床位); continue; } checkinService.checkin(stu, room); }这个模块做好之后答辩时你可以把“自动分配”作为亮点来讲因为大多数人的系统只有手动分配你能做自动分配说明你对业务场景的理解比别人深了一层。2.4 报修工单状态流转要闭环报修模块看似简单但状态流转如果做不好就会变成“学生提交了之后没人管”。完整的状态链应该是待处理 → 处理中 → 已完成如果维修不了还需要有“已驳回”状态。前端在展示报修列表的时候我建议用标签来区分状态比如“待处理”用黄色、“处理中”用蓝色、“已完成”用绿色这样宿管员扫一眼就能知道还有多少单子没处理。这里要强调一个点状态变更一定要记录操作人和时间最好是单独建一张“工单进度表”来记录每一步操作。这样学生看到的不只是“已处理”而是“宿管员张三于某时分配维修工维修工李四于某时完成维修”体验会好很多。2.5 卫生检查与统计从录入到图表卫生检查这个模块学生端几乎看不到但它是宿管员每天都要用的功能。我做的版本里宿管员按宿舍楼选择楼层逐间录入评分1-10分备注里可以写“地面不干净”“被子未叠”之类的问题。这个模块真正出彩的地方在统计。当历史评分数据积累到一定量之后用 ECharts 画一个“各宿舍楼平均分趋势图”和“卫生优秀宿舍排行”放在管理员的首页看板上效果非常直观。做毕业设计或者期末项目的时候这一段能成为系统展示的亮点因为它证明你不只是会写表格还懂数据可视化。3. 技术选型与环境搭建3.1 后端技术栈Spring Boot MyBatis-Plus 的组合拳这个项目后端的技术栈我的推荐是组件版本建议说明JDK1.8 或 11不要用太高版本避免兼容性问题Spring Boot2.7.x稳定生态兼容性好MyBatis-Plus3.5.x提高了 CRUD 开发效率MySQL5.7 或 8.0建议 8.0性能更好Maven3.6依赖管理Lombok1.18.x简化实体类代码MyBatis-Plus 这个东西我刚开始是不太用的觉得它有点“重”。但用了几次之后真香了尤其是它的QueryWrapper写条件查询太方便了。比如你要查“住在3栋、状态为空房、床位数大于2”的房间代码只需要QueryWrapperDormRoom wrapper new QueryWrapper(); wrapper.eq(building_id, 3) .eq(status, 空闲) .gt(bed_count, 2); ListDormRoom rooms dormRoomMapper.selectList(wrapper);对比传统 MyBatis 要写 XML、写 SQL这种方法省了不知道多少时间。而且它自带分页插件传入页码和每页条数返回的总数、总页数都有前端只需要接收并渲染。3.2 前端技术栈Vue Element UI 是绝配前端我推荐 Vue 2 搭配 Element UI或者 Vue 3 搭配 Element Plus。这个项目如果用 Vue 2原因可能就一个网上现成的参考代码多遇到问题容易查。但我个人的建议是如果有时间尽量用 Vue 3 写毕竟 Vue 2 已经停止维护了新项目没必要再学旧技术。前端核心依赖vue-router管理页面路由登录后根据角色动态生成菜单axiosHTTP 请求库封装 request 工具类统一处理 tokenpiniaVue 3/ vuexVue 2状态管理存放用户信息和菜单element-plusUI 组件库页面上最常用的组件就是el-table、el-form、el-dialog、el-pagination。这四个组件基本能覆盖 80% 的管理系统页面。如果你要做首页统计看板再加一个echarts。3.3 搭建时最容易忽略的环境细节环境搭建本身不复杂但我每年都能看到有人卡在这些“小问题”上这里集中说一下。后端启动前要确认三件事一是 MySQL 版本与驱动是否匹配MySQL 8.0 要选com.mysql.cj.jdbc.DriverMySQL 5.7 用com.mysql.jdbc.Driver就行二是数据库时区设置推荐在连接串里加serverTimezoneAsia/Shanghai不然会报时区错误三是 Maven 仓库地址建议换成阿里云镜像不然下载依赖能等半小时。前端启动前要注意 node 版本。Element Plus 要求 Node ≥ 16如果你机器上装的是 node 12npm install 大概率会报错。建议直接装 node 16 LTS 版本这是当前兼容性最好的版本区间。4. 实操把项目从源码跑起来4.1 拿到源码后先看什么很多人拿到源码第一件事就是双击运行结果各种报错然后就开始怀疑人生。我的习惯是先看 README 或项目文档再找数据库脚本最后才启动。这份源码对应的文档里通常会写清楚环境要求、部署步骤、默认账号密码、项目结构说明。这些信息虽然简单但能帮你少走一半弯路。然后是数据库脚本。脚本文件名一般是dormitory.sql或者init.sql。用 Navicat 或者其他数据库工具执行之前先打开看一眼里面有没有CREATE DATABASE语句。如果有说明你只需要新建一个连接然后执行这个脚本即可如果没有你就需要自己先建库再执行脚本。4.2 导入数据库的细节导入数据库看起来简单但细节决定成败。我用 Navicat 执行 SQL 脚本十次里有两次会踩字符集的坑所以这里单独拿出来说。执行前先在连接属性里把编码设置成 UTF-8脚本导入后再检查一下表数据确认中文没有变成乱码。如果发现乱码了别急着删库重来先看两处一是脚本文件本身是不是 UTF-8 编码建议用 Notepad 或 VSCode 查看右下角编码二是执行工具连接的字符集设置。MySQL 8.0 有几个库默认字符集是 latin1如果你建表时没有指定DEFAULT CHARSETutf8mb4中文字段就很容易出问题。导入后建议执行下面这句检查一下SHOW CREATE TABLE student;看到DEFAULT CHARSETutf8mb4就放心了。4.3 后端启动从 Maven 到 Spring Boot数据库搞定之后用 IDEA 打开后端代码。第一步是等 Maven 把依赖下载完这个过程取决于你的网速和镜像配置。等右下角的进度条转完检查一下application.yml里的数据源配置把它改成你自己的数据库名、用户名和密码。spring: datasource: url: jdbc:mysql://localhost:3306/dormitory?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver确认无误后运行启动类。如果启动日志里看到Tomcat started on port(s): 9090就说明后端已经跑起来了。这时候可以在浏览器里访问接口文档地址如果集成了 Swagger查看接口是否正常响应。4.4 前端启动npm install 的玄学前端比后端稍微麻烦一点。进到frontend目录后先执行npm install这个命令会根据package.json安装所有依赖包。这里我要重点提醒一下npm install不是每次都能一次成功的。我见过最多的问题是网络超时和 node-gyp 编译错误。网络超时常见于 Windows 系统未设置镜像源解决办法npm config set registry https://registry.npmmirror.com设置完镜像再执行 install速度会有质的提升。安装完成后执行npm run dev正常情况下等几秒钟终端会显示一个本地访问地址默认是http://localhost:5173Vite或http://localhost:8080Webpack。然后在浏览器里打开就能看到登录页了。4.5 前后端联调代理配置怎么搞前后端分离项目最烦的就是跨域问题。浏览器直接请求后端 9090 端口会被跨域拦截。解决办法有两种后端加 CORS 过滤器或者前端设置代理。我看这个项目里用的是 Spring Boot 的 CORS 配置其实更推荐前端配代理因为线上部署时 nginx 也是这么干的。前端 Vite 或 Vue CLI 里的代理配置大概是// vue.config.js module.exports { devServer: { proxy: { /api: { target: http://localhost:9090, changeOrigin: true } } } }这样前端所有以/api开头的请求都会自动转发到后端 9090 端口浏览器以为请求的是同源地址跨域问题就消失了。后端不用做任何跨域处理少很多麻烦。5. 常见问题与排查技巧实录5.1 数据库连不上先分清是网络问题还是账号问题数据库连接失败是最常见的问题排查思路其实就那么几步。先检查 MySQL 服务有没有启动。Windows 下在“服务”里找 MySQLLinux 下执行systemctl status mysqld。然后再检查账号密码是不是正确命令行直接连一下试试。如果命令行能连程序连不上八成是连接串的问题注意 host、port、数据库名、useSSL 参数。还有个小技巧如果程序报错说Public Key Retrieval is not allowed在连接串后面加allowPublicKeyRetrievaltrue就能解决。这个是 MySQL 8.0 特有的坑。5.2 Maven 依赖下载慢阿里云镜像安排上Maven 依赖下载到一半卡住或者Could not transfer artifact这类错误十有八九是镜像源的问题。解决办法是修改settings.xml在 mirrors 节点里加阿里云镜像mirror idaliyunmaven/id mirrorOf*/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror改完之后重启 IDEA重新刷新 Maven你会发现下载速度快了不止三倍。5.3 前端 node 版本不兼容别硬刚npm install报错里面很多跟 Node 版本有关。比如有些依赖要求 Node 14.15你机器上装的是 12.x这时候最好的方案不是去查问题的解决方案而是直接换 Node 版本。建议用 nvm-windows 或 nvm 管理多个 Node 版本随时切换非常方便。装好之后执行nvm install 16.20.2 nvm use 16.20.2切换到 Node 16 之后绝大部分 Vue 项目都能顺利安装依赖。5.4 登录不进去八成是 token 解析问题系统能启动页面也能打开但一登录就报“未登录”或者“token 已过期”这时候要从前端和后端两头排查。前端看一下 localStorage 里有没有 token请求头里有没有把 token 带上。后端在拦截器里打个日志看解析 token 时抛了什么异常。常见原因有三个一是前后端的 token 密钥不一致二是 token 过期时间设得太短三是后端拦截器放行了登录接口但没放行其他公开接口。逐个排查不难定位。为了让大家查着方便我把常见的坑整理成一个表现象可能原因解决办法后端启动报端口占用9090 被其他进程占用换端口或在任务管理器结束占用进程前端页面空白路由配置错误 / 编译报错按 F12 看控制台报错信息请求 404前端代理路径不对检查代理配置里的路径和后端 Controller 路径请求 500后端接口异常查看后端日志定位异常堆栈中文乱码数据库字符集设置不对统一改为 utf8mb4npm install 卡住网络问题配置 npmmirror 镜像重试登录后跳回登录页token 未保存成功检查前端登录成功后是否存储 token6. 系统优化方向从“作业”到“作品”6.1 引入权限框架Spring Security 还是 Sa-Token如果你想把项目从“课程设计”提升到“毕设优秀”的水平第一步就是把自研的拦截器换成真正的权限框架。Spring Security 是生态最完整的但学习曲线比较陡配置一堆新手容易绕晕。Sa-Token 是一个国产轻量级权限框架API 设计非常友好几行代码就能集成登录鉴权和权限控制。我的建议是如果你对 Spring Security 不熟直接用 Sa-Token。它的文档全是中文示例代码丰富集成到 Spring Boot 项目里 20 分钟就能搞定。一旦引入了权限框架你就能在系统里实现“管理员能看所有页面宿管员只能操作宿舍业务学生只能看自己的信息”这种精细化的权限控制这在答辩的时候是一个非常加分的点。6.2 数据可视化看板把分数和入住率变成图表前面提到卫生检查要加图表其实整个系统都适合做数据可视化。管理员登录后首页最理想的状态是一个看板上面有几个数字和一个图表区。数字包括总学生数、总宿舍数、当前入住率、待处理报修数。图表包括近一周报修趋势、各楼栋入住率对比、卫生评分分布。实现用 ECharts前端代码不算复杂。比如入住率对比柱状图数据来自后端一个统计接口GetMapping(/dashboard/building-occupancy) public Result getBuildingOccupancy() { ListBuildingOccupancyVO list dashboardService.getBuildingOccupancy(); return Result.success(list); }前端拿到数据后用echarts.init初始化图表setOption设置数据和样式一个能拿得出手的看板就出来了。这一步的价值是让项目从“功能齐全”变成“数据有洞察力”评委印象分会明显不一样。6.3 导出 Excel给老师一份能打印的报表导出功能也是容易被忽略但很加分的点。宿舍管理系统里最常见的导出需求是“学生入住名单”和“宿舍卫生检查记录”。用 EasyExcel 操作很简洁// 导出学生入住名单 EasyExcel.write(response.getOutputStream(), StudentExcelVO.class) .sheet(学生入住名单) .doWrite(list);前端触发导出的方式也很简单直接用一个a标签或者 window.location 跳转到导出接口就行。这个功能在期末做项目汇报、老师要检查数据的时候特别实用。6.4 部署上线把项目从本地搬到服务器项目做完之后如果能部署到服务器上那就是完整的一条龙交付。部署方案很成熟后端用 Maven 打成 jar 包通过java -jar运行前端npm run build生成 dist 静态文件用 Nginx 托管。Nginx 配置里最关键的是反向代理部分把/api请求转发到后端端口location /api/ { proxy_pass http://127.0.0.1:9090/api/; }部署这件事听起来很唬人但实操一遍之后会发现它跟本地跑项目没有本质区别只是换了一个环境而已。一旦你把项目成功部署到了云服务器你对整个系统的理解会再上一个台阶。7. 真心建议这几点请一定放在心上做这个项目这么多遍有几句话想说给正在做课程设计或毕设的同学听。第一不要只看“能不能跑”要看“懂不懂”。源码能跑通是最低标准但答辩的时候老师会问你“为什么要用 MyBatis-Plus”“JWT 和 Session 有什么区别”。如果你只是把代码复制粘贴跑起来这些问题一问就穿帮。建议你在跑通代码之后抽出两天时间把核心流程从登录到查询数据到底层是怎么走的完整读一遍。第二数据库备份一定要做。我见过太多人做项目做了一半MySQL 突然崩溃代码没丢但数据全没了心态直接炸裂。我的习惯是每天导出一次 SQL 备份文件放在单独目录里一旦出了问题五分钟就能恢复。第三提交代码的时候记得用 Git哪怕只是本地仓库。这个习惯能救你于水火。改了一堆代码之后发现 bug 修不了一条git checkout .就能回到之前的稳定版本这种安全感是任何编辑器撤销都比不上的。如果你手头正好在做这个宿舍管理系统拿到的源码版本可能和这里说的有些出入但核心思路是一致的先确认环境再导入数据启动后端启动前端然后逐个模块去验证功能。遇到问题不要慌从日志出发一步一步排查大部分问题都能解决。等你把系统跑起来再把这个项目从头到尾自己改一遍加上几个自己的功能我相信你在答辩的时候会比大多数同学都从容。