
学生公寓报修平台听起来像是一个常见的课程设计题目但真正动手做一遍以后会发现里面涉及Spring Boot框架、源码工程、数据库设计、调试部署和开发环境搭建整整一条链路。我最近完整做了一个这样的项目配套的源码、数据库脚本、调试部署环境和万字论文文档都整理好了今天就把从需求拆解到最终交付的整个过程重新讲一遍。这篇文章适合正在做毕业设计或课程设计的同学也适合想用Spring Boot快速搭建管理系统的开发者。我会从业务拆分、技术选型、表结构设计、功能实现、部署排查到论文写作把每个环节里最容易被忽略的细节都摊开来说尽量做到拿过去就能参考。1. 学生公寓报修平台的业务梳理与功能拆分1.1 报修不是“填个表”而是完整的状态流转先讲一个我做完这个项目后最深的体会这类系统的核心不在增删改查而在报修单的“状态流转”。学生提交一个报修单它不会瞬间变成已完成中间至少要经过审核、接单、维修、验收这几个环节。如果上来就建表写接口很容易写到一半发现维修工看不到待接单列表或者学生没法确认完成原因就是业务流没有提前梳理清楚。我在开发前的实际做法是把完整流程列成一条条动作学生登录后填写报修单填写楼栋、房间号、故障类别、详细描述可选上传图片保存后状态为“待审核”。宿管或平台管理员查看新报修单审核通过后状态变为“待接单”审核不通过则退回给学生并填写原因。维修工在“待接单”列表里看到单子选择接单状态变为“维修中”同时记录接单人和接单时间。维修完成后维修工填写维修结果状态变为“待验收”。学生看到结果后可以确认完成也可以申请返工确认完成后状态变为“已完成”最后还可以给本次维修评分。这套流程的价值在于每个状态都有明确负责人和时间点出了问题随时可追溯。哪怕是一个课设级别的管理系统我也不建议省掉审核或验收环节否则报修就变成了一锤子买卖学生体验和后期的数据统计都会很难受。实际操作时我建议把状态定义成常量或枚举比如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 idaliyunmaven/id mirrorOfcentral/mirrorOf nameAliyun Public Repository/name urlhttps://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 groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/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负责接收请求和返回JSONservice写业务逻辑尤其是状态流转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) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 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) { UpdateWrapperRepairOrder 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?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/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必须指定serverTimezoneAsia/Shanghai不指定会报时区错误第二字符编码用utf8否则页面上中文会乱码第三mybatis-plus的log-impl建议只在开发环境打开生产环境关掉因为会打印大量SQL日志影响接口性能。如果需要在不同环境切换配置建议拆成application-dev.yml和application-prod.yml启动时用--spring.profiles.activedev指定。这一步对后面部署服务器特别有用代码不用改任何数据库连接只需要在外部配置里覆盖即可。4.2 从IDEA到服务器打包部署完整流程本地调试通过后打包部署是很多人容易卡住的环节。我用Maven打成jar包命令很简单mvn clean package -DskipTests打包成功后会在target目录生成一个jar文件运行命令java -jar target/apartment-repair-0.0.1.jar --spring.profiles.activeprod如果服务器已经装了JDK和MySQL这个jar包复制过去就能直接跑不需要再装Tomcat这就是Spring Boot内置Tomcat的好处。运行时端口冲突可以使用--server.port8081覆盖默认端口不需要改配置文件。部署之后怎么确认成功不要只看控制台出现“Started”就以为没问题而是要实际访问登录接口或首页试试。最常见的部署问题有两个一是MySQL只允许本地连接服务器上要配置远程访问账号并开放3306端口二是防火墙没开放8080端口导致外网访问不了。这些都属于调试部署环境问题建议在项目实施前先列一个环境清单部署时一项项对照检查。4.3 常见问题排查速查表这段时间我整理了项目里最常踩的坑做成了速查表分享给大家问题现象可能原因解决方案启动报数据库连接失败地址、账号密码错或时区参数缺失检查url增加serverTimezone列表中文乱码数据库字符集不是utf8mb4建库时指定utf8mb4连接串加characterEncodingutf8端口被占用上次启动进程没关闭查找占用进程并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分散到不同月份这样统计页面的图表会更好看论文测试章节也有素材可用。最后分享一个我自己的习惯项目文档不要等到写论文的时候再补开发过程中每完成一个功能点随手截一张图记录关键接口和配置变化。到最后整理交付资料时你会感谢当时的自己。完整源码、数据库脚本和调试部署环境这些内容理解并跑通一遍比单纯把文件拿到手有价值得多。