
毕设拿这个项目练手SpringBootVue公寓报修管理系统源码、SQL脚本、接口文档齐全Java Web方向直接照着学就行。这篇文章我就以这套项目为主线把前后端分离开发里最关键的几个环节拆开讲清楚——从数据库设计、接口规范到联调部署全是实际操作时能直接用上的东西也顺便帮大家理一理毕设答辩时最容易被追问的那些点。1. 项目整体设计与技术选型分析1.1 为什么是SpringBootVue这个组合公寓报修管理系统这类业务系统放到Java Web毕设里几乎是标准命题。它的业务边界清晰角色分明状态流转完整数据模型也不复杂非常适合用前后端分离架构来演示。SpringBoot负责后端接口Vue负责前端页面两者通过JSON交互这种模式也正是目前企业内部项目的主流形态。选SpringBoot而不是传统的SSM核心原因是开发效率。SSM时代要写大量的XML配置光Spring、SpringMVC、MyBatis三者整合的配置就能让新手折腾好几天。SpringBoot把自动配置做到位一个spring-boot-starter-web依赖就把Web环境搭好了。这一点在毕设时间紧张的情况下尤其重要配置越少留给业务逻辑的时间越多。Vue这边选Vue 2还是Vue 3主要看学校要求和你自己的熟悉程度。这套项目用的是Vue 2 Element UI对毕设来说完全够用。Element UI的表格、表单、弹窗、分页组件都是现成的报修单列表、提交表单、审核弹窗这些页面在组件库里都有对应模板开发效率和颜值都有保障。如果你已经熟悉Vue 3换成Vue 3 Element Plus也完全可以接口部分不用动只调前端组件适配就行。1.2 公寓报修系统的核心业务链路拆解在动笔写代码之前先把业务链条理清楚。公寓报修做的事情本质上就是两条线学生报修人提交报修单 → 查看受理进度 → 确认完成 → 评价管理员维修调度查看新报修单 → 分配维修工 → 监督完成情况 → 数据统计这里面还有一个隐含角色——维修工。很多毕设会把维修工合并到管理员里但更完整的方案是单独建一张表和一个角色。这样整个系统的权限模型就是学生、维修工、管理员三类角色接口权限通过Spring Security或拦截器来控制答辩时也能多讲一个设计亮点。报修单的状态流转是这个系统的灵魂。我的建议是状态机设计成五个状态待受理、已接单、维修中、已完成、已取消。学生提交后是待受理维修工接单后变已接单开始维修后变维修中完工后变已完成学生在待受理阶段可以取消。每个状态的变更都记录操作人和时间这个设计在多张表之间配合时会非常清晰。2. 数据库设计与SQL脚本深度拆解2.1 核心数据表结构设计与字段规划这套项目的数据库设计是典型的三层结构用户体系、业务单据、日志与统计。我按实际落地时的顺序来讲建表顺序和表之间关联都直接影响SQL脚本能否一次跑通。第一层是用户相关表。tb_user是用户主表主要字段要覆盖id主键自增username登录名唯一索引password密码存BCrypt加密后的密文real_name真实姓名role角色建议用int存储1学生、2维修工、3管理员phone手机号avatar头像地址dormitory_id宿舍ID关联宿舍表status状态1正常、0禁用这里有个细节宿舍要不要单独建表我的建议是建。因为报修单需要记录报修位置如果用户表里直接存一个宿舍名字符串后期做按区域统计维修量时会很痛苦。单独建tb_dormitory表存楼栋号、房间号、区域信息报修单关联宿舍ID统计数据时用JOIN就能很方便地按楼栋聚合。第二层是报修业务表。tb_repair报修单主表是中轴字段包括id报修单IDorder_no报修单号业务编号user_id报修人ID外键关联用户表dormitory_id宿舍IDcategory_id报修分类IDtitle报修标题description详细描述images图片地址多个用逗号分隔status状态0待受理、1已接单、2维修中、3已完成、4已取消assignee_id维修工IDassign_time派单时间finish_time完成时间rating评分1-5evaluation评价内容create_time创建时间update_time更新时间报修分类tb_category单独一张表存报修类型名称比如水龙头漏水、电路故障、门窗损坏、空调不制热等。这样设计的好处是分类是一个可控集合前端可以用下拉框展示后端可以按分类做统计比用户手填一个字符串规范得多。第三层是操作日志和公告表。tb_repair_log记录每次状态变更的痕迹包括报修单ID、操作人、操作内容、操作时间。这个表在答辩时非常加分因为有状态机就一定要有操作记录否则无法追溯问题。tb_notice公告表用来发通知比如停水停电提醒。2.2 SQL脚本的执行要点与避坑指南这套项目里的init.sql或schema.sql脚本我建议在MySQL 5.7或8.0环境下执行数据库编码必须选utf8mb4。用Navicat或命令行执行时要注意两点一是先创建数据库再选择数据库二是建表语句如果包含外键约束必须严格按照从父表到子表的顺序执行。这里给大家一套稳妥的执行路径mysql -u root -p CREATE DATABASE IF NOT EXISTS repair_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE repair_system; SOURCE D:/path/to/init.sql;如果你用的是MySQL 8.0SOURCE命令依然可用。很多同学在Windows环境执行SQL脚本时报错八成是文件路径里带了中文或者反斜杠没转义建议路径统一用正斜杠。另外提醒一个SQL脚本里的顺序坑。如果脚本里既有建表语句又有插入语句插入的演示用户数据里密码字段一定要是BCrypt加密后的密文。直接用明文会导致启动后登录接口校验失败。项目里预置的三类账号学生、维修工、管理员初始密码建议统一为123456方便演示也方便答辩。3. 后端接口设计与接口文档的落地3.1 RESTful接口规范与统一响应体设计后端接口设计质量直接决定前端对接时的心情。这套项目的接口遵循RESTful风格资源用名词复数操作用HTTP动词区分。比如POST /api/repairs提交报修单GET /api/repairs/my当前用户报修列表GET /api/repairs/{id}报修详情PUT /api/repairs/{id}/assign管理员派单PUT /api/repairs/{id}/status状态变更POST /api/auth/login登录所有接口的返回结构统一为ResultT对象这是前后端分离项目的基本功。我建议的返回结构是{ code: 200, message: 成功, data: { } }后端用泛型封装Controller里只写业务逻辑返回值统一用Result.success(data)或Result.error(msg)。这个习惯从一开始就要养成不要每个接口返回不同结构否则前端axios拦截器没法统一处理。这里附上我常用的响应码约定code含义说明200成功请求正常处理400参数错误必填参数缺失或格式错误401未认证Token缺失或过期403无权限Token有效但角色不匹配404资源不存在查无记录500服务端异常程序运行时错误3.2 核心接口的业务逻辑拆解登录接口是第一个要写的也是最容易被追问的。这套项目用JWT做无状态认证用户提交用户名和密码后后端校验通过就生成一个Token返回前端把Token存在localStorage里后续请求在请求头里带Authorization: Bearer xxx。后端拦截器或Spring Security过滤器统一校验Token从Token里解析出用户ID和角色存入ThreadLocal或请求上下文。这样后续的业务接口直接通过工具类就拿到当前登录用户不用每次都在参数里传用户ID既方便又安全。这里你如果用拦截器而非Spring Security需要自己处理Token解析、过期判断、角色权限匹配逻辑也不复杂十来行代码就能搞定。考虑到毕设时间线我更推荐直接上Spring Security JWT虽然学习曲线稍陡但答辩时能讲出安全框架的使用经验含金量高不少。报修单提交接口有几个关键校验逻辑描述内容不能为空、分类必须存在、宿舍信息必须完整。图片上传我建议走独立的POST /api/file/upload接口后端用本地存储或OSS返回图片URL前端把URL拼到报修单字段里。如果不想引入OSS本地存储就行但要设置一个静态资源映射路径让前端能通过URL访问到图片。派单接口是权限控制的典型场景只有管理员角色能调用后端要从Token中解析角色并做校验。派单时更新报修单的assignee_id和assign_time同时写入一条日志记录“管理员XXX将工单分配给维修工XXX”。这种关键操作的日志不能省后续如果要做审计追踪日志表就是唯一凭证。3.3 接口文档的编写思路与Swagger配置接口文档是这套项目的标配交付物也是答辩时老师会翻看的内容。建议直接用Swagger自动生成接口文档省去手写大量Markdown的时间。SpringBoot集成Swagger的套路很固定引入springfox-boot-starter依赖写一个配置类开启EnableSwagger2设置文档标题和扫描包路径。启动项目后访问http://localhost:8080/swagger-ui/index.html就能看到所有接口的在线文档支持直接调试比手写文档更适合现场演示。但Swagger自动生成的文档不会写业务说明所以我建议在每个接口的Controller方法上写清晰的ApiOperation注释描述接口用途、参数含义、典型返回示例。如果你需要额外的接口文档文件可在Swagger的基础上再用Apifox或Postman导出API文档。实际开发中很多团队直接用Apifox在线文档接口它生成的手册页面在答辩演示时比Swagger更清晰字段含义和响应示例一目了然。记得在文档首页写清楚项目启动方式、默认账号、测试数据方便评审老师快速上手项目。4. 前端Vue项目落地与前后端联调4.1 Vue项目结构设计与页面规划Vue前端项目用Vue CLI或Vite创建都可以建议项目结构按照功能模块划分api目录放axios请求封装router目录放路由配置store目录放Vuex或Pinia状态管理views目录放页面组件components目录放公共组件。页面规划跟着角色走这是最清晰的思路登录页所有角色的入口学生端我要报修表单页、我的报修单列表详情、评价页维修工端待接单列表、我的维修任务、状态更新操作管理员端全部报修单管理、派单弹窗、用户管理、公告管理、数据统计路由守卫是必须做的不然任何人不登录都能访问页面。Vue Router的beforeEach钩子里检查本地Token没有Token一律跳到登录页。如果有Token再根据角色字段校验目标路由的权限管理员路由学生账号访问要拦截。这个逻辑写清楚答辩时能展示你对前端权限控制的理解。4.2 Axios封装与跨域问题处理前端与后端联调时最大的坑就是跨域。Vue dev server跑在9528端口后端跑在8080端口浏览器会拦截跨域请求。解决办法有两种我建议两个都做后端开启CORS配置前端配置开发代理。后端CORS配置很简单加一个配置类Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }前端代理在vue.config.js里配module.exports { devServer: { port: 9528, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }这样前端请求/api/repairs时dev server会转发到localhost:8080/api/repairs浏览器看到的是同源请求不会触发跨域拦截。注意changeOrigin必须设为true否则后端收到的请求头Host还是前端域名某些情况下会导致Session和Token解析问题。axios请求封装时核心点在拦截器里。请求拦截器从localStorage取Token并塞进请求头响应拦截器里对code ! 200的统一弹提示对401的统一跳回登录页。这套逻辑是所有前后端分离项目的通用模式写一次后面所有接口都受益。4.3 前端表达Vue文件上传与图片回显细节报修提交页里图片上传是必做功能Element UI的Upload组件可以方便地实现。在后端实现上传接口时要注意文件大小限制和类型校验防止上传超大文件拖垮服务器。建议限制5MB以内图片类型仅限jpg、png、gif。文件存储路径可以使用日期分目录例如/uploads/2025/07/避免单目录文件过多。前端上传成功后拿到图片URL要把URL拼到表单里。Web端回显注意URL必须是完整的访问路径如果后端存储路径是D:/upload/xxx.jpg前端不能直接访问需要后端配置静态资源映射把/upload/**映射到本机磁盘目录。这一步漏了图片会全部无法显示。这里补充一句Vue播放视频的m3u8流或类似多媒体场景在有直播或监控楼道的公寓项目里可能需求不少但报修系统基本不涉及大家在毕设需求分析阶段如果看到加直播巡更类的需求可视化监控可以考虑接入现成的HTML5播放器方案避免自己拉流处理特別复杂。5. 核心业务逻辑实现与关键代码解析5.1 报修单状态机与操作关联报修系统的复杂度和亮点集中在状态流转上。我建议把状态更新做成统一的一个接口通过传入目标状态来决定下一步操作而不是为每个状态写一个接口。这样既减少Controller层的代码冗余也方便权限校验。以维修工接单为例关键代码如下PutMapping(/{id}/status) public Result? updateStatus(PathVariable Long id, RequestParam Integer status) { Repair repair repairService.getById(id); if (repair null) { return Result.error(报修单不存在); } // 状态校验 if (repair.getStatus() 0 status 1) { // 待受理 - 已接单 repair.setAssigneeId(currentUserId()); repair.setAssignTime(new Date()); } else if (repair.getStatus() 1 status 2) { // 已接单 - 维修中 } else if (repair.getStatus() 2 status 3) { // 维修中 - 已完成 repair.setFinishTime(new Date()); } else { return Result.error(非法的状态变更); } repair.setStatus(status); repairService.updateById(repair); // 写入日志 repairLogService.record(id, 状态变更为 status); return Result.success(); }这套逻辑把状态机塞进一个方法里状态流转路径被硬编码非法跳转直接拒绝。代码虽然简单但状态机的思想是表达清楚了的。如果想让代码更规范可以定义枚举类RepairStatusEnum把状态值和描述放在一起前端通过接口读取枚举列表来展示状态标签。5.2 权限控制的两种实现路径对比权限控制这块我见很多毕设直接用拦截器判断角色字符串也有用Spring Security的。两种方案各有适用场景我给一个对比供参考方案实现复杂度安全性答辩亮点推荐度HandlerInterceptor 自定义注解低中能讲清原理时间紧时推荐Spring Security JWT高高能讲框架集成有余力时推荐如果你选拦截器方案核心思路是定义一个注解比如RequireRole(admin)标记在需要权限的Controller方法上拦截器里解析Token后比对角色。代码大概如下Component public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { if (!(handler instanceof HandlerMethod)) { return true; } HandlerMethod method (HandlerMethod) handler; RequireRole requireRole method.getMethodAnnotation(RequireRole.class); // 从Header解析Token String token request.getHeader(Authorization); Long userId JwtUtil.parseToken(token); // 判断角色 ... return true; } }两种方案都能实现目标但建议你在答辩材料里写明为什么选拦截器而不是直接用Spring Security。最高分回答不是“因为简单”而是“项目里涉及的接口数量有限用轻量级拦截器即可满足需求且方便定制化鉴权逻辑。”5.3 数据统计模块的SQL聚合写法公寓报修系统的管理端一定要有统计功能不然整个系统的数据闭环不够完整。统计模块最常见的就是按状态、按分类、按月统计报修数量。这里用一条SQL就能完成组合统计SELECT category_name AS name, COUNT(*) AS total, SUM(CASE WHEN status 3 THEN 1 ELSE 0 END) AS finished, SUM(CASE WHEN status 0 THEN 1 ELSE 0 END) AS pending FROM tb_repair r LEFT JOIN tb_category c ON r.category_id c.id GROUP BY r.category_id;这种按分类的状态分布统计前端用ECharts饼图展示效果很好。另一个重要的统计维度是维修工工作量排名GROUP BY assignee_id然后按完成数量排序前端可以用柱状图展示。ECharts的引入很简单npm安装后在组件内import * as echarts from echarts然后写对应的初始化代码即可。6. 常见问题排查与项目部署经验6.1 前后端联调中的典型异常与处理方案整个毕设周期里我遇到过的报错可以整理成一张排查表大家可以直接对照着找问题异常现象可能原因解决方案前端请求一直404SpringBoot上下文路径与代理路径不一致检查server.servlet.context-path和前端代理/api前缀是否匹配请求成功但数据为空后端返回的字段名是userName前端用的是username确认实体类字段与前端取值保持一致或用JsonProperty映射时间字段变成一串数字后端返回Date类型默认序列化为时间戳在application.yml里配置spring.jackson.date-format和time-zone登录后接口全部401Token过期时间设置太短JWT有效期建议设2小时答辩演示一般不会超过这个时长上传图片后访问不到静态资源映射未配置用WebMvcConfigurer添加addResourceHandlers映射到本地磁盘路径SQL脚本执行报错MySQL版本差异或编码问题8.0注意utf8mb4字符集老表结构改为ENGINEInnoDB DEFAULT CHARSETutf8mb4这里重点展开时间字段的问题。SpringBoot默认对java.util.Date的序列化结果是时间戳数字前端拿到的不是2025-07-15 14:30:00而是1752553800000在表格里显示一长串数字很难看。解决办法spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8但如果你用的是Java 8 的LocalDateTime上面的配置不生效需要额外引入jackson-datatype-jsr310依赖然后配置spring: jackson: serialization: write-dates-as-timestamps: false6.2 SpringBoot版本过高引发的依赖兼容问题很多同学习惯直接去Spring Initializr拉最新版SpringBoot但最新版经常会带来兼容性坑比如你遇到过的springboot版本太高相关搜索词就暴露了这个问题。SpringBoot 3.x要求JDK 17起步如果本机是JDK 8项目根本起不来。而且3.x里的javax.servlet包换成了jakarta.servlet老代码里的import javax.servlet.*全部要改。毕设项目如果没有特殊需求我建议直接用SpringBoot 2.7.x版本稳定且网上资料最多遇到问题随便搜都能找到解决方案。配合JDK 8和Maven全套环境十分钟就能搭好。等到工作后再去接触SpringBoot 3.x也不迟那是新项目的趋势但毕设稳字当头。6.3 Vue项目打包进SpringBoot的完整流程毕设交付时很多需求要求“一个jar包直接运行”这就需要把Vue项目打包后放进SpringBoot里。我第一次做这个操作时也踩过坑这里把完整流程分享出来。先在Vue项目根目录执行npm run build打包完成后生成dist目录里面有index.html、static或assets文件夹。此时有两种方式整合到SpringBoot。方式一直接把dist里的文件全部复制到SpringBoot的src/main/resources/static目录下重新打包SpringBoot后访问http://localhost:8080/就能看到前端页面。方式二用Maven插件在构建时自动集成在pom.xml里加plugin groupIdcom.github.eirslett/groupId artifactIdfrontend-maven-plugin/artifactId /plugin在Maven的package阶段自动执行npm install和npm run build把生成的前端文件复制进jar包。这种方式适合需要一键交付的场景评审老师拿到项目后一条java -jar命令就能跑起来。需要注意打包之后的前端请求路径会和dev环境不同。开发时前端代理指向localhost:8080打包后同源部署就不需要代理了。如果你在后端设置了server.servlet.context-path/repair那前端请求的baseURL也要改成/repair同时前端路由的base属性也要对应调整否则页面刷新会404。7. 实战中的体会与一些建议折腾完这套公寓报修管理系统我最想跟大家说的是答辩时项目能跑通只是基础更重要的是你能讲清楚设计逻辑。建议提前准备好这几个问题的回答报修单状态为什么用int不用字符串Token过期后前端如何处理数据库为什么把分类单独建表这些能答得有条理比项目多一个功能更能体现你的工程能力。最后再分享一个小技巧。毕设里如果时间来不及可以把用户管理的增删改查用代码生成器批量生成比如MyBatis-Plus的代码生成器一张表的Controller、Service、Mapper全套代码自动生成把省下来的时间留给报修单状态机和数据统计这两个核心模块打磨。它们才是公寓报修系统里真正有区分度的地方。