做了几年小程序开发,也帮不少朋友看过毕设项目,说实话“学生宿舍管理系统”这个选题在小程序毕设里算是非常经典的一个方向——需求明确、业务闭环完整、前端页面有辨识度、后端也有足够的逻辑深度,不管是拿来应付答辩还是以后往简历上写,都有东西可说。这篇就把我在实际搭建和维护这套系统时踩过的坑、梳理过的思路、以及源码里最核心的几个模块,完整拆开讲一遍。
1. 选题价值与技术路线:为什么宿舍管理系统适合做小程序毕设
1.1 从毕设评审角度看待这个选题
先说一个很多同学容易忽略的点:毕设评审看重的不是你用了多新鲜的技术栈,而是你的系统能不能讲清楚“业务怎么流转”“数据怎么组织”“异常怎么处理”。宿舍管理系统恰好就是一个特别标准的业务系统——有用户角色区分(学生、宿管员、系统管理员)、有核心业务流(入住、退宿、调宿、报修、查寝)、有数据关联(学生与床位的绑定、报修单与宿舍的关联)、有权限控制(学生只能看自己的信息,管理员能管全局)。
这意味着一套系统做下来,后台管理系统该有的模块你基本都碰到了:登录鉴权、角色权限、增删改查、状态流转、列表分页、文件上报。这些东西在面试和答辩里都是高频考点,比单纯做一个“记账本”或者“新闻浏览”小程序要能打得多。
1.2 前端选型:原生小程序 vs uni-app 的核心权衡
很多同学上来就问:用 uni-app 行不行?我的回答是:能用,但如果是毕设,我不推荐。
原生微信小程序最大的优势在于:你不用引入额外的一层编译框架,出问题排查起来更快。uni-app 跑起来确实跨端方便,但编译过程中经常出现一些“在 H5 正常、到小程序就报错”的诡异问题,比如组件样式失效、API 兼容差异、分包路径错乱。这些坑对新手非常不友好,而且答辩的时候老师只要问一句“你这个是原生开发的吗”,你要是答“不是,是 uni-app 打包的”,接下来大概率会被追问“那你说说 uni-app 和原生小程序的区别、编译原理是什么”。
相比之下,原生小程序开发时从wx.request请求数据到setData更新视图,整个链路非常直观,答辩时你也能清楚解释每一行代码的作用。这套源码里前端用的就是原生 WXML + WXSS + JS,没有任何额外框架依赖,打开微信开发者工具就能直接编译运行。
1.3 后端方案:Spring Boot 还是 Node.js
后端我见过不少方案,有 Spring Boot、Node.js、PHP、Python Flask,甚至有人用云开发(微信云托管)。对于数据结构和业务逻辑都比较经典的宿舍管理来说,Spring Boot 是最稳妥的选择,原因有三:
第一,Spring Boot 的生态太成熟了,MyBatis-Plus、Spring Data JPA 都是现成的,分页查询、条件构造器直接拿来用,开发效率极高。
第二,Java 后端的知识体系在答辩时好讲。老师问“你的事务怎么处理的”“你的权限怎么控制的”,Spring 家族有非常成熟的答案模板,你照着源码里@Transactional注解和拦截器的实现讲,足够应对。
第三,部署简单。打一个 jar 包扔到服务器上,java -jar就跑了,后台管理系统如果配套做一个 Web 端,也可以直接部署在同一台机器上。
2. 功能模块拆解:先弄清“谁在用系统”再写代码
2.1 三类用户角色与权限边界
宿舍管理系统的用户角色一般分成三种,源码里也严格按照这个思路做的权限设计:
- 学生端:登录后只能看到本人的住宿信息、宿舍公告、本人的报修记录,能发起报修、查看审核结果。
- 宿管员端:负责楼栋管理,能审核报修单、发布楼栋公告、录入住户信息、完成查寝登记。
- 系统管理员端:全量权限,能管理宿舍楼、房间、床位,分配学生入住,重置密码,导出统计报表。
这里有一个很多同学做废掉的通病:把学生端需求和管理端需求混在一个页面里做。其实小程序端的用户几乎都是学生,宿管员和管理员的日常操作更多是在后台管理系统上完成的。所以小程序只需要做学生端即可,管理后台单独做一个 Web 页面,两边共用同一套后端 API,这才是合理的架构。
2.2 学生端核心页面清单
小程序端页面不需要太多,但要确保每个页面都是“有业务含义”的。这套源码里小程序端实际交付了下面这些页面:
| 页面 | 功能要点 | 涉及 API/数据表 |
|---|---|---|
| 登录页 | 微信授权 + 学号绑定 | wx.login、student表 |
| 首页 | 宿舍公告 + 快捷入口 | notice、banner表 |
| 宿舍信息页 | 展示当前宿舍、床位、室友信息 | dormitory、bed、student联合查询 |
| 报修页 | 提交报修单,拍照上传 | repair表、文件上传接口 |
| 报修记录页 | 查看报修状态(待处理/处理中/已完成) | repair表状态字段 |
| 个人中心 | 个人信息修改、退出登录 | student表 |
报修功能是整个小程序端最重要的业务亮点。它不仅涉及表单提交,还涉及图片上传、状态流转、进度展示,一套完整的前后端交互链路全在里面,答辩时可以重点展开。
2.3 数据库设计:表结构才是系统的灵魂
很多同学写毕设喜欢先把页面做好再倒推建表,这是本末倒置。正确的做法是先梳理清楚实体关系,再设计表结构。宿舍管理系统核心表大概六张左右,已经能覆盖全部业务场景:
student:学生表,字段包括student_no(学号)、name、password、role、phone、dormitory_id、bed_id、status(在住/搬离)。dormitory:宿舍表,字段包括building_no(楼栋)、room_no(房间号)、capacity(容量)、gender(性别限制)、manager_id(宿管员)。bed:床位表,dormitory_id、bed_no、status(空闲/占用),床位和学生是一对一关系。repair:报修表,student_id、dormitory_id、title、description、image_url、status、create_time、handle_time。notice:公告表,title、content、publisher_id、create_time、target_building(可空,空则表示全员可见)。attendance:查寝表,building_no、room_no、student_id、status(在寝/未归)、record_date。
学生表和床位的关联是重点。学生入住时,需要先去查bed表里是否有status = 0(空闲)的床位,然后更新床位的status = 1,再更新学生的bed_id,这两个操作必须放在同一个事务里,否则就会出现“床位显示占用但学生没有绑定上”的数据不一致问题。源码里这一步就是通过@Transactional注解保证原子性的。
3. 核心模块实操:登录、分配床位、报修流程全解析
3.1 微信登录鉴权:从 wx.login 到后端 token 校验
小程序登录是目前所有业务系统的第一道关卡。一般的流程是:
- 前端调用
wx.login()拿一个临时code。 - 把
code发给后端,后端拿着code + appid + secret去微信的接口换openid。 - 后端根据
openid查学生表,如果查不到说明用户不是本系统的合法学生,返回“未绑定”的提示。 - 如果查到了,后端生成一个 token(JWT 或者 Redis session),返回给前端,前端存在
wx.setStorageSync('token', ...)里。 - 后续请求在 header 里带上前端的 token,后端通过拦截器校验 token 是否有效。
这里有一个非常重要的细节:不要在前端直接判断登录状态。很多人写代码喜欢打开小程序就先判断本地有没有 token,有就跳首页,没有就去登录页。这个判断逻辑是错的,因为本地 token 可能过期了,也可能被清掉了。正确做法是:每个需要登录态的请求发出去,如果后端返回 401,就在拦截器里统一清理本地缓存并跳转到登录页。
源码里封装了一个request.js工具文件,所有接口请求都会自动带上 token、统一处理 401 跳转,这个封装思路在答辩时可以单独拿出来讲。
3.2 宿舍分配逻辑:如何避免“抢床位”冲突
宿舍分配是这套系统里最容易出并发问题的模块。学生入住时,如果两个人同时申请同一个空闲床位,后端的两个请求可能同时读到“床位空闲”,然后同时写入,最终一个床位分给了两个人。这就是典型的超卖问题。
解决思路有好几种,源码里用的是最简单可靠的一种:利用数据库的乐观锁或者条件更新。给bed表加一个version字段,更新床位状态时使用 SQL:
UPDATE bed SET status = 1 WHERE id = #{bedId} AND status = 0如果这条 SQL 的影响行数是 1,说明抢位成功,可以继续完成学生绑定;如果影响行数是 0,说明床位已经被别人抢走,需要重新选择。这个方案不需要引入复杂的分布式锁,在单机部署的毕设场景里完全够用,而且代码逻辑清晰,答辩时还能主动讲一句“这里用了乐观锁解决并发分配问题”,老师听了就知道你懂数据库并发控制。
3.3 报修流程的状态机设计
报修模块是整个小程序端页面最多、交互最复杂的模块,也是答辩时最适合展开讲的部分。状态流转要设计清楚,不能只是简单的“提交”和“完成”。
源码里报修单设计了四个状态:
0:待提交(用户填写但未最终确认)1:待处理(提交成功,宿管未接单)2:处理中(宿管已接单,维修中)3:已完成(维修结束)
前端提交报修时,先让用户填写报修标题、描述、图片,然后直接提交为1状态。宿管员在后台接单后,状态变为2,维修完成后填写维修备注,状态变为3。学生端“报修记录”页面根据状态字段展示对应的标签和进度提示,状态为3时还允许学生对维修结果打分评价。
这个设计在答辩时可以这样表述:“报修单从创建到关闭经历了完整的生命周期管理,每个状态都由后端接口驱动变更,而不是前端随意修改。”这句话的价值比写几百行增删改查强得多。
3.4 后端 API 设计:统一返回格式与参数校验
后端接口如果不统一返回格式,前端处理起来会疯掉。源码里定义了一个Result类,所有接口都返回统一结构:
{ "code": 200, "message": "操作成功", "data": {} }code约定:200 是成功,401 是未登录或 token 过期,403 是权限不足,500 是业务异常。前端request.js里统一拦截code !== 200的情况,弹 toast 显示message,不需要每个接口都写一遍错误处理。
另外,参数校验不能只靠前端。后端的每个新增或修改接口都必须做非空校验和长度校验。源码里使用 Spring Boot 的@Valid注解配合@NotBlank、@Size等注解实现,一旦校验失败会自动抛出异常,由全局异常处理器统一转成上面说的Result格式。这是很多同学容易忽略的细节,但老师现场演示时如果故意输错参数发现接口崩了,印象分会大打折扣。
4. 常见问题与排坑实录:这些坑我几乎每个项目都踩过
4.1 微信开发者工具里的“合法域名”限制
本地调试的时候最坑的就是这个。小程序在开发者工具里默认校验“request 合法域名”,你要是不在后台配置,wx.request直接报错。毕设阶段绝大多数人都没有自己的已备案域名和 HTTPS 证书,怎么办?
两个办法:
第一个,在微信开发者工具的“详情 -> 本地设置”里勾选“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”。这个选项只对本地开发生效,个人项目调试完全没问题。
第二个,把后端改成 HTTP 明文接口,配合内网穿透工具或者在同一局域网内真机调试,注意要在真机上打开“调试模式”。
需要提醒的是:上线前这些校验是绕不过去的。如果你真的要在微信公众平台正式发布,必须有 ICP 备案的域名,并且域名要配置 SSL 证书,接口必须是 HTTPS,同时在公众平台后台把域名加入 request 合法域名列表。毕设答辩一般做到本地演示这一步就够,但老师如果问“这个系统能发布到线上吗”,你要能说出上面这套流程,说明你已经考虑过生产环境的问题。
4.2 真机预览时接口地址无法访问
很多同学做完本地调试发现电脑上的开发者工具一切正常,但一用手机预览就请求失败。原因通常是:你后端启动的地址是localhost:8080或者127.0.0.1:8080,手机访问这个地址指向的是手机自己,当然不通。
解决办法是让后端监听0.0.0.0,然后找到你电脑在局域网内的 IP(Windows 上用ipconfig,macOS 上用ifconfig),前端请求地址改成http://你的局域网IP:8080,手机和电脑连同一个 Wi-Fi 才能访问。
这个坑特别隐蔽,因为你改完地址后必须重新编译小程序才能生效,很多人改了request.js里的 baseURL 却忘了点编译按钮,排查半天结果发现是新代码没生效。
4.3 图片上传功能在毕设演示环境的隐藏风险
报修功能涉及图片上传,如果你直接把图片存到后端服务器本地磁盘,会有一个问题:图片路径返回给小程序之后,小程序端要显示图片需要后端能正常访问到这个路径。本地调试时没问题,但拿到了老师电脑上演示,或者部署到自己的服务器上,路径一变就全乱。
源码里处理图片上传用的是本地存储 + 静态资源映射方案,Spring Boot 里通过配置把磁盘上的某个目录映射为/images/**的 URL 访问路径。这样做的好处是图片访问不依赖数据库存储的绝对路径,迁移部署时只要把整个上传目录一起拷走就行。
但我给你的建议是:如果你有时间,尽量把图片上传改成对象存储方案(比如七牛云、阿里云 OSS)。对象存储有现成的 SDK,上传后直接拿到一个公网 URL,图片显示不受部署环境变化影响。毕设答辩现场最怕的就是演示到报修上传时图片加载不出来,这种偶发问题会打断你的节奏。
4.4 数据库连接池耗尽导致系统假死
有一次我帮朋友排查,系统启动后刚跑两分钟就卡死不动了。查后台日志发现是数据库连接池满。原因是他代码里有一个查询方法没用@Transactional包裹,但连接没有正常关闭,导致连接池被占满。
Spring Boot 默认用的是 HikariCP 连接池,默认最大连接数是 10。如果你在循环里查询数据库,每次查询都会从连接池拿一个连接,用完没还回去,连接池肯定很快耗尽。
解决方案有两个方向:一是检查代码,确保JdbcTemplate或 MyBatis 的会话正确关闭;二是把连接池参数调大,在application.yml里配置:
spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 idle-timeout: 600000不过要注意,调大连接池只是缓兵之计,根因通常是代码里有资源泄漏,比如查完数据没关闭ResultSet或Statement。用 MyBatis-Plus 基本上不用担心这个,框架帮你管理了连接生命周期,但如果你自己用原生 JDBC 写的代码,就要特别留意。
4.5 小程序端 setData 的性能陷阱
小程序的setData是同步到视图层的操作,数据量越大性能越差。很多同学喜欢在拿到后端返回的整个列表之后直接setData全部内容,如果列表有几百条甚至更多数据,页面会明显卡顿。
一个简单的优化是列表页只渲染当前页数据,用分页请求来实现“上拉加载更多”。源码里列表页都做了分页处理:初次加载只取第一页,滚动到底部时再请求下一页并把新数据concat到原数组后面。这里也有一个细节:每次setData整个list数组仍然会重新渲染所有项,更优的做法是使用wx:for配合wx:key来减少 diff 成本,同时把setData的 key 细化到具体字段而不是整个对象。
5. 答辩演示与源码交付的实战建议
5.1 演示脚本要提前设计好,不要现场乱点
毕设答辩最怕的不是项目烂,而是演示得乱。我强烈建议你提前给自己写一份演示脚本,按固定顺序操作:
- 先展示小程序登录流程,说明微信登录和后端 token 鉴权的完整链路。
- 进入首页,介绍公告模块,现场发布一条公告并在小程序端刷新出来。
- 进入宿舍信息页,展示当前学生和室友信息,讲解学生表、宿舍表、床位表如何关联。
- 提交一条报修单,现场上传图片,然后切到管理后台演示接单、处理、完成的操作。
- 最后展示数据库表结构和几条关键 SQL,说明你的设计思路。
每一步操作前先讲“我要做什么、这个功能解决什么问题”,然后再动手演示。演示过程中即使出了 bug,也不要慌,你越镇定、越能快速定位问题,老师越会觉得你对系统足够了解。
5.2 源码交付时应该包含哪些东西
源码交付不只是把代码打个包发给老师就完事了。一份合格的毕设交付物应该包含:
- 完整的前端小程序工程(可以直接用微信开发者工具打开)。
- 完整的后端工程(包含 SQL 初始化脚本、配置文件、说明文档)。
- 数据库建表脚本(最好带几条测试数据,方便演示)。
- 项目部署说明文档(写清楚 JDK 版本、MySQL 版本、Redis 是否需要、端口号是多少)。
- 演示视频录制一份,防止现场设备出问题时救场。
源码里附带的 SQL 脚本除了建表语句,我还加了预设数据,比如宿舍楼、部分宿舍、几个测试学生账号、几条公告记录。这些数据不是摆设,是为了让演示时页面不那么空,也方便老师现场查看效果。
5.3 后续可以扩展的方向
如果你学有余力,以下几个方向能明显提升项目的“含金量”:
- 接入微信订阅消息,报修状态变更时主动推送给学生,这是现在比较热门的功能点。
- 增加宿舍水电费缴费记录模块,把缴费状态和结算流水做成一个小闭环。
- 加一个数据可视化页面,用 ECharts 展示各楼栋入住率、报修数量趋势、未归学生统计。
就拿我自己带过的项目来说,光是“微信订阅消息推送报修进度”这一点,答辩时老师基本都会眼前一亮。原因很简单,它体现的不只是“你会用某个 API”,而是你真的思考过“系统如何主动触达用户”。
6. 一些实在话
做毕设最大的误解是“代码越多越厉害”,其实评审老师最在意的从来都是“你能不能讲清楚你的设计”。这套宿舍管理系统代码量不大,但每一块都有明确的业务归属和技术考点——登录、权限、事务、并发、状态机、文件上传,全是计算机专业应该掌握的基本功。
如果你现在刚拿到源码,建议你从头到尾把后端接口过一遍,用 Postman 或者 Apifox 逐个测一下,然后对着前端request.js里的接口路径核对一遍,搞清楚每个页面调用了哪些接口、传了哪些参数。这个过程比你看十篇技术博客都管用。等你把“前端页面 -> 后端接口 -> 数据库表”这条链路梳理通了,答辩的时候基本就没有答不上来的问题了。
最后再分享一个我常用的调试技巧:小程序开发工具里的 Network 面板不要关掉,每次请求的耗时、状态码、返回数据全都在那里,很多看着像“页面逻辑问题”的 bug,其实都是接口返回的数据结构和前端预期不一致导致的。先把接口返回看明白,再去看前端代码,排查效率能翻好几倍。