简介《宿舍卫生管理系统的设计与实现》是一份完整的本科毕业设计论文doc文档面向计算机、软件工程及相关专业学生可作为课程设计、毕业设计或实训项目的参考范本。论文针对当前高校宿舍卫生管理仍以人工记录为主、效率低下的问题提出了信息化解决方案系统涵盖宿舍基本信息管理、学生基本信息管理、卫生检查结果管理、结果评估管理和整改意见管理等主要功能模块。包体方面资源包内包含1个doc文件整体大小为2.62MB属于单一文档形式便于直接阅读、编辑和排版复用。目前已有133人学习/下载说明该课题在毕业设计中具有一定代表性。论文内容包含中英文摘要、关键词、目录、概述、系统设计与实现、数据库设计等章节技术选型采用Visual Studio 2010和SQL Server 2008并设计了可视化图形界面。读者可以从中学到完整的论文写作框架、系统功能划分、数据库表结构设计和界面开发思路尤其适合需要快速搭建同类管理系统或撰写相关论文的在校生。1. 寝室卫生管理系统把纸质检查表搬到线上的毕业设计难的不是技术而是“公信力”每年宿舍楼里最让辅导员头疼的事不是查寝本身而是查完之后的“扯皮”。纸质检查表容易丢、容易改Excel 汇总后稍微排序一下就能出排名但学生永远有理由质疑凭什么上周是 A 这周变 C同一间宿舍宿管打 85 分学生干部打 70 分到底听谁的寝室卫生管理系统这个毕业设计核心价值恰恰不在“录入”和“展示”而在于把打分依据、检查时间、检查人、扣分项全部留痕让排名和分数不再是一个黑匣子。这个课题对做毕业设计的同学来说非常友好技术栈主流Java 后端 Web 前端 MySQL业务边界清晰检查、评分、排名、申诉、通知论文素材天然充分。它不需要人工智能算法不需要高并发架构只要把数据库表结构设计得合理、把流程状态流转做对就能拿到一个逻辑完整、能演示、能答辩的系统。适合的人群很明确做 Java Web 方向、想要一个“看起来像回事”的管理系统的本科生。但别急着建表。我见过太多人一开始就扎进代码写了 2000 行才发现评分规则一变表结构就废了宿舍长一申诉流程就走不通了。这一篇我把自己做这类系统时的经验和踩过的坑完整过一遍从技术选型到表设计再到评分算法和避坑清单你照着做就能复现还能答辩时讲清楚。2. 技术选型与系统架构为什么推荐 Spring Boot Vue 3 MySQL 8.02.1 前端用 Vue 3 Element Plus后端用 Spring Boot 3而不是 SSM 或 JSP做寝室卫生管理系统最常见的错误是一上来就纠结框架。我直接给结论后端用 Spring Boot 3.x前端用 Vue 3 Element Plus数据库用 MySQL 8.0。这个组合是当前毕业设计的主流配置网上资料最多遇到问题最容易搜到答案。Spring Boot 内置 Tomcat省去手动配置的麻烦Vue 3 的 Composition API 写页面逻辑比 Options API 更清晰Element Plus 的表单、表格、弹窗组件拿来就能用比你自己写 CSS 快十倍。我为什么不推荐 SSMSpring SpringMVC MyBatis不是说不能用而是 SSM 的 XML 配置太多光配置文件就能写一百多行对本科毕设来说纯属浪费时间。JSP 更不建议前后端不分离改个页面样式还要重启服务演示的时候一旦出问题很难快速修复。后端我建议用 MyBatis-Plus 而不是原生 MyBatis。MyBatis-Plus 提供了通用的 CRUD 方法、分页插件和条件构造器写寝室卫生管理系统的增删改查基本不需要手写 SQL能省下大量时间。当然核心的统计排名 SQL 还是要自己写的这个后面细说。2.2 寝室卫生管理系统的功能边界五个角色和六个模块要把系统做好先要把“谁是用户”想清楚。我一般把用户分成五类系统管理员——维护宿舍楼栋、宿舍、床位、用户账号管理评分项配置。宿舍管理员/宿管阿姨——发起查寝任务录入检查结果处理复查。辅导员——查看所带学生的宿舍卫生情况发起整改要求。宿舍长——查看本宿舍得分、扣分明细提交申诉。学生——查看自己宿舍的分数和排名通常不单独做宿舍长账号即可覆盖。模块上我建议六个功能模块就够了宿舍管理、用户管理、卫生检查、申诉管理、通知公告、数据统计。不要想着做考勤、报修、门禁每多一个模块论文里就要多写一章答辩就要多准备一轮提问。作为一个毕设题目一定要克制。数据流的主线是管理员配置评分项 → 宿管发起查寝任务 → 检查人员逐间打分 → 系统自动计算总分和排名 → 宿舍长收到通知 → 不满意则提交申诉 → 管理员复查并更新结果。这条主线必须在系统里完整跑通否则答辩时会被问“流程不闭环”。2.3 本地跑通最小例子的具体操作步骤我一般会用 Docker 启动 MySQL这样不至于在自己电脑上装一堆东西后把系统搞乱。以下是核心步骤。# 拉取并启动 MySQL 8.0 容器宿主机端口 3306创建数据库 dorm_health docker run -d --name mysql-dorm \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDroot123 \ -e MYSQL_DATABASEdorm_health \ mysql:8.0 \ --character-set-serverutf8mb4 \ --collation-serverutf8mb4_unicode_ci这段命令里-d让容器后台运行--name给容器起名字方便后续操作。MYSQL_ROOT_PASSWORD是 root 密码我在这里故意用了简单的root123仅限本地开发用正式环境必须换成强密码。--character-set-serverutf8mb4和--collation-serverutf8mb4_unicode_ci这两个参数必须加否则 MySQL 默认的 latin1 字符集存中文会乱码。utf8mb4 支持完整的 Unicode 字符包括 Emoji比 utf8 更稳。数据库起来之后在 Spring Boot 项目的application.yml里配置数据源spring: datasource: url: jdbc:mysql://localhost:3306/dorm_health?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: root123 driver-class-name: com.mysql.cj.jdbc.Driver jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8注意serverTimezoneAsia/Shanghai和time-zone: GMT8必须保持一致。我遇到过本地开发一切正常部署到服务器上所有时间都差 8 小时的情况根源就是这两处时区配置不一致。useUnicodetruecharacterEncodingutf8确保 JDBC 传输中文不乱码。前端用 Vite 创建 Vue 3 项目npm create vitelatest dorm-front -- --template vue cd dorm-front npm install element-plus axios npm run dev这一段执行完浏览器打开http://localhost:5173就能看到 Vue 默认页面。接下来在main.js里注册 Element Plusimport { createApp } from vue import ElementPlus from element-plus import element-plus/dist/index.css import App from ./App.vue const app createApp(App) app.use(ElementPlus) app.mount(#app)app.use(ElementPlus)是全局注册组件这样所有.vue文件里直接用el-table、el-form等标签即可不需要逐个 import。对于毕业设计来说全量引入可以接受不用做按需加载省去配置的复杂度。后端启动后访问http://localhost:8080前端通过axios请求后端接口需要配置 Vite 代理让/api开头的请求转发到 8080 端口// vite.config.js export default { server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }changeOrigin: true会让后端认为请求来自 8080 端口避免跨域报错。这里不配代理直接用后端 CORS 也可以但代理是更规范的做法答辩时也能讲清楚这是前后端分离的标准配置。3. 核心数据模型与业务闭环宿舍-床位-成员与“一父两子”检查单3.1 宿舍-床位-成员三表结构设计解决换寝和退宿的备案问题很多同学做寝室卫生管理系统第一版表结构就两级宿舍表和学生表学生表里加一个dorm_id外键。这个设计在静态数据下没问题但一旦有学生换宿舍、休学、毕业退宿历史卫生成绩就全乱了。想想看A 同学第一学期住在 201第二学期换到 305如果他之前记录的所有卫生成绩只关联到“学生”那 201 的卫生历史数据就缺了一段如果关联到“宿舍”又说不清是哪个学生造成的扣分。我习惯的做法是拆成宿舍表dorm、床位表bed、宿舍成员表dorm_member三张表。宿舍和床位是一对多床位和成员是一对一且可空。核心 DDL 如下CREATE TABLE dorm ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 宿舍ID, building_name VARCHAR(50) NOT NULL COMMENT 楼栋名如雅园3号, room_number VARCHAR(20) NOT NULL COMMENT 房间号如301A, dorm_type TINYINT NOT NULL COMMENT 1-四人间 2-六人间 3-八人间, floor_no INT DEFAULT 1 COMMENT 所在楼层, is_active TINYINT DEFAULT 1 COMMENT 是否启用0-停用翻修, UNIQUE KEY uk_building_room (building_name, room_number) ) COMMENT 宿舍表; CREATE TABLE bed ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 床位ID, dorm_id BIGINT NOT NULL COMMENT 所属宿舍ID, bed_no VARCHAR(10) NOT NULL COMMENT 床位号如A1、B2, student_id BIGINT DEFAULT NULL COMMENT 当前占用学生ID空为无人, occupancy_status TINYINT DEFAULT 0 COMMENT 0-空置 1-有人, KEY idx_dorm_id (dorm_id) ) COMMENT 床位表;这里有两个比较关键的设计。第一dorm表用UNIQUE KEY uk_building_room (building_name, room_number)做联合唯一约束防止同一栋楼里录入重复的房间号。第二bed.student_id不是直接指向学生表的主键而是可空的。当一个学生搬走不要删除床位记录只需把student_id置空、occupancy_status置 0。这样换宿历史天然可追溯——通过床位表就能查某个宿舍当前住的是谁也能查某位学生住过哪几个床位。这里不直接写学生表的字段是因为学生信息通常已经存在于学校统一认证中。做毕设时可以在dorm_member表里冗余学号和姓名便于查询。CREATE TABLE dorm_member ( id BIGINT PRIMARY KEY AUTO_INCREMENT, dorm_id BIGINT NOT NULL, student_no VARCHAR(20) NOT NULL COMMENT 学号, student_name VARCHAR(50) NOT NULL COMMENT 姓名, is_dorm_leader TINYINT DEFAULT 0 COMMENT 1-宿舍长 0-普通成员, check_in_date DATE NOT NULL COMMENT 入住日期, check_out_date DATE DEFAULT NULL COMMENT 搬出日期空为在住, KEY idx_dorm_id (dorm_id), KEY idx_student_no (student_no) ) COMMENT 宿舍成员历史表;dorm_member这张表是“历史表”而不是“当前状态表”入住和搬出分别记录日期查询“当前 201 住了谁”只需要过滤check_out_date IS NULL。这样设计的好处是每年奖学金评选需要“某学生在 2023-2024 学年宿舍成绩”时直接按时间段关联即可不需要事后补数据。3.2 卫生检查单的三段式设计检查任务、检查主表、扣分明细寝室卫生检查的业务节奏一般是每周固定时间查一次有时有专项检查比如查大功率电器。如果一张表搞定一切你会发现同一个宿舍同一周的检查数据要改一个扣分项其他字段都得跟着重写。所以我把检查模块设计成“一父两子”三段结构检查任务表check_task、检查记录表inspection、检查明细表inspection_detail。CREATE TABLE check_task ( id BIGINT PRIMARY KEY AUTO_INCREMENT, task_name VARCHAR(100) NOT NULL COMMENT 任务名称如“第12周常规卫生检查”, check_type TINYINT NOT NULL COMMENT 1-常规 2-专项 3-复查, check_date DATE NOT NULL, start_time DATETIME DEFAULT NULL, end_time DATETIME DEFAULT NULL, status TINYINT DEFAULT 0 COMMENT 0-未开始 1-进行中 2-已完成 3-已归档, creator_id BIGINT NOT NULL COMMENT 发起人ID, remark VARCHAR(255) DEFAULT NULL, KEY idx_status (status) ) COMMENT 检查任务表; CREATE TABLE inspection ( id BIGINT PRIMARY KEY AUTO_INCREMENT, task_id BIGINT NOT NULL COMMENT 所属任务, dorm_id BIGINT NOT NULL COMMENT 被检查宿舍, inspector_id BIGINT NOT NULL COMMENT 检查人ID, total_score DECIMAL(5,2) NOT NULL DEFAULT 0 COMMENT 总得分, original_score DECIMAL(5,2) DEFAULT 0 COMMENT 原始得分申诉前, inspect_time DATETIME DEFAULT NULL COMMENT 实际检查时间, status TINYINT DEFAULT 0 COMMENT 0-待检查 1-已检查 2-已申诉 3-已复查 4-已确认, is_abnormal TINYINT DEFAULT 0 COMMENT 1-拒检/无人/锁门, abnormal_reason VARCHAR(100) DEFAULT NULL COMMENT 异常原因, photo_url VARCHAR(500) DEFAULT NULL COMMENT 现场照片URL, remark VARCHAR(255) DEFAULT NULL, UNIQUE KEY uk_task_dorm (task_id, dorm_id) ) COMMENT 检查记录表;inspection表里的UNIQUE KEY uk_task_dorm (task_id, dorm_id)很重要它保证同一个任务下同一间宿舍只有一条主记录。如果需要复查不是在原记录上改状态而是再建一个task_id不同的复查任务。很多同学在这里设计失误复查时直接覆盖原来的分数导致扣分依据丢失——申诉记录里到底哪次检查是有效的必须靠“任务批次”来区分而不是靠修改时间。inspection_detail表存每个检查项的得分和扣分原因CREATE TABLE inspection_detail ( id BIGINT PRIMARY KEY AUTO_INCREMENT, inspection_id BIGINT NOT NULL COMMENT 检查记录ID, item_id BIGINT NOT NULL COMMENT 评分项ID, score DECIMAL(5,2) NOT NULL COMMENT 该项实得分, deduction DECIMAL(5,2) NOT NULL DEFAULT 0 COMMENT 扣分数, deduction_reason VARCHAR(255) DEFAULT NULL COMMENT 扣分原因描述, KEY idx_inspection_id (inspection_id) ) COMMENT 检查明细表;为什么主表里要有total_score和original_score两个分数字段total_score是当前有效分original_score是第一次检查的原始分。宿舍长申诉后管理员复查复查结果写入另一条inspection记录关联复查任务但原始分保留在第一版记录中。这样在论文和答辩演示里能同时展示“申诉前 vs 复查后”的对比是非常加分的细节设计因为很多毕设系统根本没有申诉的历史轨迹。3.3 图片取证、整改复查与申诉流程的状态机设计卫生检查最怕争议。宿管说地面有垃圾学生说那是刚掉落的纸屑。没有照片扯不清。因此inspection.photo_url这个字段用来存检查时的现场照片前端在上传时直接把图片压缩到 200KB 以内再转存到服务器后端只存 URL。照片文件不要直接进数据库这个坑后面会专门讲。状态流转我用一个整数状态字段表达这也是毕业设计里最容易被追问的部分。我的状态设计是0 待检查任务已创建宿舍尚未被检查1 已检查正常扣分明细已录入完毕系统计算出总分2 已申诉宿舍长对分数有异议提交申诉材料3 已复查管理员安排复查并录入复查结果4 已确认宿舍长无异议或申诉超时最终分生效这个状态机的核心约束是一次检查的主记录一旦进入“已确认”状态就不允许再被修改。所有状态变化必须通过 Service 层的方法而不是在 Controller 里直接更新字段。我见过一个翻车例子同事为了省事在 Controller 里直接写inspection.setStatus(2)结果操作权限没校验宿舍长可以自助把状态改成“已确认”流程就乱了套。状态流转的代码逻辑应该封装在服务层用枚举类定义状态并在每次流转时校验上一状态是否合法。public enum InspectionStatus { PENDING(0, 待检查), CHECKED(1, 已检查), APPEALED(2, 已申诉), RECHECKED(3, 已复查), CONFIRMED(4, 已确认); private final int code; private final String desc; }状态统一成枚举避免魔法数字散落在代码各处。后续如果要加“已整改”状态也只需要在这个枚举里加不用满代码找setStatus(5)。4. 从检查表到红黑榜评分模型、周月排名的计算与展示4.1 评分项配置表与权重折算100 分制的关键细节寝室卫生系统的核心是评分规则。常见做法是 100 分制基础分 100 分检查项按重要性设置满分值检查时逐项打分。比如地面清洁满分 30 分、床铺整齐满分 25 分、桌面物品摆放满分 20 分、阳台/卫生间满分 15 分、违规电器扣分项满分 10 分有则倒扣。每个宿舍类型四人间、六人间、八人间对某些检查项的重视程度不同所以评分项最好做成可配置的。// 评分项配置实体 class InspectionItemConfig { Long id; String itemName; // 例如地面清洁 Integer fullScore; // 该项满分 Integer sortOrder; // 检查顺序影响移动端录入顺序 BigDecimal weight; // 加权系数默认1.0 Integer itemType; // 1-常规评分项 2-倒扣项 3-一票否决项 String dormTypeScope; // 适用宿舍类型1,2,3 }这里最容易忽略的是dormTypeScope。八人间的宿舍面积大、物品多“桌面物品摆放”的评分标准应该和四人间不同。如果你在系统里用同一个配置去算所有宿舍宿管阿姨第一个骂娘。我习惯的做法是评分项配置表按宿舍类型拆分四人间和六人间各有独立的一组检查项。这样每间宿舍的“满分”其实是不同的四人间满分 100六人间满分 110最终排名时需要把得分折算成百分制再比较。折算公式为折算分 (实际得分 / 该宿舍类型满分) * 100。这个公式必须在代码里醒目标注因为答辩时评审老师很可能问为什么不同宿舍类型的分数可以直接排名你要回答因为已经做了百分制归一化。4.2 周排名与月排名不要在 SQL 里算“全历史排名”排名是寝室卫生管理系统最显眼的展示功能。周排名就是本周所有宿舍按折算分从高到低排这个用 MySQL 查询很简单。但月排名要注意一个月有四周每周检查的分数都已经百分制归一化月末排名要用“加权平均”而非“简单平均”。比如某宿舍第 1 周 95 分、第 2 周因为被发现违规电器直接记 0 分如果简单平均是 47.5 分看起来没那么严重但加权平均后违规电器权重高才能体现问题的严重性。我推荐的排行方案是每次检查完成时系统实时计算该宿舍的“本周得分”并存到dorm_weekly_score表冗余字段月末统计时直接对这张表聚合。这样做的好处是排名查询响应快不用每次发起都对全部检查明细做 join。CREATE TABLE dorm_weekly_score ( id BIGINT PRIMARY KEY AUTO_INCREMENT, dorm_id BIGINT NOT NULL, week_no INT NOT NULL COMMENT 学年周次如202401表示2024学年第1周, week_start DATE NOT NULL, week_end DATE NOT NULL, raw_score DECIMAL(5,2) DEFAULT 0 COMMENT 原始折算总分, final_score DECIMAL(5,2) DEFAULT 0 COMMENT 最终确认分, rank_no INT DEFAULT NULL COMMENT 本周排名, status TINYINT DEFAULT 0 COMMENT 0-草稿 1-已确认, UNIQUE KEY uk_dorm_week (dorm_id, week_no) ) COMMENT 宿舍周得分汇总表;在 Java 里计算排名时可以使用java.util.ArrayList保存所有宿舍的周得分然后按final_score倒序排列遍历设置rank_no。对于一间几百人的学院来说这个量级完全没有性能问题不需要引入 Redis 有序集合来做排行榜那是过度设计。// 计算某周排名的核心方法 public void calculateWeeklyRank(int weekNo) { ListDormWeeklyScore weeklyScores weeklyScoreMapper.selectByWeek(weekNo); // 按最终确认分从高到低排序 weeklyScores.sort((a, b) - b.getFinalScore().compareTo(a.getFinalScore())); int rank 0; BigDecimal lastScore null; for (int i 0; i weeklyScores.size(); i) { DormWeeklyScore item weeklyScores.get(i); // 分数相同时名次并列即“同分同排名” if (lastScore null || lastScore.compareTo(item.getFinalScore()) ! 0) { rank i 1; lastScore item.getFinalScore(); } item.setRankNo(rank); weeklyScoreMapper.updateRank(item); } }注意这里的“同分同排名”逻辑如果两个人都是 95 分第一个人排名 1第二个人也应该排名 1而不是 2。这个细节会影响红黑榜的展示也容易在答辩时被问到。lastScore.compareTo(...) ! 0用 compareTo 而不是!因为 BigDecimal 不能直接用equals比较数值大小。4.3 红黑榜展示与通知触达宿舍长如何第一时间知道结果红黑榜是“宿舍卫生评比”的可视化输出。红榜前 10%用暖色调突出黑榜后 10%用冷色调警示中间部分正常列表展示。前端用 Element Plus 的el-table加row-class-name自定义行样式即可el-table :datarankList :row-class-namerowClassName el-table-column propbuildingName label楼栋 / el-table-column proproomNumber label房间 / el-table-column propfinalScore label折算分 sortable / el-table-column proprankNo label名次 / /el-table script setup const rowClassName ({ row }) { if (row.rankPercent 10) return red-list-row if (row.rankPercent 90) return black-list-row return } /scriptrankPercent是后端返回的排名百分比前端拿到后直接映射样式类。这里的比例阈值前 10%、后 10%建议做成可配置项因为不同学院的寝室数量和奖惩策略不同硬编码进代码会让你后期改配置时必须重新打包发布。通知触达推荐走两条路一是小程序订阅消息宿舍长在微信小程序里订阅检查结果通知二是邮件兜底。小程序订阅消息的优点是触达率高缺点是申请模板复杂。邮件兜底虽然老土但实现简单一封包含表格的 HTML 邮件发过去逻辑清晰且稳定。我一般会把两个通道都做上小程序消息失败时自动转邮件。5. 寝室卫生管理系统的避坑清单从数据库设计到上线交付的 5 个翻车点5.1 用学号做主键导致换宿、退宿后数据错乱现象学生 A 从 201 换到 305系统会把 A 原来的历史卫生成绩带到 305 宿舍导致 305 的宿舍长发现分数凭空多了一段。原因很多同学下意识把学号作为学生表主键而宿舍卫生检查是“按宿舍维度记录”学生和宿舍的关系是多对多且随时间变化。学号作为主键意味着一个学生在系统里只能有一条“当前宿舍”记录历史变动没有存储空间。解决学生表主键用自增id学号只做普通唯一索引。换宿时新增一条dorm_member记录原记录写入check_out_date而不是 update 原记录。这个教训几乎每个做这类系统的人都踩过属于“数据模型设计阶段的后悔药”——改表结构比改代码难十倍。5.2 检查照片用 Base64 存 MySQL导致接口超过 3 秒现象1920×1080 的照片在手机端直接转 Base64传给后端后端直接存 MySQL。前端检查列表页每次拉取都在等照片数据接口响应从 200ms 涨到 3 秒以上高峰期直接超时。原因Base64 编码让数据体积增大 33%且图片二进制数据写入 MySQL 会撑大 InnoDB 缓冲池拖垮整个库的性能。解决图片先上传到本地服务器磁盘或对象存储数据库只存 URL 地址。上传接口对图片做压缩目标分辨率 1280×720、质量 80%单张控制在 200KB 以内。前端展示时用懒加载不滚动不加载。这样列表接口只管查 URL 字符串响应时间回到毫秒级。这是寝室卫生管理系统里最典型的性能优化点论文里写一章“系统优化”正合适。5.3 定时生成“本周检查任务”的 Cron 表达式不触发现象部署上线后发现每周六早上 8 点的自动检查任务生成功能没执行日志里连报错都没有。本地开发时一切正常。原因服务器时区是 UTC数据库连接时区也是 UTC但业务期望时间是北京时间周六 8:00。Cron 表达式写的是0 0 8 * * 6实际在 UTC 时间 8 点执行换算成北京时间就是下午 4 点。更隐蔽的是Spring Boot 的Scheduled默认对时区无感知它用的是 JVM 默认时区。本地开发时 JVM 时区是 Asia/Shanghai部署到云服务器后默认 UTC所以本地测不出来。解决在启动类或配置里显式指定时区。Configuration public class ScheduleConfig implements SchedulingConfigurer { Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.setScheduler(Executors.newScheduledThreadPool(2)); } }同时在application.yml里设置spring: jackson: time-zone: GMT8 quartz: properties: org.quartz.jobStore.misfireThreshold: 60000实际上最稳妥的方案是不依赖系统的Scheduled而是每天晚上用定时任务扫一遍“明天需要检查的宿舍”生成检查记录后直接入库。这样即使偶尔某一次任务因为服务器重启错过第二天也能自动补上不会影响整个检查流程。5.4 月度排名 SQL 聚合错误SUM 多表 JOIN 时明细重复现象某宿舍的月排名分数是 190 分但每周分数分别是 95、95、90、95怎么算都不是 190。仔细排查发现是SUM(inspection_detail.score)时因为 JOIN 其inspection主表多条记录明细表的分数被累加了两遍。原因这是典型的一对多 JOIN 重复统计。inspection表和inspection_detail是一对多如果一周内该宿舍被检查了两次常规 复查JOIN 后的结果集中每个检查项都出现两次SUM 自然翻倍。解决不要在明细表 JOIN 主表后直接聚合。在周得分计算时先只取inspection主表的final_score按宿舍和任务维度查出一周内所有检查的主表记录再按“最后一次有效检查”取数。实际上我建议干脆不用 SQL 做这个聚合用 Java 代码遍历一遍数据量几百条逻辑清晰且可调试比写复杂的 SQL 子查询靠谱得多。这是典型的“用空间换正确性”的选择毕设阶段不要一味追求 SQL 炫技。5.5 申诉超过 48 小时没人处理宿舍长认为系统是“黑匣子”现象宿舍长提交申诉后如果管理员一周不处理系统没有任何提醒宿舍长觉得分数被系统“吞了”投诉到辅导员那里。原因状态机里没有“超时自动升级”机制。申诉状态长时间停留在2-已申诉既没有通知管理员也没有给学生反馈。解决增加超时提醒任务。申诉提交后 24 小时未处理向管理员推送一条待办提醒48 小时仍未处理自动发短信通知到管理员的上级领导一般是学生工作负责人。在代码里这个逻辑就是定时扫一遍status 2且update_time NOW() - INTERVAL 24 HOUR的记录然后调用通知服务。这个功能不做系统流程不说有问题但答辩时老师一定会问“如果管理员忘了处理怎么办”6. 把 demo 做成能过答辩的完整交付论文结构、数据流图与查重前的自查6.1 论文的目录“五段式”结构不要按教科书抄三层答辩老师看论文的速度很快通常先看目录再看图表最后翻代码。所以我建议论文结构按“五段式”来组织绪论——背景与意义、国内外研究现状、论文组织结构。这一章不用长1500 字左右即可。系统需求分析——角色分析、功能模块图、用例图、数据字典。这里可以放大量表格比如角色权限对照表、评分项配置表。系统概要设计——架构图、功能结构图、流程图重点画检查-申诉-复查的状态流转图。系统详细设计与实现——数据表结构每个字段列清楚、核心算法评分折算、周排名、关键页面截图、核心代码片段。这里是论文最厚的一章也是最容易写的部分。系统测试——用黑盒测试的用例表格展示但不要只写“功能正常”每一个测试用例都要写“预期结果”和“实际结果”。6.2 最值得画的一张图卫生间检查状态流转图我画过的最有价值的图不是 E-R 图而是“卫生检查状态流转图”。把 0-待检查、1-已检查、2-已申诉、3-已复查、4-已确认这五个状态画成五个节点用箭头标出允许转移的路径再在旁边标注“触发条件”和“触发角色”。这张图说出来有三层价值第一证明你真正理解了业务闭环第二论文答辩时可以直接对着这张图讲 10 分钟第三评审老师最容易就着这张图提问你能答上来就稳了。注意画图时不要用太复杂的工具draw.io 就够了。导出 PNG 时分辨率调到 300 DPI论文里插图和表格都要求清晰可读。E-R 图当然也要画但很多同学画的 E-R 图字段不全答辩时被问到“这张表的主外键是什么”答不上来反而扣分。6.3 查重自查清单与部署交付代码块不要直接贴进论文如果你想在论文里贴核心代码建议先做三件事去掉注释里和业务无关的闲聊性文字只保留必要的技术注释。代码缩进用 4 空格字号调小一号保持格式整洁。核心代码摘录只保留核心逻辑每个代码块 20 行左右即可不要整类粘贴。一整段 200 行的 Controller 贴进去查重风险高也没有人看。查重时除了正文文字图表里的字段名、类名也要留意。如果数据库字段命名非常有特色比如dorm_health_2019被查重系统识别出来反而正常不用刻意改。最后是部署交付。答辩一般是在演示现场跑系统最稳妥的方案是用 Docker Compose 一键启动后端、前端、MySQL本地是 Windows 或 macOS 都能跑起来。# docker-compose.yml 核心服务 services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: dorm_health volumes: - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql ports: - 3306:3306 backend: build: ./backend depends_on: - mysql ports: - 8080:8080 environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/dorm_health?serverTimezoneAsia/Shanghai frontend: build: ./frontend ports: - 5173:5173volumes里的./sql/init.sql会在 MySQL 容器首次启动时自动执行这样数据库表结构和示例数据都自动建好不用每台机器手动导入给评审老师演示时也显得专业。注意backend连接数据库的 URL 用的是容器名mysql而不是localhost这是 Docker 内部网络的标准写法本地直接跑单个 Spring Boot 时才是localhost。两处环境不一致答辩前要提前确认我见过演示现场因为这个问题起不来服务急出一身汗。回想我自己做这类系统时最后悔的一件事是在初期没把“宿舍类型”作为评分维度设计进表里导致后期加了六人间之后评分规则硬编码改了好几处。如果你现在刚开始动手建议第一天就把宿舍类型、评分项权重这些“看起来是明细功能”的东西设计好后面能省你好几个通宵。这些边界问题都提前摸一遍你的毕业设计就可以从“能跑”变成“能讲”希望帮到你。本文还有配套的精品资源点击获取