☰
Spring Boot学生公寓报修平台:需求、设计、部署全解析
2026/10/3 9:54:06 网站建设 项目流程

学生公寓报修平台,听起来像是一个常见的课程设计题目,但真正动手做一遍以后会发现,里面涉及Spring Boot框架、源码工程、数据库设计、调试部署和开发环境搭建整整一条链路。我最近完整做了一个这样的项目,配套的源码、数据库脚本、调试部署环境和万字论文文档都整理好了,今天就把从需求拆解到最终交付的整个过程重新讲一遍。这篇文章适合正在做毕业设计或课程设计的同学,也适合想用Spring Boot快速搭建管理系统的开发者。我会从业务拆分、技术选型、表结构设计、功能实现、部署排查到论文写作,把每个环节里最容易被忽略的细节都摊开来说,尽量做到拿过去就能参考。

1. 学生公寓报修平台的业务梳理与功能拆分

1.1 报修不是“填个表”,而是完整的状态流转

先讲一个我做完这个项目后最深的体会:这类系统的核心不在增删改查,而在报修单的“状态流转”。学生提交一个报修单,它不会瞬间变成已完成,中间至少要经过审核、接单、维修、验收这几个环节。如果上来就建表写接口,很容易写到一半发现维修工看不到待接单列表,或者学生没法确认完成,原因就是业务流没有提前梳理清楚。

我在开发前的实际做法,是把完整流程列成一条条动作:

  1. 学生登录后填写报修单,填写楼栋、房间号、故障类别、详细描述,可选上传图片,保存后状态为“待审核”。
  2. 宿管或平台管理员查看新报修单,审核通过后状态变为“待接单”,审核不通过则退回给学生并填写原因。
  3. 维修工在“待接单”列表里看到单子,选择接单,状态变为“维修中”,同时记录接单人和接单时间。
  4. 维修完成后,维修工填写维修结果,状态变为“待验收”。
  5. 学生看到结果后可以确认完成,也可以申请返工,确认完成后状态变为“已完成”,最后还可以给本次维修评分。

这套流程的价值在于每个状态都有明确负责人和时间点,出了问题随时可追溯。哪怕是一个课设级别的管理系统,我也不建议省掉审核或验收环节,否则报修就变成了一锤子买卖,学生体验和后期的数据统计都会很难受。

实际操作时,我建议把状态定义成常量或枚举,比如0待审核、1待接单、2维修中、3待验收、4已完成、5已驳回、6已取消。千万不要用“0和1”两个值走天下,后面做统计和前端筛选时会非常痛苦,状态含义不清晰还会导致论文里的流程图没法画。

1.2 角色权限拆分:四类用户,各管一段

学生公寓报修平台至少需要四个角色:学生、维修工、管理员、超级管理员。角色不同,看到的菜单和可执行操作完全不同。

学生端主要处理自己的报修单:提交报修、查看进度、确认完工、评价、修改个人资料。维修工端负责执行维修任务:查看待接单列表、接单、填写维修结果、查看历史工单。管理员端做整体管控:审核报修单、指派维修工、查看全量报修单、处理评价、发布公告。超级管理员在管理员基础上还要能管理用户账号、查看统计数据、导出报表。

从实现角度看,一张user表加role字段就能区分四种角色。前端根据角色控制菜单显示,后端在拦截器或方法入口校验角色权限。这里有一个很典型的漏洞:很多人把前端按钮用v-if隐藏了就以为权限控制完成了,其实直接调用后端接口还是可以操作。权限是安全边界,必须后端校验,前端只是用户体验的一部分。

如果想让代码整洁一点,可以把角色校验抽成注解,比如@RequireRole("admin"),在拦截器里统一读取当前登录用户的角色并判断。这种设计在答辩时也比较容易讲清楚。

1.3 功能清单:先做核心,再谈扩展

很多同学一上来就想加短信通知、实时聊天、在线支付,结果到答辩的时候核心流程都没跑通。我的建议是分版本做。第一版必须有:用户登录注册、报修单提交、报修单列表(学生、维修工、管理员不同视角)、状态流转操作(审核、接单、完工、验收)、基础统计(本月报修数、完成率、未完成列表)。第二版再做公告通知、维修评价、按楼栋筛选统计、图片上传、消息提醒。

我最终实现的平台包含了第一版全部功能,并加上了维修评价和楼栋统计。做规划时用了一张优先级表格,很实用:

功能模块核心程度实现要点
用户登录注册必做密码加密、角色区分
报修单提交必做图片上传、故障分类
报修单列表必做分页查询、关键词搜索
状态流转必做事务控制、条件更新
审核与派单必做管理员操作日志
维修评价建议关联报修单、星级评分
数据统计建议按时间和楼栋聚合

有了这张表,开发时就不会在旁枝末节上浪费太多时间。先把主流程打通,再回头优化体验,这是做管理系统的通用节奏。

2. 技术选型与开发环境准备

2.1 为什么选择Spring Boot,版本怎么定

报修平台用Spring Boot来做,几乎是最稳妥的选择。Spring Boot通过starter依赖和自动配置,把以前SSM框架里大量的XML配置省掉了,内置Tomcat,一个main方法就能启动Web服务。对课程设计或毕业设计来说,能极大减少环境配置的时间,把精力集中在业务代码上。

但版本选择有一个很容易踩的坑:很多人直接去官网下最新的Spring Boot 3.x,然后发现JDK版本、javax命名空间、第三方库兼容性全变了。我实际用的是Spring Boot 2.7.18配JDK 1.8,这个组合最成熟,网上教程和踩坑记录也最多。如果你本机已经装了JDK 17,用Spring Boot 2.7.x同样可以,但要注意pom里编译参数和部分依赖版本;如果非要用Spring Boot 3.x,则需要JDK 17及以上,而且很多代码里的import javax.*要改成jakarta.*。

结合“springboot版本太高”这个很常见的翻车点,我的个人建议是:做课设或者想快速出成果,就老老实实用2.7.x,没必要追最新。最新版本确实有很多新特性,但处理兼容问题的时间往往比写代码还多,对项目交付来说完全没必要冒险。

2.2 开发环境搭建:从JDK到Postman

“调试部署+开发环境”是这个项目的关键交付环节。环境不统一,项目换一台电脑就会出现各种诡异问题。我推荐的最小环境清单如下:

  • JDK 1.8或11,配置好JAVA_HOME环境变量
  • Maven 3.6.3或3.8.x,配置阿里云镜像加速依赖下载
  • IntelliJ IDEA,安装Lombok插件并开启注解处理
  • MySQL 5.7或8.0,推荐8.0,注意时区参数
  • Navicat或DataGrip,作为数据库客户端
  • Postman或Apifox,用于调试后端接口

以IDEA为例,第一次打开项目后要重点检查三处:Project SDK是否指向JDK 1.8、Maven的settings.xml是否生效、Lombok插件是否安装。很多初学者报错“cannot resolve symbol log”或者“程序包lombok不存在”,十有八九是插件没装好,或者IDEA里的注解处理没有开启。

Maven镜像配置也很关键,不配置镜像的话下载Spring Boot依赖能卡到崩溃。在settings.xml的mirror节点中加入阿里云镜像:

<mirror> <id>aliyunmaven</id> <mirrorOf>central</mirrorOf> <name>Aliyun Public Repository</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>

配置完以后,在IDEA里重新reimport项目,依赖下载速度会明显提升。这个步骤能解决80%的Maven依赖下载慢问题,值得第一步就做。

2.3 项目依赖与包结构怎么组织

我用的是Spring Boot + MyBatis-Plus的组合。为什么不用JPA?因为MyBatis-Plus写复杂SQL更直观,尤其是报修列表需要按不同角色做多条件筛选,用QueryWrapper能省很多代码。pom.xml里的核心依赖大概是这样:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>

注意Spring Boot 2.7.x自带依赖管理,spring-boot-starter-web可以不写版本号,但MyBatis-Plus不在Spring Boot的托管范围内,必须自己加version。另外MySQL驱动在2.7.x里也可以省略版本号,但如果换新版驱动,驱动类名可能是com.mysql.cj.jdbc.Driver,配置数据源时要写对。

包结构我建议这样分:controller负责接收请求和返回JSON,service写业务逻辑尤其是状态流转,mapper做数据访问,entity放数据库表实体,config放拦截器和跨域配置,common放统一返回结果、常量和异常处理。分层的核心逻辑是让每个类只关心自己这一层的事。很多人喜欢把所有逻辑堆在controller里,前期写起来快,后面改一个字段要翻很多文件,非常痛苦。

3. 数据库设计和核心功能从零实现

3.1 核心表设计:六张表搞定主流程

做管理系统,数据库设计基本决定了后面的开发效率。我的做法是先画ER图,再写建表SQL,最后再多写代码。核心表没有想象中那么多,把用户表、报修单表、评论表、公告表、操作日志表建好,主流程就通了。

下面是报修单表的简化版建表SQL,这也是整个系统最核心的一张表:

CREATE TABLE `repair_order` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `order_no` varchar(32) NOT NULL COMMENT '报修单号', `student_id` bigint(20) NOT NULL COMMENT '提交学生id', `building` varchar(50) DEFAULT NULL COMMENT '楼栋', `room` varchar(20) DEFAULT NULL COMMENT '房间号', `category` varchar(30) DEFAULT NULL COMMENT '故障类别', `description` varchar(500) DEFAULT NULL COMMENT '故障描述', `image_url` varchar(255) DEFAULT NULL COMMENT '图片地址', `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态', `assignee_id` bigint(20) DEFAULT NULL COMMENT '维修工id', `audit_remark` varchar(200) DEFAULT NULL COMMENT '审核备注', `create_time` datetime DEFAULT NULL COMMENT '提交时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报修单表';

有几个细节值得注意。第一,字符集一定要用utf8mb4而不是utf8,因为utf8在MySQL里存不了emoji和部分生僻字;第二,状态用tinyint而不是varchar,查询和统计效率更高,也更容易保证数据一致性;第三,我倾向不在表结构里加物理外键约束,逻辑上关联就够了。比如student_id和assignee_id,完全由代码保证关联关系,数据库层加外键会影响插入性能和后续扩展。

其他表设计也比较常规:user表保存用户基础信息和角色,comment表关联报修单记录评价内容,notice表保存公告,operation_log表保存关键操作日志。操作日志表虽然看起来优先级不高,但强烈建议加一张,后面排查问题和写论文测试章节都用得上。

3.2 登录认证与权限拦截器的实现

登录认证我用了简单的Session方案,没有引入Spring Security。原因很简单:报修平台角色少、接口也不多,Spring Security的过滤器链配置反而增加理解成本。密码加密用Spring自带的BCryptPasswordEncoder,这是一个被广泛验证过的加密算法。

BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); String rawPassword = "123456"; String encoded = encoder.encode(rawPassword); boolean match = encoder.matches(rawPassword, encoded);

很多系统被拖库后用户密码大面积泄露,就是因为密码表里存的是明文。BCrypt每次加密会生成不同的盐,相同密码加密后的结果也不一样,即使数据库泄露,也无法直接反推出原始密码。这个点在答辩时经常会被问到,能讲清楚很加分。

拦截器的核心逻辑是,从Session里取出当前登录用户,没取到就返回401,取到了再判断当前请求是否需要特定角色。由于前后端分离,前端Vue会先控制菜单,后端还需要再校验一次,防止直接调用接口越权。核心代码类似这样:

public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { User user = (User) request.getSession().getAttribute("loginUser"); if (user == null) { response.setStatus(401); return false; } String requireRole = request.getHeader("X-Require-Role"); if (StringUtils.hasText(requireRole) && !requireRole.equals(user.getRole().toString())) { response.setStatus(403); return false; } return true; } }

然后在WebConfig里注册拦截器,并放行登录、注册和静态资源路径。这里有一个新手很容易犯的错:忘记放行登录接口,导致页面能打开但登录功能一直404,排查半天才发现是被拦截器拦掉了。

3.3 报修单状态流转:事务、并发和状态机

状态流转是整个项目最难也最核心的部分。最基本的思路是:不要在Controller里直接允许前端修改status字段,而是定义好业务方法,例如submitRepair、auditOrder、assignOrder、finishRepair、confirmFinish。每个方法只允许从指定状态流转到下一个状态。

一个典型的反面案例是:前端传什么status,后端直接无条件update,这样学生可以把自己的单子直接改成已完成,维修工可以跳过接单直接改完工,整个流程就失去意义了。我实际采用的方式是条件更新,把状态判断放到update的where条件里,这样还能天然解决并发问题:

@Transactional(rollbackFor = Exception.class) public boolean assignOrder(Long orderId, Long workerId) { UpdateWrapper<RepairOrder> wrapper = new UpdateWrapper<>(); wrapper.eq("id", orderId) .eq("status", RepairStatus.WAITING_ASSIGN.getCode()) .set("status", RepairStatus.REPAIRING.getCode()) .set("assignee_id", workerId) .set("update_time", new Date()); return repairOrderMapper.update(null, wrapper) == 1; }

这个技巧在并发场景下很有效。假如两个维修工同时点了同一个单子,数据库层面只有一个update会成功,影响行数为1,另一个影响行数为0,从而避免了重复接单。用这个写法之后,不需要额外的分布式锁,也不需要耗时地查了再改,性能和正确性都能兼顾,这是学生项目里很显技术含量的写法。

同时,所有涉及多表写入的操作都要加@Transactional。比如确认完工时不仅要更新repair_order状态,还要插入一条评论记录,如果第二步失败,第一步也不能留下。事务的rollbackFor一定要写成Exception.class,否则只拦截RuntimeException,遇到受检异常还是会出问题。

状态定义最好用枚举或常量类,不要用魔法数字散落在代码里。我定义了一个RepairStatus枚举,包含code和desc,前端根据状态码显示不同的标签颜色,后端根据code做流转判断,代码可读性会好很多。

3.4 接口设计与前端界面联调

前后端分离时,接口设计必须有统一格式。我用的统一返回体是{code: 200, message: "success", data: {...}},所有接口都返回这个结构,前端封装一个request方法统一处理code,这样能省掉大量重复的错误处理。

下面是我当时整理的接口清单:

接口路径请求方式说明
/api/user/loginPOST登录,返回用户信息和角色
/api/order/submitPOST学生提交报修单
/api/order/listGET分页查询报修单,按角色过滤
/api/order/auditPOST管理员审核通过或驳回
/api/order/assignPOST维修工接单
/api/order/finishPOST维修工填写完工结果
/api/order/confirmPOST学生确认验收
/api/statistics/summaryGET首页统计卡片数据

前端我用Vue 2 + ElementUI,学生端、维修工端、管理员端三套页面放在同一个工程里,通过登录后返回的role动态渲染菜单。界面实现上有一个小经验:状态标签的颜色一定要区分明显,待审核用灰色、维修中用蓝色、已完成用绿色、已驳回用红色,演示时视觉效果会好很多,论文截图也会更清楚。

联调阶段最推荐先用Apifox或Postman把每个接口测一遍,确认返回JSON符合前端需求,再去接前端页面。这个顺序能砍掉至少一半的联调Bug,因为大部分前后端冲突本质上是接口约定不清晰。

4. 调试部署实践与常见问题排查

4.1 application.yml配置,别在这里翻车

整个项目跑不起来,十有八九是配置文件有问题。我用的核心配置如下:

server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/apartment_repair?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 servlet: multipart: max-file-size: 10MB mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

有几个细节经常让人排查很久。第一,MySQL 8.0必须指定serverTimezone=Asia/Shanghai,不指定会报时区错误;第二,字符编码用utf8,否则页面上中文会乱码;第三,mybatis-plus的log-impl建议只在开发环境打开,生产环境关掉,因为会打印大量SQL日志,影响接口性能。

如果需要在不同环境切换配置,建议拆成application-dev.yml和application-prod.yml,启动时用--spring.profiles.active=dev指定。这一步对后面部署服务器特别有用,代码不用改任何数据库连接,只需要在外部配置里覆盖即可。

4.2 从IDEA到服务器:打包部署完整流程

本地调试通过后,打包部署是很多人容易卡住的环节。我用Maven打成jar包,命令很简单:

mvn clean package -DskipTests

打包成功后会在target目录生成一个jar文件,运行命令:

java -jar target/apartment-repair-0.0.1.jar --spring.profiles.active=prod

如果服务器已经装了JDK和MySQL,这个jar包复制过去就能直接跑,不需要再装Tomcat,这就是Spring Boot内置Tomcat的好处。运行时端口冲突可以使用--server.port=8081覆盖默认端口,不需要改配置文件。

部署之后怎么确认成功?不要只看控制台出现“Started”就以为没问题,而是要实际访问登录接口或首页试试。最常见的部署问题有两个:一是MySQL只允许本地连接,服务器上要配置远程访问账号并开放3306端口;二是防火墙没开放8080端口,导致外网访问不了。这些都属于调试部署环境问题,建议在项目实施前先列一个环境清单,部署时一项项对照检查。

4.3 常见问题排查速查表

这段时间我整理了项目里最常踩的坑,做成了速查表,分享给大家:

问题现象可能原因解决方案
启动报数据库连接失败地址、账号密码错,或时区参数缺失检查url,增加serverTimezone
列表中文乱码数据库字符集不是utf8mb4建库时指定utf8mb4,连接串加characterEncoding=utf8
端口被占用上次启动进程没关闭查找占用进程并kill,或改端口
Maven依赖下载慢未配置镜像使用阿里云镜像
静态资源404拦截器放行路径漏了在拦截器配置中排除/static/**
接口返回403角色校验失败或Session丢失检查登录后Session写入,角色头是否传递
报修单重复接单没有条件更新状态使用update where status条件
Spring Boot版本太高导致报错3.x与2.x依赖差异降低到2.7.x,或调整jakarta依赖

这张表按照“现象、原因、解决”的格式整理,排错时先定位是环境问题、配置问题还是代码问题,不要一上来就复制整个错误日志去搜索,效率会高很多。实际项目里80%的问题都跑不出这张表。

5. 论文文档和交付资料整理的实用经验

5.1 万字论文怎么安排才不空洞

配套论文要达到1万字以上,但凑字数并不等于重复描述,而是要有合理的章节结构。我建议参考下面的用量安排:

  • 摘要:400字左右,写系统背景、技术栈、功能和测试结果。
  • 绪论:1200字左右,写目前高校报修管理的现状和痛点。
  • 需求分析:1500字左右,写用户角色、业务流程、功能需求。
  • 系统设计:2000字左右,写架构设计、功能模块划分和类图。
  • 数据库设计:2000字左右,写ER图、表结构、字段说明。
  • 系统实现:1500字左右,写关键功能实现,配合截图和关键代码。
  • 系统测试:1200字左右,写功能测试用例和测试结论。
  • 总结与展望:400字左右,写个人收获和可优化方向。

加起来刚好接近1万字,不会让人觉得空。写作顺序上我强烈建议先画用例图和ER图,再回头写需求分析和数据库设计,因为图在前面,文字只是对图的解释,效率会高很多。先写文字再画图,很容易出现图文对不上的情况。

最关键的一点是:论文里放的代码和截图必须是自己项目里真实运行的,不要从网上随手找。答辩老师如果问到一个细节,你连项目里有没有这个类都说不清楚,就很容易穿帮。真实运行过的项目,代码位置和界面长什么样都在脑子里,怎么问都不怕。

5.2 系统界面截图怎么拍才能加分

题目里那句“系统界面在最后面”,通常指的是论文最后附带系统界面截图。我整理截图时发现,不是截得越多越好,而是要有逻辑顺序。我的做法是:先截登录页,表示登录验证;然后以学生身份提交一条报修单,截列表页和详情页;再切到维修工身份,截待接单列表和接单操作;再到管理员身份,截审核页面和统计页面;最后截已完成状态和评价页面。这样正好复现一条完整业务流,答辩时照着截图讲就能讲清楚。

截图也有一些小技巧:浏览器窗口调整成固定宽度,不要出现无关书签和工具栏;数据用真实感的内容,比如“3栋502房间 空调故障”,不要写“测试1”“aaa”这种明显没打磨的内容;每张图配一句图注,比如“图4-3 维修工接单页面”,不要只贴图不解释。这些小细节会让论文专业度提升一个档次。

5.3 交付清单:源码、数据库、部署文档缺一不可

这类项目常见的交付物包含源码、数据库脚本、调试部署环境和论文文档。我建议把交付目录整理成这样:

apartment-repair/ ├── backend/ # Spring Boot 源码工程 ├── database/ │ └── init.sql # 数据库建库脚本和初始化数据 ├── docs/ │ ├── 论文文档.docx │ └── 系统使用说明.docx ├── deployment/ │ └── README.md # 环境要求、部署步骤、注意事项 └── screenshots/ # 系统界面截图

deployment/README.md里至少要写清楚JDK版本、MySQL版本、Maven版本、需要修改的配置项,以及如何导入数据库和启动项目。很多人拿到源码跑不起来,往往就是因为部署文档只写了两句“导入项目,运行”,结果连数据库账号都没说明。真正负责的做法是把自己从空环境跑通的全过程写下来,按照文档能一步步复现才算合格。

数据库脚本方面,建议包含建库语句、建表语句和初始化测试数据。初始化数据可以多放几条不同状态的报修单和几个不同角色的账号,方便演示。批量造报修单数据时,可以把create_time分散到不同月份,这样统计页面的图表会更好看,论文测试章节也有素材可用。

最后分享一个我自己的习惯:项目文档不要等到写论文的时候再补,开发过程中每完成一个功能点,随手截一张图,记录关键接口和配置变化。到最后整理交付资料时,你会感谢当时的自己。完整源码、数据库脚本和调试部署环境这些内容,理解并跑通一遍,比单纯把文件拿到手有价值得多。

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

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

立即咨询