Java+SpringBoot+Vue宿舍报修管理系统:需求分析与数据库设计

发布时间:2026/11/4 10:14:19
Java+SpringBoot+Vue宿舍报修管理系统:需求分析与数据库设计

简介:这份资源面向计算机专业学生与Java Web初学者,提供一套基于Java的宿舍报修管理系统完整毕业设计资料,包含论文与源码,可用于课程设计、毕业设计参考或校园后勤维修管理场景的技术学习。压缩包共1个docx文件,约4.78MB,内容为系统设计与实现的完整论文文档,涵盖摘要、绪论、相关理论与技术、系统分析等章节,后端采用Java语言与SpringBoot框架,前端使用Vue,数据库为MySQL,并借助Navicat与IDEA、Tomcat完成开发部署。系统功能覆盖用户管理、维修员管理、宿舍类型与信息管理、配件分类与设备管理、维修类型管理、宿舍分配、报修信息与接单管理、配件申请及维修进度管理等模块,论文对可行性分析、需求与设计思路均有展开。目前已有433人学习,适合需要理解SpringBoot+Vue前后端分离项目结构、撰写同类论文或搭建报修管理系统的读者参考借鉴。

1. 从一张手写报修单说起:这套系统到底要解决什么

宿舍楼管桌上那本翻烂的报修登记簿,大概是很多后勤管理者最熟悉的“黑匣子”——学生写一句“灯不亮”,宿管抄一遍,维修师傅来了再问一遍是哪个房间,修完了没人记录换了什么配件。信息在三个角色之间反复传递,每一次传递都在丢东西。这套基于 Java + SpringBoot + Vue + MySQL 的宿舍报修管理系统,要解决的就是这条链路上的信息断层:让学生在线下单、维修员在线接单、管理员在线调度配件和进度,把“口头报修、纸面登记”换成一条可追溯的数据流。它适合正在做 Java Web 方向毕设或课程设计的同学直接参考整体结构,也适合需要给小型园区、公寓楼做一套轻量报修流程的开发者拿来改。下面按需求、设计、实现、避坑、验收的顺序,把这份方案拆开讲透。

2. 需求与角色分析:三类用户、十二条功能线怎么划

2.1 先定角色,再谈功能

很多同学一上来就画功能模块图,结果画到一半发现“谁能删这条报修单”说不清楚。这套系统的角色划分很干脆:管理员、用户(学生/住宿者)、维修员。三个角色对应三条完全不同的操作路径,功能清单必须挂在角色下面才有意义。

用户侧的核心动作只有五个:注册登录、查宿舍信息、提交报修、查自己的报修记录、看维修进度。注意“查宿舍信息”不是可有可无的,报修单里的宿舍名称、房间号、床位号都依赖宿舍分配数据,用户得先能看到自己住哪,报修时才能选对位置。

维修员侧是:登录注册、查配件、申请配件、接单、查报修、更新维修进度。这里有个容易被忽略的点——维修员不是直接改配件库存,而是“申请”,由管理员审批。这个设计把库存变更的权限收口到管理员手里,避免维修员各自为政把库存改乱。

管理员侧最重,十二条管理线里有九条归他:用户管理、维修员管理、宿舍类型管理、宿舍信息管理、配件分类管理、配件设备管理、维修类型管理、宿舍分配管理、报修信息管理、报修接单管理、配件申请管理、维修进度管理。看着多,其实可以归成四组:基础数据(宿舍类型/宿舍信息/配件分类/配件设备/维修类型)、人员(用户/维修员)、业务流转(报修信息/报修接单/配件申请/维修进度)、分配(宿舍分配)。

2.2 功能需求落到用例上

把上面的清单转成用例,用户用例是“宿舍信息查询、报修信息查询、接单信息查询、维修进度查询、登录、注册、宿舍报修”;维修员用例是“配件查询、配件申请、任务接单、报修查询、维修进度查询、登录、注册”;管理员用例覆盖全部十二条管理线。写论文或方案文档时,这三张用例图是系统分析章节的骨架,别省。

2.3 非功能需求别写成套话

原文提了可靠性、稳定性、可扩展性、易于维护性四条。这四条要落到可检验的表述上才有价值:可靠性指登录和报修数据录入在并发提交时不丢单;稳定性指连续操作两小时不出现白屏或接口 500;可扩展性指新增一种维修类型不需要改代码,只在维修类型管理里加一条记录;易于维护性指接口异常时有统一返回结构和日志可查。写方案时把这四条翻译成这样的句子,答辩时老师追问“你怎么保证稳定性”,你才有话答。

提示:需求分析阶段就把“配件申请需要管理员审批”这条写进流程图,后面数据库设计和接口设计都会顺很多,否则做到一半才发现库存表没有审批状态字段,返工成本很高。

3. 总体架构与技术选型:前后端分离下的四层结构

3.1 为什么是 SpringBoot + Vue 这套组合

后端 Java + SpringBoot,前端 Vue,数据库 MySQL,开发工具 IDEA + Navicat,服务器 Tomcat。这套组合在高校毕设里出现频率极高,原因不玄学:SpringBoot 把 XML 配置砍掉大半,起步快;Vue 的组件化让列表页、表单页可以复用;MySQL 免费、资料多、Navicat 可视化建表省事。对一个人要独立完成前后端加论文的项目来说,选型的首要标准不是“先进”,而是“每一层你都能自己调通”。

需要说清楚的是 Tomcat 的位置:SpringBoot 内嵌了 Tomcat,打成 jar 直接跑,不需要单独部署一个外部 Tomcat。原文写“IDEA 服务器的搭建使用 Tomcat 来完成”,实际落地时通常是 IDEA 里直接启动 SpringBoot 主类,内嵌容器就是 Tomcat。方案文档里可以这么表述,但代码层面别去配外部 Tomcat,多一层就多一个翻车点。

3.2 四层结构怎么分

整体按前后端分离组织,逻辑上分四层:

  • 表现层:Vue 单页应用,按角色渲染不同菜单,登录后把 token 存本地,每次请求带上。
  • 接口层:SpringBoot 的 Controller,按业务域拆成用户、宿舍、报修、配件、进度等控制器,统一返回结构。
  • 业务层:Service,处理“接单后状态怎么变”“配件申请通过后库存怎么扣”这类规则。
  • 数据层:MyBatis 或 JPA 映射到 MySQL,表结构对应前面列的实体。

前端通过 axios 调后端 REST 接口,跨域在开发期用代理解决,生产期同源部署。这个结构的好处是每一层职责清晰,答辩时被问“你的业务逻辑写在哪”,能明确指到 Service 层,而不是全堆在 Controller 里。

3.3 统一返回结构先定下来

接口返回格式要在写第一个接口前定死,不然后面十几个控制器各写各的,前端处理起来很痛苦。通常的做法是定义一个通用结果类:

// 统一接口返回结构,code=200 表示成功,其余为业务错误码 public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> success(T data) { Result<T> r = new Result<>(); r.code = 200; r.message = "操作成功"; r.data = data; return r; } public static <T> Result<T> fail(Integer code, String message) { Result<T> r = new Result<>(); r.code = code; r.message = message; return r; } }

code用 200 表示成功,401 表示未登录或 token 失效,500 表示服务端异常,业务错误(比如“该报修单已被接单”)用 4xx 段自定义码。data泛型承载列表或对象。前端拦截器统一判断code,非 200 弹提示,401 跳登录页。这个约定一旦定下,后面所有接口都照此返回,联调时能省掉大量“这个接口返回的字段名怎么又不一样”的扯皮。

4. 数据库设计:从 E-R 到十二张表的落地

4.1 实体与关系先理清

系统里的核心实体有六个:管理员、用户、维修员、宿舍、配件、报修单。关系上,一个用户对应一条或多条宿舍分配记录(换宿舍的情况),一条报修单属于一个用户、关联一个宿舍、可被一个维修员接单、产生若干条配件申请和进度记录。E-R 图里把“报修单”放在中心,它连接用户、维修员、宿舍、配件四个实体,这个中心位置决定了后面表设计的关联字段往哪放。

4.2 关键表结构

原文给了管理员表、token 表、宿舍信息表、用户表、宿舍类型表、宿舍分配表的结构。挑几张关键的说明设计意图。

管理员表users字段是 id、username、password、role、addtime。role字段区分角色,虽然叫管理员表,实际可以承载多角色账号,登录时按 role 分流到不同首页。密码字段长度 10 偏短,实际落地建议放宽到 64 并存加密后的值,原文没写加密,但这是合格负责人的常规做法。

token 表是这套系统的一个实用设计:id、userid、username、tablename、role、token、addtime、expiratedtime。tablename记录这个 token 属于哪张用户表(用户表还是维修员表),因为不同角色存在不同表里,登录校验时要靠它定位。expiratedtime做过期控制,前端每次请求带 token,后端查这张表判断有效性。这比纯 JWT 多一次查库,但实现简单、能主动踢人下线,对毕设场景够用。

宿舍信息表sushexinxi字段较多:宿舍名称、宿舍类型、宿舍分类、宿舍楼、房间号、可住人数、已住人数、有床位、更新时间、宿舍详情。这里“可住人数/已住人数/有床位”三个字段是冗余设计,理论上可由宿舍分配表统计得出,但列表页要频繁展示,冗余存一份能避免每次聚合查询,属于用空间换查询效率的常见取舍。代价是分配或退宿时要同步更新这三个字段,这个同步逻辑必须写在 Service 里,不能靠手动改。

宿舍分配表sushefenpei记录宿舍名称、类型、分类、楼、房间号、用户账号、用户姓名、床位号、分配日期、备注。它和宿舍信息表有字段重叠,这是反范式的结果——分配记录要保留当时的快照,即使宿舍信息后来改了,历史分配记录也不该跟着变。

4.3 建表时的两个约定

一是所有表统一带id主键(bigint 自增)和addtime(timestamp 默认 CURRENT_TIMESTAMP),排序和排查问题时直接按时间倒序,不用额外加字段。二是状态类字段用整型或短字符串枚举,比如报修单状态用 0 待接单、1 已接单、2 维修中、3 已完成、4 已取消,别用中文直接存,前端映射显示文案,后期加状态不用改表结构。

-- 报修信息表核心字段示例,状态用整型枚举便于流转控制 CREATE TABLE baoxiuxinxi ( id BIGINT PRIMARY KEY AUTO_INCREMENT, addtime TIMESTAMP DEFAULT CURRENT_TIMESTAMP, baoxiubianhao VARCHAR(32) NOT NULL, -- 报修单号,业务唯一 yonghuzhanghao VARCHAR(20) NOT NULL, -- 报修人账号 sushemingcheng VARCHAR(20), -- 宿舍名称 fangjianhao VARCHAR(20), -- 房间号 weixiuleixing VARCHAR(20), -- 维修类型 baoxiuneirong TEXT, -- 故障描述 zhuangtai INT DEFAULT 0, -- 0待接单 1已接单 2维修中 3已完成 4已取消 weixiuyuanzhanghao VARCHAR(20), -- 接单维修员账号,未接单为空 INDEX idx_yonghu (yonghuzhanghao), INDEX idx_zhuangtai (zhuangtai) );

baoxiubianhao单独做业务单号,方便用户口头报单号查询;zhuangtai加索引,因为管理员列表页最常按状态筛选;weixiuyuanzhanghao为空表示未接单,接单时写入,这个字段同时承担“是否已被接单”的判断职责,不用再加布尔字段。

5. 核心模块实现:登录、报修流转与配件申请

5.1 登录与 token 校验

登录接口接收账号密码,按角色查对应表,校验通过后生成 token 写入 token 表,返回给前端。前端存本地,后续请求在请求头带 token。后端用一个拦截器统一校验:

// 登录拦截器:放行登录注册接口,其余请求校验 token 有效性 public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String uri = request.getRequestURI(); if (uri.contains("/login") || uri.contains("/register")) { return true; // 登录注册直接放行 } String token = request.getHeader("token"); if (token == null || token.isEmpty()) { writeFail(response, 401, "未登录"); return false; } // 查 token 表,判断是否存在且未过期 TokenEntity t = tokenService.getByToken(token); if (t == null || t.getExpiratedtime().before(new Date())) { writeFail(response, 401, "登录已失效,请重新登录"); return false; } return true; } }

拦截器注册时排除登录、注册和静态资源路径。writeFail往 response 写统一 JSON,前端拦截器收到 401 清本地 token 并跳登录页。这里的关键是 token 表要记录tablename,校验通过后把当前用户信息放进 request 上下文,后续 Controller 取当前登录人时直接用,不用前端再传一遍账号——前端传的账号不可信,这是权限控制的基本盘。

5.2 报修单的状态流转

报修单是整个系统的业务主线,状态流转必须收口在一个 Service 方法里,不能各个 Controller 随手改zhuangtai。流转规则是:用户提交生成待接单(0);维修员接单变已接单(1)并写入维修员账号;维修员开始维修变维修中(2);维修完成变已完成(3);用户或管理员可取消未接单的单(4)。每次流转写一条维修进度记录,进度表存报修单号、状态、操作人、操作时间、说明。

// 接单操作:校验状态后更新,防止两个维修员同时接同一单 @Transactional public Result<String> acceptOrder(String baoxiubianhao, String weixiuyuanzhanghao) { BaoxiuEntity order = baoxiuMapper.selectByBianhao(baoxiubianhao); if (order == null) { return Result.fail(404, "报修单不存在"); } if (order.getZhuangtai() != 0) { return Result.fail(400, "该单已被接单或已取消"); } // 带状态条件的更新,影响行数为 0 说明被并发抢先 int rows = baoxiuMapper.acceptIfPending(baoxiubianhao, weixiuyuanzhanghao); if (rows == 0) { return Result.fail(409, "手慢了,该单已被其他维修员接走"); } progressService.add(baoxiubianhao, 1, weixiuyuanzhanghao, "维修员接单"); return Result.success("接单成功"); }

acceptIfPending对应的 SQL 是UPDATE baoxiuxinxi SET zhuangtai=1, weixiuyuanzhanghao=? WHERE baoxiubianhao=? AND zhuangtai=0。先查再改在并发下会翻车:两个维修员同时查到状态 0,都判断可接,然后都更新成功,一单被两人接。带AND zhuangtai=0的条件更新让数据库来保证原子性,影响行数为 0 就说明被别人抢先了。这个细节答辩时讲出来,比背十页理论都管用。

5.3 配件申请与库存扣减

维修员修东西要换配件,流程是:维修员提交配件申请(报修单号、配件、数量),管理员审批,通过后扣减配件库存并记录。库存扣减同样要防超卖:

// 审批通过:先条件扣库存,再改申请状态,同一事务 @Transactional public Result<String> approve(Long shenqingId) { ShenqingEntity sq = shenqingMapper.selectById(shenqingId); if (sq == null || sq.getZhuangtai() != 0) { return Result.fail(400, "申请不存在或已处理"); } // 库存充足才扣,影响行数为 0 表示库存不足 int rows = peijianMapper.reduceStock(sq.getPeijianId(), sq.getShuliang()); if (rows == 0) { return Result.fail(400, "配件库存不足,无法通过"); } shenqingMapper.updateZhuangtai(shenqingId, 1); // 1 表示已通过 return Result.success("审批通过"); }

reduceStock的 SQL 是UPDATE peijian SET kucun = kucun - ? WHERE id = ? AND kucun >= ?。把“库存够不够”的判断交给 WHERE 条件,而不是先查再减,避免并发下扣成负数。审批和扣库存放在同一个@Transactional里,任何一步失败整体回滚,不会出现“申请通过了但库存没扣”的脏数据。

5.4 宿舍分配与人数同步

宿舍分配新增一条记录时,要同步更新宿舍信息表的已住人数和有床位字段。这个同步写在分配 Service 的同一个事务里:插入分配记录后,按宿舍名称统计当前分配人数,回写宿舍信息表。退宿或换宿舍时反向操作。之所以用统计回写而不是简单加一减一,是因为换宿舍、删记录等操作容易让计数漂移,每次按实际记录数重算虽然多一次查询,但数据永远对得上,这是用一点性能换数据一致性,在宿舍规模不大的场景完全划算。

6. 避坑与排查:五个最容易翻车的点

6.1 跨域配置写了但预检请求还是 403

现象是前端调接口浏览器报 CORS 错误,后端日志看不到请求。原因通常是只配了addCorsMappings允许来源,但拦截器把 OPTIONS 预检请求也拦了,预检没通过,真实请求根本发不出去。解决是在拦截器preHandle里对OPTIONS方法直接返回 true,或者用过滤器在拦截器之前处理跨域。开发期也可以用前端代理绕开,但生产同源部署时这条配置仍要写对。

6.2 token 过期后前端一直弹登录框

现象是 token 过期,用户点任何操作都弹“请重新登录”,关掉又弹。原因是前端拦截器对 401 的处理没有去重,一个页面同时发三个请求,三个都返回 401,弹三次。解决是在拦截器里加一个标志位,第一次 401 时清 token 跳登录页,后续 401 直接丢弃;或者用 Promise 队列让并发请求等登录完成后再重放。这个坑不致命但体验极差,答辩演示时很容易被撞上。

6.3 报修单列表按状态筛选查不到数据

现象是管理员选“已接单”筛选,列表为空,但数据库里明明有状态 1 的记录。原因多半是前端传的是字符串"1",后端实体字段是 Integer,MyBatis 拼接时类型不匹配,或者状态枚举前后端定义不一致(前端 1 代表待接单,后端 1 代表已接单)。解决是把状态枚举统一定义在一处,前后端都引用同一份约定,接口参数用整型接收并在文档里写清每个值的含义。这类问题排查时先看后端收到的参数值,再看 SQL 日志,两步就能定位。

6.4 配件库存扣成负数

现象是并发审批时库存出现负数。原因就是前面说的先查再减。解决是改成条件更新WHERE kucun >= ?,判断影响行数。已经出现负数的,写一个修复脚本按实际出入库记录重算库存回写。这个坑在演示时不一定触发,但代码评审或答辩追问时是高频问题,提前改掉能加分。

6.5 删除宿舍类型导致宿舍信息页报错

现象是管理员删了一个宿舍类型,宿舍信息列表页加载失败或类型显示空白。原因是宿舍信息表里存的是类型名称字符串,删类型不影响已有数据,但前端下拉框取不到该选项,或者后端关联查询时按类型名匹配不到。解决有两个方向:一是删除前校验是否被引用,被引用则禁止删除并提示;二是关联字段改存类型 id 而不是名称。毕设场景推荐第一种,改动小、逻辑直观,在删除接口里加一次引用计数查询即可。

注意:上面五个点里,6.2 和 6.4 是演示环节最容易暴露的,建议在联调阶段就专门造数据压一遍,别等到答辩前一天才发现。

7. 验收与答辩:怎么证明这套系统真的能跑

验收不是把功能点挨个点一遍就完事,要有能拿出手的证据链。我一般按三步走。

第一步,功能验收对照需求清单逐条打勾,但每条要配一个具体操作路径和数据。比如“报修接单管理”这条,验收动作是:用户 A 提交报修单,维修员 B 登录看到待接单列表,接单后状态变已接单,用户 A 的进度页出现“已接单”记录,管理员列表按状态筛选能查到。一条链路串起三个角色,比单独点三个页面有说服力。测试用例表可以这么组织:

用例编号测试功能前置条件操作步骤预期结果
TC-01用户登录账号已注册输入正确账号密码点登录跳转用户首页,token 写入本地
TC-02登录失败账号已注册输入错误密码提示密码错误,不跳转
TC-03提交报修用户已登录且有宿舍分配选宿舍、填故障描述提交生成待接单报修单,列表可见
TC-04维修员接单存在待接单报修单维修员点接单状态变已接单,其他维修员不可再接
TC-05配件审批扣库存存在待审批申请且库存充足管理员点通过申请状态变已通过,库存减对应数量
TC-06配件审批库存不足申请数量大于库存管理员点通过提示库存不足,申请状态不变

第二步,异常路径验收。正常流程谁都能跑通,答辩老师更爱问异常:重复接单会怎样、库存不足会怎样、token 过期会怎样、删除被引用的类型会怎样。把 6.1 到 6.5 那几个坑对应的场景各测一遍,记录实际返回,这比只演示成功路径更能说明系统健壮。

第三步,答辩陈述控制在五分钟内,结构是:一句话说清解决什么问题,一张架构图说清技术分层,一条报修全流程串起三个角色,最后主动讲一个你踩过的坑和怎么解决的。最后这点特别重要——主动暴露一个已解决的问题,比被问出来强得多。比如讲接单并发那个条件更新,既展示了思考深度,又堵住了“两个人同时接单怎么办”的追问。

从那以后我每次带人做这类系统,都强制在联调前把状态流转和库存扣减的并发场景先写测试跑一遍,再开始堆页面。页面做得再花,一条数据对不上就全盘失信。希望这套结构和验收思路能帮到你,把方案落到自己的项目里时,按你的实际表结构和角色再对一遍,别照抄字段名。

本文还有配套的精品资源,点击获取