资讯动态

SpringBoot+Vue+MyBatis+MySQL宿舍维修管理系统前后端分离实战

发布时间:2026/10/9 8:25:33 来源:尧图企业网站定制
搞宿舍维修管理系统这个项目说实话是我这几年带着学员做过最多的一类练手项目。因为它足够典型有明确的新增、查询、修改、删除流程有用户和员工两个角色有图片上传、状态流转、数据统计这些至少中小型项目里跑不掉的环节拿来跑一遍前后端分离的完整链路比单纯刷一百道CRUD题有用得多。这篇文章就把这套系统的完整写法和部署过程摊开讲从项目拆解、技术栈选型、数据库表设计到后端接口怎么写、前端页面怎么对接、上线部署踩了哪些坑全部整理一遍。标题定的是 SpringBoot Vue MyBatis MySQL 这套组合但我更想强调的是前后端分离的思维方式——它决定了你每个接口怎么设计、每个页面怎么组织、每个异常怎么处理。让你跑通的不只是源码而是真的能独立从零搭建一套可用的管理系统。1. 项目定位与核心需求拆解1.1 宿舍维修管理系统的痛点在哪很多学校、企业园区、长租公寓的宿舍报修流程现实中往往是靠微信群接龙或者一纸纸质表格完成的。学生报修了没有回执、维修师傅不知道任务量、宿管没法统计哪些问题反复出现——整个闭环是断裂的。宿舍维修管理系统要解决的核心问题就是把“学生报修—宿管派单—师傅维修—结果确认—数据统计”这五步串成一条线上链路。从开发视角看它的需求其实非常清晰。学生端能做的是提交维修单、填写报修位置和描述、上传照片、查看自己的报修进度管理端则是查看所有工单、分配维修师傅、更新维修状态、完单后回填维修结果。如果再往外扩展还可以加维修评价、催单提醒、超时预警、维修费用统计这些功能。但我建议第一版不要把范围铺太开优先把报修主流程做扎实再做统计报表和用户管理这样项目节奏可控出错也容易定位。1.2 为什么要选前后端分离架构前后端分离说白了就是后端只提供接口不关心页面上按钮怎么摆前端只负责渲染和交互不直接操作数据库。中间通过 JSON 格式的 HTTP 接口通信。这样带来的直接好处是后端和前端可以并行开发两个人做一个月就能上线页面改动不需要重新部署 Java 工程只替换前端静态资源就行以后要出小程序端、移动端后端接口稍作适配就能复用不用重写业务逻辑。我见过很多同学的项目是后端写 Thymeleaf 模板直接渲染页面这种做法在小项目里确实快但代码耦合度很高一个页面要改布局服务端模板、路由、控制器都得动。前后端分离之后后端代码专注于业务和数据处理前端代码专注于用户体验职责边界非常清楚。对于宿舍维修管理系统这种中型业务场景分离架构是性价比最高的选择维护成本远低于单体模板方案。技术栈上后端选了 SpringBoot 2.7 MyBatis MySQL前端选了 Vue 2 Element UI Axios。这套组合在校园项目和中小型公司里出现频率极高网上资料多、现成组件丰富、遇到问题的排查路径基本都有前人踩过特别适合拿来做实战训练。2. 技术栈选型解析为什么是这四件套2.1 SpringBoot快速搭建后端服务的利器SpringBoot 的核心价值在于“自动配置”。它把 Spring 框架里大量的 XML 配置收敛成了默认约定你只需要在 pom.xml 里引入对应依赖再在 application.yml 里写上数据库连接、端口、上传大小限制这些必要项项目就能跑起来。宿舍维修系统项目里SpringBoot 主要负责三件事处理前端发来的 HTTP 请求、调用 MyBatis 操作数据库、返回统一的 JSON 数据格式。我建议在源码中引入 spring-boot-starter-web、spring-boot-starter-validation、mybatis-spring-boot-starter、mysql-connector-java 这几个依赖。HTTP 请求处理和参数校验靠前两个数据库访问靠后两个。有同学问过 SpringBoot 版本怎么选我在这里多说一句。后端这块我选 2.7.x 而不是 3.x。原因很简单SpringBoot 3 基于 JDK 17要求 javax 改成 jakarta很多老教程和开源组件还没完全跟上新手照着资料写代码容易因为包路径不同报错。用 2.7.18 搭配 JDK 8稳定性极高跑这套系统完全够用。2.2 Vue Element UI前端页面与交互实现Vue 这个框架的核心特点是数据驱动视图。页面上的列表、表单、状态标签都和数据绑定在一起数据变了页面自动刷新你不用手动去操作 DOM。Element UI 是 Vue 2 生态里最经典的组件库表格、弹窗、日期选择器、分页组件全部现成省去了大量写样式和交互逻辑的时间。前端部分我按组件化思路拆分。路由页面有登录、报修单列表、提交报修、工单管理、用户管理、统计看板公共组件有顶部导航、侧边菜单、图片上传弹窗。每一个列表中行的操作按钮删除、确认派单、完成维修都有对应的处理函数通过 Axios 调用后端接口拿到结果后再刷新本地的数据源。关于 Vue 版本我强烈建议新手第一版别上 Vue 3 TypeScript Vite 的激进组合。不是说它不好而是 Vue 2 Element UI Vue CLI 的生态非常成熟任何报错你都能搜到现成的解法。先跑通这套再往 Vue 3 迁移思路会清晰很多。等到你把这种经典组合吃透了再去折腾组合式 API 和 Vite 也不迟。2.3 MyBatis 与 MySQL数据访问与持久化数据库选 MySQL是因为它是目前使用最广的开源关系型数据库安装部署简单性能可靠网上教程多到不能再多。系统里涉及的表不超过十张MySQL 5.7 或 8.0 都能轻松胜任。MyBatis 的工作方式和 Hibernate、Spring Data JPA 不同它不会自动帮你生成 SQL而是让你自己写 SQL 或利用 XML 映射文件定义 SQL。看着像是“倒退”但对于要控制 SQL 执行效率的项目来说是优势。比如宿舍维修系统里最常见的查询——按状态筛选工单、按日期范围统计维修完成率、多表联查用户和维修记录自己写 SQL 能精确控制关联条件、索引使用和返回字段比框架自动生成的语句更可控。还有一个点是 MyBatis 的驼峰映射。Java 里的属性名通常是 camelCase 风格例如 userName、createTime而数据库字段一般是下划线风格 user_name、create_time。application.yml 里配置下 mybatis.configuration.map-underscore-to-camel-case: true查询结果就能自动映射到实体少写很多 ResultMap。3. 系统功能模块与数据库设计3.1 功能模块划分与角色权限宿舍维修系统的用户可以分为三类学生、维修师傅、管理员宿管。不同角色看到的菜单和数据范围不一样这套系统的功能模块围绕这三个角色展开。学生角色的功能包含登录注册、我的报修单、提交新报修。提交时填写宿舍号、联系方式、故障描述支持上传故障照片。这个页面要注意表单校验宿舍号和电话格式都可以做到必填校验减少后端处理垃圾数据的压力。管理员功能模块包含报修单管理、用户管理、维修师傅管理、数据统计。报修单管理是核心列表默认展示全部工单支持按状态筛选——待处理、维修中、已完成管理员可以把工单派给指定师傅并记录派单时间。统计页可以从 SQL 里聚合出每周报修数量、各类故障占比、平均维修时长用简单的柱状图展示即可。维修师傅功能相对轻量查看分配给自己的工单修改维修状态填写维修反馈内容和实际花费时长。这三个角色对应三张菜单权限表前端根据登录时返回的角色字段渲染不同的菜单后端接口也要做对应的权限拦截至少保证学生不能通过手动请求调用管理员的接口。3.2 数据库表结构怎么设计数据库表设计是整个系统的地基我建议用脚本建表不要用图形化工具点来点去。核心表规划如下用户表sys_user存的是所有人的账号和角色信息。字段包括 id、username、password、real_name、role、phone、dormitory_no、create_time。password 一定要存 BCrypt 加密后的值千万不能明文。角色字段用字符串STUDENT、WORKER、ADMIN区分即可比单独建角色表简单得多适合这种规模的系统。报修表repair_order是业务主表。字段设计上要有 order_no、user_id、dormitory_no、contact_phone、fault_type、description、photo_url、status、assignee_id、assign_time、complete_time、feedback、create_time。order_no 可以用时间戳加随机数生成展示给用户方便查询status 用数字表示0待处理、1维修中、2已完成前后端约定好就行。再配上系统日志表sys_log来记录接口调用或关键操作方便排查问题。一张日志表不复杂主键自增存操作人、操作类型、操作时间、请求参数即可。这张表在开发调试阶段特别有用线上排查用户反馈的“我的操作没生效”问题看日志比猜代码快得多。表之间的外键关系不需要强行约束在数据库里程序里通过逻辑字段关联即可。比如 repair_order.user_id 指向 sys_user.id查询用户信息时多表联查MyBatis 写在 XML 里很直观。4. 完整部署实操过程4.1 基础环境准备与版本搭配先说环境的版本搭配这个坑很多新手会踩。我这套源码的推荐搭配是JDK 8、MySQL 5.7 或 8.0、Node.js 14 到 16、Maven 3.6 以上。JDK 版本高的话要看后端代码里有没有用到 javax 包SpringBoot 2.7 用 JDK 11 也能跑但 JDK 8 是最稳的。Node 版本如果太高比如 18 或 20vue-cli 5 可以支持但 node-sass 这类旧依赖会编译报错这个后面常见问题里会说。安装 MySQL 时要注意如果之前装过旧版本残留初始化时根目录和 service 名称可能冲突。建议彻底卸载干净再按默认配置装 8.0设置 root 密码时统一记好后面配置数据源要用的。前端环境安装主要就是安装 Node 和 npm再全局装一个 cnpm 镜像加速依赖下载。Vue CLI 脚手架工具通过 npm install -g vue/cli 安装版本用 4.x 或 5.x 均可。安装完成后可以用 vue --version 验证。4.2 后端项目结构说明与启动步骤拿到源码后先看整体目录。后端项目是一个标准的 Maven 工程目录结构包含 src/main/java 下的 controller、service、mapper、entity 包以及 src/main/resources 下的 mapper 目录、application.yml。启动步骤我在 README 里写得很明确第一步用 IDEA 打开后端根目录等待 Maven 把依赖下载完成。如果 IDEA 提示没有配置 Maven注意 Settings 里指定本地 Maven 仓库路径。第二步在 MySQL 中新建数据库名字随意比如 repair_db然后执行项目里 database 目录下的 init.sql 脚本。脚本里包含了建库、建表和初始数据管理员账号默认 admin / admin123学生示例账户 student / 123456师傅示例账户 worker / 123456。第三步修改 application.yml 里的数据源配置。将 spring.datasource.url 改成你自己数据库地址username 和 password 改成你的 MySQL 登录账号。这里提醒一下时区和编码参数建议加上否则连数据库会报时区错误spring: datasource: url: jdbc:mysql://localhost:3306/repair_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 你的密码第四步配置端口和应用上下文路径。默认端口是 8080路径留空即可。最后找到 Application 启动类点击运行。启动成功后控制台会出现 Spring Boot 的启动日志和端口号再用浏览器访问 http://localhost:8080/doc.html 如果已经集成接口文档插件就能看到所有接口列表了。4.3 前端项目运行与代理配置前端项目目录是一个标准的 Vue CLI 工程。用 IDEA 或 VS Code 打开后在终端里先执行 npm install 安装依赖等 node_modules 生成后再执行 npm run serve 启动开发服务器。这里有个关键配置前端开发服务器的默认端口是 8080后端的接口也是 8080两个会冲突而且浏览器跨域策略默认不允许脚本直接访问不同端口的接口。解决办法是在前端项目的 vue.config.js 里配置 devServer.proxy把前端的请求转发到后端地址module.exports { devServer: { port: 3000, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } };这样一来前端页面发请求时都写 /api/login本地开发时 Node 服务器会把请求转发给后端的 8080 端口浏览器看到的是同一个来源就不会报跨域错误后端接口代码也不用额外处理 CORS。前端启动成功后浏览器访问 http://localhost:3000能看到登录页。默认账号直接用管理员 admin 登录进去后应能看到侧边菜单和统计面板如果数据能正常展示说明前后端联调已经打通。4.4 前后端接口联调与数据交互前后端联调是这个项目比较关键的环节。我建议先把后端接口用 Postman 或者接口文档插件全部验证一遍确认每个接口都能正常返回数据再去调前端页面。前端页面与后端数据交互的标准流程是在 Axios 封装文件里定义 baseURL 和拦截器登录时向后端发送账号密码后端校验通过后返回一个 Token 字符串。前端拿到 Token 后存到 localStorage并在后续每次请求的请求头里带上 Authorization 字段。后端用一个拦截器对所有非登录接口做 Token 校验这样能保证没有权限的人拿不到数据。Token 的生成我这里用了 JWT 工具类。集成起来不难引入 jjwt 依赖写一个 JwtUtil 类包含生成 Token 和解析 Token 的方法。Token 里放用户 id 和角色字段后端拦截器里每次请求都解析一次再通过 ThreadLocal 把用户信息传给控制器。这套逻辑麻雀虽小五脏俱全能帮你以后迁移到拦截器、权限框架理解底层原理。5. 常见问题与排查技巧实录5.1 SpringBoot 版本过高引发的依赖问题很多同学从网上下载的源码可能是 SpringBoot 2.3 时代的写法但自己新建项目时用了 SpringBoot 3.2 甚至更高结果一启动就报错。最常见的是 javax.servlet 包找不到了。SpringBoot 3 里 javax 被换成了 jakarta以前的 import javax.servlet.http.HttpServletRequest 全部编译失败而且项目中引入的很多老版本第三方库也不兼容。遇到这类问题最快的解决办法是看后端 pom.xml 里 spring-boot-starter-parent 的版本号统一改成和源码一致的版本例如 2.7.18。IDEA 修改后点击 Maven 面板的刷新按钮等依赖重新解析完再启动。如果项目里引入了 pagehelper 分页插件、druid 连接池也要注意它们的版本和 SpringBoot 版本要匹配pagehelper 就用 1.4.xdruid 用 1.2.x 即可。5.2 MySQL 连接失败的几种情况后端启动后提示 Cannot create PoolableConnectionFactory 或者 Access denied for user基本都是数据库连接配置的问题。不要急着去改代码按下面的顺序排查第一确认 MySQL 服务有没有启动。Windows 下看服务管理器里 MySQL 的状态Linux 下用 systemctl status mysql 来查。第二确认密码是否正确。初学者特别容易在 root 密码输入的时候多打了空格或者记错大小写。可以在命令行里用 mysql -u root -p 手动连一下确认。第三确认 URL 里的数据库名是否存在。如果 application.yml 里写的数据库名和实际建的不一致直接启动报错。这个错误信息很明确跟着日志找到 Unknown database 字样就知道是库名问题。第四确认时区配置。8.0 版本的 MySQL 如果 URL 里不写 serverTimezone会报 The server time zone value 的异常。加上 serverTimezoneAsia/Shanghai 就解决。5.3 前端页面白屏与跨域报错前端启动后页面白屏先在浏览器控制台看具体报错。如果是 Failed to load resource 且 URL 指向 /api 开头十有八九是代理配置没生效。重新检查 vue.config.js 文件是不是在项目根目录而配置文件里的端口和实际启动的端口是否一致改完配置文件要重启前端服务才生效。如果控制台报 401 或 403说明接口请求发到了后端但身份校验没过。这个情况先检查登录接口是否能正常返回 Token再看 Axios 请求拦截器里是否正确携带了 Authorization。我见过有人把字段名写成了 user-token和后端拦截器读取的 header 名对不上排查了好几个小时。这种问题直接用浏览器开发者工具的 Network 面板看请求头一眼就能看出来。如果控制台报跨域错误且你没有配置代理而是在后端加了 CrossOrigin 注解那要确认注解加在了正确的控制器类上同时注意它只对开发环境友好上线部署时还是要走 Nginx 反向代理或者后端统一配置跨域。依赖注解做跨域处理的时间久了容易被忽略。5.4 前后端数据格式不一致时间、空值处理这个项目里时间字段很多创建时间、派单时间、完成时间、回复时间前后端容易因为数据格式不一致出问题。后端 MyBatis 查出来的 java.util.Date 序列化成 JSON 时默认输出格式是 ISO 时间戳比如2025-03-16T21:08:30前端展示时直接 toString 会显示成一长串观感很差。我建议后端在实体类的日期字段上统一加 JsonFormat(pattern yyyy-MM-dd HH:mm:ss) 注解时间格式就固定了。前端表格里如果字段值为 null显示为空白单元格不够友好可以用模板片段处理一下——比如状态字段为 null 时显示未知照片字段为 null 时不渲染上传预览框。这些细节决定了项目交付给用户用的时候是不是好用代码写得好不好不只是功能通不通还有体验细节打磨得细不细。6. 系统扩展点与 MyBatis 进阶实践6.1 MyBatis 动态 SQL 与多条件查询宿舍维修列表页常见的需求是状态筛选加关键词搜索。用 MyBatis 写这种多条件查询动态 SQL 是必须掌握的技巧。核心标签就是 和 。举个例子查询报修单列表时根据前端传过来的 status、keyword、userId 参数动态拼接查询条件select idselectRepairOrderList resultTypecom.example.entity.RepairOrder SELECT * FROM repair_order where if teststatus ! null AND status #{status} /if if testkeyword ! null and keyword ! AND (dormitory_no LIKE CONCAT(%, #{keyword}, %) OR description LIKE CONCAT(%, #{keyword}, %)) /if if testuserId ! null AND user_id #{userId} /if /where ORDER BY create_time DESC /select使用 标签的好处是当所有条件都不传时它不会生成空的 WHERE 关键字语法不会报错。而且第一个条件前加的 AND 会被自动忽略不用自己费心处理前缀。传 null 的参数在 判断里会走 false 分支条件就不会拼接。这一点在生产环境里很重要因为前端列表页用户可能不填筛选条件直接点查询SQL 必须能正确处理。6.2 MyBatis 的一级缓存与二级缓存MyBatis 的缓存机制是面试常客做项目时也要心里有数。一级缓存是 SqlSession 级别的默认开启。同一个 SqlSession 内同样的 SQL 和参数查询第二次会直接用缓存结果不再查询数据库。但 SpringBoot 整合 MyBatis 后每次请求都会创建一个新的 SqlSession所以一级缓存的实际作用有限跨请求的内容靠它兜不住。二级缓存是 Mapper 级别的需要手动开启。在 mapper XML 文件里加 标签同一个 namespace 的查询结果会被缓存。但这里有一个大坑如果涉及修改操作增删改MyBatis 会清空该 namespace 下的缓存这个机制没问题可是如果两张表被不同 Mapper 操作并且有联查关系比如用户表和报修表就会产生缓存不一致的风险。宿舍维修系统的报修列表联查了用户姓名而用户信息更新走的又是另一个 Mapper开启二级缓存后可能出现修改了用户名称但列表还显示旧值的情况。所以我在这个项目里没有开启二级缓存借助 MySQL 自身的查询效率已经足够快省去缓存一致性维护心智负担。在高并发场景下建议引入 Redis 做业务缓存而不是依赖 MyBatis 的二级缓存。6.3 系统后续可扩展方向这套系统跑通之后可以做的扩展方向我个人觉得有四个都挺有实际意义。第一个是接入 Redis。把工单统计、用户 Token、高频查询列表放到缓存里降低数据库压力。这也是一条让项目简历亮眼的技术点。第二个是增加 Websocket 实时推送。当学生提交报修单后管理端页面实时弹出一条新工单提醒不需要用户手动刷新。这个体验升级很直观也适合讲解。第三个是增加文件上传模块的独立化。当前照片上传是单机的存到本地磁盘指定目录后续可迁移到云存储的 OSS 服务把上传功能拆成一个通用文件服务。第四个是数据统计可视化。目前统计只是简单柱状图可以加维修趋势折线图、不同故障类型饼图、每个师傅接单量排行配合 ECharts 能做出很漂亮的看板页面。我个人的体会是做这类管理系统最重要的不是懂某个框架的高深用法而是把一条业务链路完整打通。数据库怎么设计才能好扩展接口怎么定义才能让前端用得舒服权限控制怎么加才能不出安全漏洞这些能力比背框架 API 值钱得多。7. 部署上线经验与源码使用要点7.1 本地打包与线上部署流程开发环境跑通后上线部署又是一个分水岭。后端打 Jar 包时需要跳过测试在 IDEA 右侧 Maven 面板执行 package第一次打包等依赖下载会慢一些。打包完成后 target 目录下会生成 jar 文件用命令行 java -jar xxx.jar 启动即可。生产环境建议加 nohup 不让程序在退出终端时被杀掉nohup java -jar repair-server.jar console.log 21 前端打包用 npm run build生成 dist 静态目录。拿到 dist 目录后把它交给 Nginx 托管是最常见的方案。Nginx 配置文件里设置 root 指向 dist 目录然后配置一个反向代理把所有 /api 开头的请求转发到后端的 8080 端口这样线上环境也不会有跨域问题。我给出的最小 Nginx 配置片段供参考server { listen 80; server_name your-domain.com; root /home/www/repair/dist; index index.html; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location / { try_files $uri $uri/ /index.html; } }这个配置里最后一条 location / 的 try_files 是把路由请求交给前端 index.html 处理这样 Vue Router 的滚动路由刷新页面时不会出现 404。这一步非常关键不配的话很多人上线后发现刷新就白屏。7.2 安全处理与鉴权细节项目上线前有几处安全细节一定要处理。密码存储方面用户注册和内置账号在数据库中的密码一律使用 BCrypt 加密后的密文不要明文存储更不要用简单的 MD5这种哈希算法已经被证伪碰撞成本太低了。登录接口的参数校验要防 SQL 注入MyBatis 的 #{} 占位符本身就是预编译能有效防注入所以写 SQL 时养成用 #{} 不用 ${} 的习惯。另外接口层面不要把所有查询接口都暴露给所有角色。比如维修师傅登录后只能查看分配给自己的工单管理员才能查看所有工单。接口拦截器里加一层角色判断用更细粒度的权限控制来避免越权访问。最后是日志问题。上线环境不要把 SpringBoot 默认的日志直接丢弃到后台像上面例子中那样重定向到 console.log时间久了文件会很大。更规范的做法是通过 logback-spring.xml 配置按天滚动生成日志文件保留最近 30 天即可。日志里别打印密码、Token 等敏感字段挨个排查时看请求参数都要小心。7.3 这套源码适合什么人学习和使用这套系统适合的人群其实很广泛。对在校学生来说它是一个标准的课程设计和毕业设计选题技术栈主流、功能完整、演示效果好。对刚学完 SpringBoot 和 Vue 但没做过完整项目的开发者来说跟着源码把业务链路跑通能真正理解前后端分离的项目是怎么组织起来的。对需要内部管理工具的小型团队来说把代码里的宿舍名称换成部门名称把报修换成其他内部工单流程稍微改一下字段也能直接内网跑起来。如果你拿到源码第一件事是 CtrlC 提交作业那我建议你还是老老实实把数据库脚本执行一遍接口一个接口看过去前端路由跟着点一遍。源码的价值在于给你一套已经跑通的标准答案你要做的是理解它为什么这么设计然后把其中用到的技能变成自己的。至少把建表、接口代码、前端页面三个环节拆开重写一遍这个项目的训练效果才能真正到位。我在实际带项目的时候很多同学一开始都会遇到版本不匹配、依赖下载失败、控制台报红色异常就慌了。其实排查的思路无非就是先看是不是环境问题再看是不是配置问题最后才是代码问题。报错信息里往往已经把原因说得清清楚楚培养读报错信息的能力比你现在多背一百个 API 都重要。这套宿舍维修管理系统源码如果你能一头一尾完整搭起来独立把它部署到服务器上那你的工程化能力就已经超过很多只会敲增删改查的初级开发了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑