☰
SpringBoot+Vue学生宿舍管理系统设计与实现全复盘
2026/10/7 17:29:38 网站建设 项目流程

1. 这个系统为什么年年有人做,年年有人喊难

每到了课程设计和毕业设计的季节,技术社区里就会出现大量"求学生宿舍管理系统源码"的帖子。说实话,这道题"看起来简单"和"做起来麻烦"的落差,比想象中要大得多。表面上看就是几个增删改查页面:学生信息、宿舍信息、报修记录。但真正动手做的时候,权限怎么划分、床位状态怎么流转、同一个床位会不会被两个人同时选中、统计报表里的数字怎么算才说得清,这些细节会把一个"简单系统"硬生生拖成"日夜赶工项目"。

我去年帮一个朋友完整做了一套基于SpringBoot和Vue的学生宿舍管理系统,从数据库设计到前端页面再到部署上线,前后搭进去一个周末加几个晚上。这篇文章就把整个开发过程中的决策逻辑、踩坑点和最终方案完整复盘一遍。不涉及具体商业代码,但每一个设计思路和实现方案,你都可以直接复制到自己的项目里。适合正在做课设或毕设、想从"能跑"进化到"能讲"的同学,也适合刚接触前后端分离架构、想找一个完整案例练手的开发者。

1.1 一份需求清单,先搞清楚"宿舍管理系统"到底管什么

在动手写代码之前,我习惯先把需求掰开揉碎。学生宿舍管理系统通常涉及三类角色:系统管理员、宿管员、学生。以最常见的课设要求为例,核心功能基本跑不出这几个模块:

  • 基础信息管理:楼栋管理、宿舍管理、床位管理、学生信息录入与维护。
  • 宿舍分配业务:学生入住分配床位、退宿释放床位、调宿申请与审批。
  • 日常事务管理:卫生检查打分、报修登记与处理进度、晚归或请假登记。
  • 查询与统计:按楼栋、学院、班级查学生,统计入住率、报修处理率等。
  • 系统管理:账号管理、角色权限控制、密码修改、登录日志。

这里有一个非常重要的认知:这些功能里,真正有技术含量的不是增删改查,而是床位的状态流转和权限控制。床位不是简单的一个字段,它有"空闲、已入住、维修中"三种状态,而且同一个学生不能同时占两个床位,两个管理员也不能同时把同一个床位分给不同的人。如果不提前设计好数据模型和更新逻辑,后面做分配功能时会不停地返工。

1.2 这篇博文的定位:不是源码搬运,而是设计思路的完整复盘

我清楚很多人搜"学生宿舍管理系统源码",就是想要一份能直接交差的东西。但我更建议你把这篇内容当成"设计文档级别的实战笔记"来看。我会详细说明:为什么选SpringBoot而不选SSM,数据库表为什么要那样建,用户登录的token到底是怎么流转的,前端打包之后怎么丢进SpringBoot的静态目录里,以及哪几个位置最容易在答辩现场被老师一句话问住。

就算你最后不用我这里的方案,沿着这套思路去拆解任何一份开源源码,你也能在很短时间内看懂它、改进它,并写好配套文档。下面进入正题。

2. 翻开一份"能跑"的源码:SpringBoot+Vue的骨架到底长啥样

我见过太多课设项目,前端是一个HTML页面套着一堆jQuery,后端是Servlet加JDBC,代码全堆在Controller里。能跑,但答辩老师只要问一句"如果并发50个人同时选床位怎么办",基本就卡壳了。用SpringBoot加Vue做前后端分离,不是为了赶潮流,而是这两个框架恰好都满足课设场景里最重要的三个要求:学习成本可控、资料足够多、架构经得起追问。

2.1 前后端分离的本质:两个项目还是一个项目

先把这个问题讲透。前后端分离在物理上通常是两个独立的工程:一个是SpringBoot的Maven工程,一个是用Vue CLI或Vite创建的Node前端工程。后端只提供HTTP接口、返回JSON,前端只管渲染页面和交互,二者通过Axios之类的HTTP客户端通信。

一个标准的目录结构长这样:

dormitory-system/ ├── backend/ # SpringBoot后端工程 │ ├── src/main/java/com/dorm/ │ │ ├── controller/ # 接收请求,返回JSON │ │ ├── service/ # 业务逻辑 │ │ ├── mapper/ # 数据访问层 │ │ ├── entity/ # 实体类 │ │ ├── config/ # 配置类(跨域、拦截器等) │ │ └── common/ # 统一返回结果、异常处理 │ └── pom.xml ├── frontend/ # Vue前端工程 │ ├── src/ │ │ ├── views/ # 页面级组件(如DormitoryManage.vue) │ │ ├── components/ # 复用组件 │ │ ├── router/ # 路由配置 │ │ ├── api/ # 封装请求 │ │ └── store/ # 全局状态管理 │ └── package.json └── sql/ # 数据库脚本.sql

分这么清楚有个实打实的好处:你可以在一个端口只开后端,用Postman调接口;也可以只开前端,用Mock数据调试样式。调试效率比单体应用高很多,出问题时也能快速定位是接口的问题还是页面的问题。

2.2 技术选型背后的真实理由

很多人选型时看"哪个流行选哪个",我建议看"哪个对当前项目收益最高"。给课设做选型时,我考虑过三个问题:

第一,为什么后端用SpringBoot而不是SSM?SSM五年前是主流,但配置一堆XML,光Spring和MyBatis整合就够新手喝一壶。SpringBoot把自动配置内化,你只要引入依赖、写几个注解就能跑起来。而且市面上绝大多数课设代码、博客、视频教程都基于SpringBoot,遇到问题搜得到答案,这一点在赶工期时能救命。

第二,为什么ORM层选MyBatis-Plus?这里说句实在话,学生宿舍管理系统的数据查询复杂度不高,大部分是单表操作加简单条件查询。MyBatis-Plus提供了一整套单表CRUD方法,连SQL都不用写,内置分页插件也很方便。相比原生MyBatis要手动维护XML,效率高出不止一点。但它不是万能药,后面讲多表联查时你会看到什么时候该放弃它、直接手写SQL。

第三,为什么前端选Vue而不是React?对做课设的同学来说,Vue的中文资料和Element UI/Element Plus这类现成组件库是核心优势。你不需要自己手写一个好看的后台管理界面,直接拿组件库拼页面,一天的活儿能缩到两小时。这不是投机取巧,而是工程上正常的复用思维。

2.3 版本选择:SpringBoot、JDK、Vue三者搭配是最大的坑

我见过太多人死在这上面,所以单独拉一节说。搜索热词里"springboot版本太高"能上热搜,真不是没道理。现在常见的搭配有两套:

项目保守方案(推荐课设用)较新方案
JDK1.817
SpringBoot2.7.x3.x
MyBatis-Plus3.5.x3.5.x(注意兼容)
Vue2.6 + Vue CLI3.x + Vite
UI库Element UIElement Plus

两套方案都能做出完整项目,但如果你用新教程配合老代码,或者反过来,多半会撞上"javax"和"jakarta"的报错。SpringBoot 3.x把javax.servlet改成了jakarta.servlet,很多老代码的import javax.*直接失效。所以我的建议是:项目开始之前先定死版本清单,写进文档里。这一步能帮你省掉后面至少两天的排错时间。

3. 数据库是整套系统的地基:表结构与初始化数据怎么设计

说句可能得罪人的话,我看了不少课设源码,很多"能跑"的系统,数据库表设计是站不住脚的。要么把所有信息塞进一张大宽表,要么外键关系混乱,要么字符集不是utf8mb4导致中文乱码。数据库设计得不好,后面每个功能写起来都别扭。

3.1 核心表的关系网:用户、学生、宿舍、楼栋

先理清核心实体。以我常用的方案为例,最终表控制在10张以内,但关系清晰:

  • sys_user账号表:存登录名、密码(BCrypt加密)、角色(admin/manager/student),和学生表是一对一或一对零。
  • t_student学生表:存学号、姓名、性别、学院、班级、手机号、当前宿舍ID,其中学号是天然的业务主键。
  • t_building楼栋表:存楼栋名称、可容纳人数等。
  • t_dormitory宿舍表:存楼栋ID、房间号、楼层、床位数、当前已住人数。
  • t_bed床位表:把床位单独拆一张表。宿舍和床位是一对多,每个床位有独立的状态字段。这样做的好处是分配时可以精确到床位,而不是只能整个宿舍一起分配,也为后续调宿、退宿留出了清晰的状态流转空间。

至于业务表,常见的有t_repair(报修)、t_hygiene(卫生检查)、t_leave(请假或晚归登记)、t_transfer(调宿申请)。它们都有共同点:一个业务主键、一个关联的外键字段、一个状态字段、一条时间线。

这里我特别想强调一点:外键到底加不加。课设里我建议不加数据库外键约束,而是把关联关系放在代码层维护。原因有二:第一,MyBatis-Plus这种框架对数据库外键没有特殊支持,真正维护关系的是业务代码;第二,有外键约束后,做删除和批量初始化数据时会遇到一堆顺序依赖的麻烦。但不加外键不代表不设计关系,关系在表和字段层面就已经定了,外键约束只是物理层的保护。

3.2 一份能从头执行到底的SQL:建库、建表、灌数据

"源码+数据库+文档"三件套里,数据库往往是最容易被忽略、最后又最影响验收的一环。我给你一个建议:交付的SQL脚本必须是从头到尾能完整执行的,包含建库、建表、插入初始化数据三个部分。很多同学导出数据库时只导出了表结构和业务数据,评审老师拿到手根本起不来。

我的SQL脚本按这个顺序组织:

  1. 先建库,CREATE DATABASE dormitory DEFAULT CHARACTER SET utf8mb4;。注意字符集指定utf8mb4,光写utf8在MySQL 5.7之后依然可能出问题。
  2. 按依赖顺序建表:sys_user→t_building→t_dormitory→t_bed→t_student→ 各业务表。
  3. 插入初始化数据:至少包含一个admin账号、一个宿管账号、两三个学生账号,以及几条楼栋和床位数据。

这里有个经验:初始化数据的密码记得统一,比如都是123456,并且用同一种加密算法生成,方便演示时登录。不要在文档里写"密码请自行查看"这种话,那等于给验收环节添堵。

3.3 让统计报表不那么难写的两个小技巧

宿舍系统很难避开统计功能:入住率、各楼栋人数、报修完成率。如果每次统计都要在代码里写一大段循环去查数据库,既慢又丑。我常用的做法是两个层面配合:

一是增加冗余字段。在t_dormitory表里放一个"已住人数"字段,每次分配或退宿时,在同一个事务里同步更新床位状态和宿舍已住人数。查询汇总时直接对已住人数求和,不需要实时count床位表。你可能会问:冗余字段不怕数据不一致吗?怕,所以在同一个事务内更新t_bed和t_dormitory,一致性就有保证。

二是复杂统计直接用SQL的GROUP BY加聚合函数,不要在Java代码里算。比如按楼栋统计人数,一行SQL就能解决:

SELECT b.id, b.name, COUNT(s.id) AS stu_count FROM t_building b LEFT JOIN t_student s ON b.id = s.building_id LEFT JOIN sys_user u ON s.student_no = u.username WHERE u.role = 'student' AND s.status = 1 GROUP BY b.id, b.name;

这种SQL写完放进Mapper的@Select注解里,比在Service层写循环高效得多,答辩时也更讲得清楚。

4. 从学生端到管理端:权限与核心业务模块的实现逻辑

骨架和数据库搭好之后,该解决"系统怎么运转"的问题了。这一章讲三个核心实现逻辑,分别对应三个最容易答辩翻车的点:登录鉴权、宿舍分配、状态类业务流转。

4.1 登录鉴权:前后端分离下"我是谁"的问题

传统单体应用可以用Session,前后端分离后我更推荐用JWT做无状态鉴权。流程很简单:

  1. 用户输入账号密码,后端校验通过后生成一个JWT字符串,里面带上用户ID和角色,通过接口返回给前端。
  2. 前端把token存起来,之后每次请求都在Header里带上Authorization: Bearer <token>。
  3. 后端写一个拦截器,统一拦截除登录接口之外的请求,解析并校验token,通过后放行,不通过返回401。

注意几个细节。密码不要明文存储,用BCrypt或MD5加盐。课设用BCrypt更显专业,Spring Security里自带BCryptPasswordEncoder,但不想引入完整Security框架的话,也可以单独引入Spring Security Crypto的依赖,只拿它的加密工具类。token有效期建议设24小时,引入Redis做黑名单会更专业,但对课设场景来说属于超纲,也容易把自己绕晕,可以不引入。

拦截器的实现参考这样:

@Component public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); // 校验token,合法则把用户信息放入request上下文 // 不合法则返回401并终止请求 return true; } }

记得在配置类里注册拦截器,并且放行/api/login和静态资源路径。这个配置遗忘率非常高,很多人部署后页面打不开,就是因为静态资源被拦截器拦了。

4.2 宿舍分配:床位状态机和并发问题

宿舍分配是整个系统里业务逻辑最"像样"的部分,也是答辩老师最喜欢深挖的地方。一个学生申请入住时,怎么保证他拿到的床位真的是空的?如果两个管理员同时操作,会不会把同一个床位分给两个人?

我的方案是给床位加状态字段,并在分配事务里做条件更新。床位的状态机是:

  • 0-空闲:可以被分配
  • 1-已入住:不可分配
  • 2-维修中:不可分配

分配的核心逻辑是:先根据宿舍ID查可用的空闲床位,然后用带状态条件的SQL去更新:

boolean success = bedMapper.updateByCondition( // 设置新状态 new Bed().setStatus(1).setStudentId(studentId), // 条件为:床位ID匹配且当前状态为0 new LambdaQueryWrapper<Bed>() .eq(Bed::getId, bedId) .eq(Bed::getStatus, 0) ) > 0;

关键在于WHERE id=? AND status=0。如果返回更新行数为0,说明床位已经被别人抢走了,本次分配失败,重新选择床位即可。这其实就是乐观锁的思路,不需要引入分布式锁,用数据库自带的行锁就能解决。

调宿和退宿都是在这个状态机上做流转。退宿把床位状态还原为空闲,同时清空学生ID关联。把关键约束放在数据库字段和更新条件里,比在Java代码里写一堆if-else要稳得多。

4.3 报修、卫生检查这类"状态流转"业务怎么做

学生报修→宿管查看→维修处理→学生确认,这类流程本质上就是一张表加上一个状态字段的流转,区别只在于哪个角色能改状态。实现时,我建议统一返回格式:

{ "code": 200, "message": "操作成功", "data": {} }

前端用Axios统一拦截,解析code并做提示;后端用@RestControllerAdvice做全局异常处理。这样一来,报修模块、卫生模块、请假模块都可以复用同一套结构和逻辑,代码量能压缩不少。

表单提交前,前端做一次必填校验和手机号格式校验;后端接口再做一次非空和长度校验,双保险。千万别只做前端校验,因为接口是可以被直接调用的。这是一个非常基础但常见的扣分点。

5. 把前端打包塞进SpringBoot:从本地联调到服务器部署

代码写完了,最折腾人的其实是"怎么让前后端真正跑在一起"。我见过太多项目在本地跑得好好的,一到部署就崩。这一章把联调、跨域、部署三个环节说透。

5.1 跨域问题:前端端口和后端端口"八字不合"的根源

开发环境下,前端跑在localhost:8080,后端跑在localhost:9090,端口不同,浏览器的同源策略就会拦下请求,这就是跨域。解决办法有两种:

第一种,后端直接加CORS配置类,允许前端地址访问。写一个WebMvcConfigurer配置类,重写addCorsMappings方法,允许所有来源和所有请求方法即可。这种方式简单直观,适合课设。

第二种,前端用Vite或Vue CLI的代理功能,把/api开头的请求代理到后端地址。开发期用代理更接近生产环境,改接口地址时不用动前端代码。这两种方式我都试过,开发期推荐代理,生产期推荐直接打包进后端同源部署,整个系统只有一个地址,没有跨域问题。

5.2 两种打包部署方式,先看懂再选择

第一种是"Vue打包放进SpringBoot"。在frontend目录执行npm run build,得到dist目录,把里面的静态文件复制到后端src/main/resources/static下,然后重新打包后端的jar。这样整个系统只有一个jar包,里面既包含后端接口,也包含前端页面。部署时用java -jar dormitory.jar就能跑,非常省事。对应的,前端请求接口的地址不要写死成http://localhost:9090/api,应该用相对路径/api,这样在同一个Tomcat下才不出问题。

第二种是"前后端分离部署"。后端jar包跑在9090端口,前端dist目录交给Nginx托管,Nginx配置反向代理,把/api请求转发给9090的SpringBoot进程。这种部署方式更贴近真实企业环境,适合在文档里写"未来可扩展性",也方便把静态资源独立管理。但如果你在校期间没有云服务器,用第一种方式就足够了。

这里直接给出一份Nginx静态托管加反向代理的关键配置:

server { listen 80; server_name your_domain_or_ip; root /usr/share/nginx/html/dist; index index.html; location /api/ { proxy_pass http://127.0.0.1:9090; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

5.3 部署时的常见问题:端口、数据库连接、配置文件

部署踩坑主要集中在三件事:

  • 端口被占用:Linux服务器上用netstat -tlnp查端口,找到占用8080或9090的进程处理掉。Windows下对应的是netstat -ano加任务管理器,但服务器大概率是Linux。
  • 数据库连接不上:大概率是数据库地址写成了localhost,而客户端和数据库不在同一台机器。把application.yml里的url改成服务器的IP或内网地址,并确认3306端口在防火墙或安全组里放行。
  • 配置文件分环境:我的习惯是application-dev.yml和application-prod.yml两套配置,启动时用--spring.profiles.active=prod指定。课设虽然不强制,但这个习惯写在文档里,评委印象分会高不少。

6. 配套文档怎么写,答辩才不至于"一问三不知"

标题里的三件套,源码和数据库都聊完了,最后说文档。我见过不少学生代码写得不错,文档却很糟糕,答辩时只能干巴巴地说"我用了SpringBoot和Vue"。文档其实是给评委的第一印象,在答辩中占的比重有时候比代码本身还高。

6.1 课设文档的黄金结构:从需求到验证一脉相承

不要从网上下一个"万能模板"套上去,而是围绕逻辑主线自证合理性。我的建议顺序是:

  1. 需求分析:把系统用户和用例列清楚。学生能干什么、宿管能干什么、管理员能干什么。这是整份文档的根基。
  2. 系统设计:画整体架构图(前后端分离、标注技术栈),再加数据库ER图和表结构说明。表结构说明要包含字段名、类型、是否主键、含义。评委不一定逐行看代码,但会扫一眼表设计是否合理,字段命名是否规范。
  3. 核心模块设计:选两三个最能体现技术能力的模块深入写,比如宿舍分配的并发控制、JWT鉴权流程。这里是你得分的地方,一定要把"为什么这么设计"写出来。
  4. 系统实现与测试:贴关键界面截图和接口测试结果,顺带写一个简单的测试用例表,比如测试正常分配、测试重复分配、测试权限拦截。
  5. 总结与展望:一两句话带过即可,重点是"实现了什么、还能优化什么"。不要写"我相信该系统具有良好的应用前景"这种空话,改成"后续可引入消息队列处理报修通知"这种具体方向。

6.2 答辩演示的节奏:核心链路优先,别从登录页开始讲20分钟

答辩演示是很多同学忽略的环节。我的经验是:按"核心链路"演示,不要按"菜单顺序"演示。菜单顺序演示的问题在于:讲者容易陷入一个个页面的截图流,评委听不出业务闭环。核心链路演示则不一样:

第一步,用管理员账号登录,展示学生信息和楼栋宿舍列表,说明数据如何录入。 第二步,走一遍"学生入住分配床位"的完整流程,顺便展示床位状态的实时变化。这里是体现数据库设计和业务逻辑的最好时机。 第三步,用学生账号登录,演示提交一条报修,再切回宿管账号处理这条报修,只讲状态流转。 第四步,打开统计页面,展示入住率和报修处理率,解释这两组数据是怎么算出来的。

整个演示控制在5到8分钟,评委对系统业务闭环的感知会非常清晰。接着你再讲设计亮点(JWT、乐观锁、统一异常处理),基本就是顺着你的节奏走了。

6.3 三件套交付前,最后花半小时自查一遍

交付前的自查清单,我整理一份直接可用的:

  • SQL脚本能不能从空数据库直接完整执行,不报错?
  • 初始账号是否能正常登录?角色是否正确?
  • 前端打包后的静态文件是否已经放进了SpringBoot的static目录?
  • 能不能在只装JDK和MySQL的环境下,用一条java -jar命令把系统跑起来?
  • 文档里的截图是不是最新界面的截图?有没有残留旧版页面?
  • 外键、时区、字符集、跨域这些配置是否在文档中有说明?

这半小时的检查,能帮你避免很多"老师当场打开却发现跑不起来"的尴尬场景。我做课设和帮朋友验收项目时,每次都跑一遍这个流程。

最后再说一个小习惯:在SQL脚本和接口路径的命名上尽量保持规整和语义化,接口统一用/api前缀,表名统一用t_开头。你说不上这是哪个大功能,但评委翻代码时,视觉上的规整会潜移默化地影响他对你代码质量的判断。这些细节积累起来,就是同一套功能,有人被夸"工程化意识强",有人被批"这是玩具项目"的根本区别。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询