SpringBoot+Vue学生宿舍报修系统:毕业设计实战与前后端分离架构详解
30款热门AI模型一站整合DeepSeek/GLM/Claude 随心用限时 5 折。 点击领海量免费额度每到毕业季计算机专业的学生们最头疼的往往不是论文而是那个必须完成的“毕业设计”。选题太简单显得没技术含量选题太复杂又怕时间不够、代码跑不通。一个能兼顾技术栈学习、业务逻辑清晰、又能快速上手的项目就成了刚需。今天要讨论的“基于SpringBootVue的学生宿舍报修信息管理系统”就是一个非常典型的毕业设计选题。它看似简单一个“报修系统”而已但如果你只把它当作一个增删改查的练习那就错过了它真正的价值。这个项目的核心不在于实现一个功能而在于如何通过一个具体的业务场景串联起Java后端、Vue前端、数据库设计、权限控制、前后端分离架构等一系列企业级开发的核心技能点。很多同学在开发类似系统时容易陷入两个误区要么前端页面写得漂亮后端逻辑却一团糟接口设计混乱要么后端CRUD写得飞起前端却交互生硬用户体验极差。更常见的问题是代码虽然能跑但结构混乱毫无扩展性经不起任何追问。这篇文章我们就来彻底拆解这个项目不仅告诉你“怎么做”更会深入分析“为什么这么做”以及在实际开发中“有哪些坑”。无论你是正在寻找毕业设计题目的同学还是想通过一个完整项目巩固SpringBoot和Vue技能的开发者这篇文章都将提供一份从零到一的实战指南。1. 这个项目真正要解决什么问题学生宿舍报修管理系统表面上是解决“宿舍东西坏了找谁修”的问题。但从软件开发的角度看它要解决的是多角色协同业务流程的数字化建模与实现。这听起来有点抽象我们拆开来看业务痛点传统报修靠纸条、电话或跑腿信息易丢失、进度不透明、责任难追溯。系统要解决信息流转低效、状态不透明、数据无法统计的问题。技术痛点对开发者而言如何设计一个清晰、可扩展的数据库来支撑“报修单”这个核心实体的全生命周期状态流转如何为不同角色学生、维修工、管理员设计合理的前端界面和后端接口权限如何保证前后端数据交互的效率和安全性学习痛点对毕业设计而言如何选择一个技术栈既能体现技术能力又不会过于冷门或复杂如何确保项目结构清晰、代码规范便于答辩讲解如何让项目除了基础功能外还有那么一两个“亮点”因此这个项目的价值远不止于实现功能。它是一次完整的、微缩版的企业应用开发实践。通过它你可以系统地练习后端SpringBoot的快速构建、MyBatis-Plus的高效数据操作、RESTful API设计、全局异常处理、权限拦截如JWT。前端Vue的组件化开发、路由管理(Vue Router)、状态管理(Vuex/Pinia)、异步请求(axios)、Element UI等组件库的使用。工程化前后端分离的协作模式、接口文档管理、基础的Git版本控制。业务思维从需求分析到数据库设计再到功能模块划分的完整流程。如果你能跟着本文的思路不仅跑通代码更能理解每个技术选型背后的原因那么这份毕业设计的含金量将远超一个简单的“作业”。2. 技术栈选型与核心概念为什么是SpringBoot Vue这是目前国内Java领域最主流、最成熟的前后端分离开发组合之一社区活跃、资料丰富非常适合学习和毕业设计。2.1 后端技术栈SpringBoot生态SpringBoot核心框架。它最大的优点是“约定大于配置”内置了Tomcat服务器让你无需复杂配置就能快速启动一个Web应用。这对于需要快速交付的毕业设计来说至关重要。Spring MVC处理Web请求的模型。它帮你优雅地组织Controller、Service、DaoMapper三层架构这是企业级项目的标准分层。MyBatis-Plus数据持久层框架。它是MyBatis的增强工具提供了强大的CRUD封装。你几乎不用写简单的SQL就能完成绝大多数数据操作极大提升开发效率。它的QueryWrapper等条件构造器也非常好用。MySQL关系型数据库。稳定、易用、免费是学习和小型项目的首选。Maven项目构建与依赖管理工具。通过一个pom.xml文件管理所有第三方库Jar包解决令人头疼的依赖冲突问题。2.2 前端技术栈Vue生态Vue.js渐进式JavaScript框架。核心是数据驱动和组件化学习曲线相对平缓能快速构建出交互丰富的单页面应用(SPA)。Vue Router官方路由管理器。负责管理前端页面之间的跳转在SPA中实现无刷新切换视图。Vuex/Pinia状态管理模式库。用于集中管理所有组件共享的状态例如当前登录的用户信息。Pinia是Vuex的升级版更简单、更符合组合式API风格新项目建议使用Pinia。Axios基于Promise的HTTP客户端。用于浏览器和Node.js中发送请求是前后端通信的桥梁。Element Plus基于Vue 3的桌面端组件库。提供了丰富的、美观的UI组件按钮、表单、表格、弹窗等让你能快速搭建出专业的管理后台界面无需从零设计CSS。2.3 核心架构前后端分离B/S这是本项目的关键架构。理解它就理解了现代Web开发的主流模式。前端Vue运行在用户的浏览器中负责渲染页面、处理用户交互。它通过Axios调用后端提供的RESTful API接口来获取或提交数据JSON格式。后端SpringBoot运行在服务器上负责处理业务逻辑、操作数据库。它接收前端的API请求处理完成后返回JSON数据不关心页面如何渲染。优势前后端职责清晰可以并行开发前端技术选型灵活后端接口可以供多种客户端Web、App、小程序复用。3. 开发环境与工具准备工欲善其事必先利其器。以下是推荐的环境配置清单版本号请根据实际情况调整但大版本建议保持一致以避免兼容性问题。3.1 后端环境准备JDK版本 8、11 或 17LTS长期支持版。推荐JDK 17它是目前的主流选择。安装后配置JAVA_HOME环境变量。IDEIntelliJ IDEA社区版或旗舰版。它对Java和SpringBoot的支持是最好的能极大提升开发效率。Maven版本 3.6。IDEA通常自带但建议独立安装并配置MAVEN_HOME和仓库镜像如阿里云镜像以加速依赖下载。MySQL版本 5.7 或 8.0。安装后记住root密码并安装一个图形化管理工具如Navicat、MySQL Workbench或IDEA自带的Database工具。3.2 前端环境准备Node.js版本 16。它是JavaScript的运行环境自带包管理工具npm。安装Node.js后npm即可使用。包管理器可以使用npm但更推荐yarn或pnpm它们速度更快、依赖管理更清晰。可以通过npm install -g yarn安装yarn。IDEVisual Studio Code (VSCode)。轻量且强大的代码编辑器拥有丰富的Vue插件生态。Vue CLI 或 Vite项目脚手架。Vue CLI是传统选择功能全面。Vite是新一代构建工具启动和热更新速度极快。本文示例将使用更现代的Vite来创建Vue项目。3.3 初始化项目结构在开始编码前你的工作空间应该有两个独立的项目文件夹workspace/ ├── dorm-repair-backend/ # SpringBoot后端项目 └── dorm-repair-frontend/ # Vue前端项目两者完全独立通过API接口通信。4. 后端核心设计与实现我们从后端开始因为后端定义了数据的结构和业务的规则。4.1 数据库设计数据库设计是项目的基石。一个糟糕的设计会让后续编码举步维艰。围绕“报修单”这个核心我们至少需要以下表用户表 (sys_user)存储所有系统用户学生、维修工、管理员。通过user_type字段区分角色。报修单表 (repair_order)核心表。记录报修详情、状态、时间等。宿舍楼表 (dorm_building)和宿舍房间表 (dorm_room)维护宿舍资源信息。报修单需要关联到具体房间。维修记录表 (repair_record)可选。用于记录维修工每次的处理反馈实现更细粒度的跟踪。以下是repair_order表的一个简化DDL示例CREATE TABLE repair_order ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID, order_number varchar(32) NOT NULL COMMENT 报修单号可规则生成如REPAIR202411110001, student_id bigint(20) NOT NULL COMMENT 报修学生ID, room_id bigint(20) NOT NULL COMMENT 报修房间ID, title varchar(100) NOT NULL COMMENT 报修标题, description text COMMENT 问题详细描述, image_urls varchar(500) DEFAULT NULL COMMENT 现场图片URL多个用逗号分隔, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 状态0-待受理1-已受理/维修中2-已完成3-已取消, handler_id bigint(20) DEFAULT NULL COMMENT 处理人维修工ID, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, appointment_time datetime DEFAULT NULL COMMENT 预约维修时间, finish_time datetime DEFAULT NULL COMMENT 完成时间, rating tinyint(4) DEFAULT NULL COMMENT 评分1-5星, comment varchar(255) DEFAULT NULL COMMENT 评价内容, PRIMARY KEY (id), UNIQUE KEY uk_order_number (order_number), KEY idx_student_id (student_id), KEY idx_handler_id (handler_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT报修单表;设计要点order_number唯一单号便于线下沟通和查询。status字段使用字典值清晰定义工单生命周期。记录关键时间点create_time,update_time,finish_time便于统计和分析。image_urls字段存储图片路径实际文件可上传至服务器目录或云存储如OSS数据库中只存访问地址。4.2 创建SpringBoot项目使用IDEA的Spring Initializr或访问 start.spring.io 创建项目。Project: MavenLanguage: JavaSpring Boot: 2.7.x 或 3.x注意JDK版本对应关系Spring Boot 3.x需要JDK 17Dependencies: 勾选Spring Web,MyBatis Framework,MySQL Driver。创建完成后在pom.xml中手动添加MyBatis-Plus的依赖。!-- pom.xml 中添加 MyBatis-Plus 依赖 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version !-- 请使用最新稳定版 -- /dependency !-- 代码生成器可选但强烈推荐用于快速生成基础代码 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-generator/artifactId version3.5.3/version scopeprovided/scope /dependency4.3 项目结构与核心代码标准的MVC分层结构如下src/main/java/com/yourcompany/dormrepair/ ├── DormRepairApplication.java # 启动类 ├── config/ # 配置类如MyBatis-Plus配置、跨域配置 ├── controller/ # 控制器层接收请求返回响应 ├── entity/ # 实体类与数据库表对应 ├── mapper/ # Mapper接口即Dao层 ├── service/ # 业务逻辑层 │ └── impl/ # 业务逻辑实现类 ├── dto/ # 数据传输对象用于前后端交互 ├── vo/ # 视图对象用于返回给前端的特定数据模型 └── common/ # 通用类如统一返回结果、异常、常量实体类示例 (RepairOrder.java)package com.yourcompany.dormrepair.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.time.LocalDateTime; Data TableName(repair_order) // 指定表名 public class RepairOrder { TableId(type IdType.AUTO) // 主键自增 private Long id; private String orderNumber; private Long studentId; private Long roomId; private String title; private String description; private String imageUrls; private Integer status; // 使用枚举更佳 private Long handlerId; TableField(fill FieldFill.INSERT) // 插入时自动填充 private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) // 插入和更新时自动填充 private LocalDateTime updateTime; private LocalDateTime appointmentTime; private LocalDateTime finishTime; private Integer rating; private String comment; // 非数据库字段用于关联查询显示 TableField(exist false) private String studentName; TableField(exist false) private String handlerName; TableField(exist false) private String roomNumber; }Mapper接口 (RepairOrderMapper.java)package com.yourcompany.dormrepair.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.yourcompany.dormrepair.entity.RepairOrder; import org.apache.ibatis.annotations.Mapper; Mapper // 重要让MyBatis-Plus扫描到 public interface RepairOrderMapper extends BaseMapperRepairOrder { // 继承BaseMapper后基础的CRUD方法已自动拥有 // 复杂查询可以在这里定义方法并在对应的XML中写SQL }Service层 (RepairOrderService.java)package com.yourcompany.dormrepair.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.yourcompany.dormrepair.entity.RepairOrder; import com.yourcompany.dormrepair.vo.RepairOrderVO; public interface RepairOrderService extends IServiceRepairOrder { // 分页条件查询报修单带关联信息 PageRepairOrderVO getOrderPage(PageRepairOrder page, String keyword, Integer status, Long userId, Integer role); // 学生提交报修单 boolean submitOrder(RepairOrder order, Long studentId); // 维修工接单 boolean acceptOrder(Long orderId, Long handlerId); // 维修工完成维修 boolean completeOrder(Long orderId, String comment); }Controller层 (RepairOrderController.java)package com.yourcompany.dormrepair.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yourcompany.dormrepair.common.Result; import com.yourcompany.dormrepair.entity.RepairOrder; import com.yourcompany.dormrepair.service.RepairOrderService; import com.yourcompany.dormrepair.vo.RepairOrderVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/api/repair-order) public class RepairOrderController { Autowired private RepairOrderService repairOrderService; // 学生提交报修 PostMapping(/submit) public Result? submitOrder(RequestBody RepairOrder order, RequestAttribute Long currentUserId) { // 从Token中获取当前用户ID boolean success repairOrderService.submitOrder(order, currentUserId); return success ? Result.success(提交成功) : Result.error(提交失败); } // 分页查询报修单不同角色看到的数据不同 GetMapping(/page) public ResultPageRepairOrderVO getPage( RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) String keyword, RequestParam(required false) Integer status, RequestAttribute Integer userType) { // 用户角色 PageRepairOrder page new Page(pageNum, pageSize); PageRepairOrderVO orderPage repairOrderService.getOrderPage(page, keyword, status, null, userType); return Result.success(orderPage); } // 维修工接单 PostMapping(/{orderId}/accept) public Result? acceptOrder(PathVariable Long orderId, RequestAttribute Long currentUserId) { boolean success repairOrderService.acceptOrder(orderId, currentUserId); return success ? Result.success(接单成功) : Result.error(接单失败工单可能已被处理); } }统一返回结果封装 (Result.java)package com.yourcompany.dormrepair.common; import lombok.Data; import java.io.Serializable; Data public class ResultT implements Serializable { private Integer code; private String msg; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMsg(操作成功); result.setData(data); return result; } public static T ResultT success(String msg) { ResultT result new Result(); result.setCode(200); result.setMsg(msg); return result; } public static T ResultT error(String msg) { ResultT result new Result(); result.setCode(500); result.setMsg(msg); return result; } // 可以定义更多状态码如 400参数错误、401未授权、403禁止访问等 }4.4 关键配置application.yml配置文件server: port: 8080 # 后端服务端口 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/dorm_repair_db?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai username: root password: yourpassword servlet: multipart: max-file-size: 10MB # 文件上传大小限制 max-request-size: 20MB mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印SQL调试用生产环境关闭 global-config: db-config: logic-delete-field: deleted # 全局逻辑删除字段名如果表中有此字段 logic-delete-value: 1 # 逻辑已删除值 logic-not-delete-value: 0 # 逻辑未删除值 mapper-locations: classpath:mapper/*.xml # XML映射文件位置 # 自定义配置如JWT密钥、文件上传路径 app: upload-path: /path/to/upload # 文件上传本地路径 jwt: secret: your-jwt-secret-key-here-minimum-32-chars expire: 7200 # token过期时间秒5. 前端核心设计与实现后端API准备好后前端的工作就是调用这些接口构建用户界面。5.1 使用Vite创建Vue 3项目在dorm-repair-frontend目录下打开终端执行# 使用 npm npm create vuelatest # 或使用 yarn yarn create vue按照提示选择项目特性TypeScript推荐、Vue Router、Pinia、ESLint。 创建完成后安装Element Plus和Axioscd dorm-repair-frontend npm install element-plus axios # 或 yarn add element-plus axios5.2 项目结构src/ ├── api/ # 所有API请求封装 ├── assets/ # 静态资源 ├── components/ # 公共组件 ├── router/ # 路由配置 ├── stores/ # Pinia状态管理 ├── views/ # 页面组件 │ ├── Login.vue # 登录页 │ ├── Student/ # 学生相关页面 │ │ ├── Dashboard.vue │ │ ├── RepairSubmit.vue │ │ └── MyOrders.vue │ ├── Worker/ # 维修工相关页面 │ │ ├── TaskList.vue │ │ └── TaskDetail.vue │ └── Admin/ # 管理员相关页面 │ ├── UserManage.vue │ └── OrderManage.vue ├── utils/ # 工具函数如请求拦截器、日期格式化 ├── App.vue └── main.ts5.3 核心代码示例1. 配置Axios和请求拦截器 (utils/request.ts)import axios from axios; import { ElMessage } from element-plus; import router from /router; const service axios.create({ baseURL: http://localhost:8080/api, // 后端API地址 timeout: 10000, }); // 请求拦截器在请求头中添加Token service.interceptors.request.use( (config) { const token localStorage.getItem(token); if (token) { config.headers.Authorization Bearer ${token}; } return config; }, (error) { return Promise.reject(error); } ); // 响应拦截器统一处理错误 service.interceptors.response.use( (response) { const res response.data; // 假设后端统一返回 { code: 200, msg: success, data: ... } 格式 if (res.code ! 200) { ElMessage.error(res.msg || 请求失败); // 如果是未授权跳转到登录页 if (res.code 401) { localStorage.removeItem(token); localStorage.removeItem(userInfo); router.push(/login); } return Promise.reject(new Error(res.msg || Error)); } return res.data; // 直接返回后端封装里的data字段 }, (error) { console.error(请求错误:, error); ElMessage.error(网络错误或服务器异常); return Promise.reject(error); } ); export default service;2. 封装API模块 (api/repairOrder.ts)import request from /utils/request; // 定义接口返回的数据类型根据后端VO定义 export interface RepairOrderVO { id: number; orderNumber: string; title: string; status: number; studentName: string; handlerName?: string; createTime: string; // ... 其他字段 } export interface PageResultT { records: T[]; total: number; size: number; current: number; } // API函数 export const repairOrderApi { // 提交报修单 submitOrder(data: any) { return request.post(/repair-order/submit, data); }, // 分页查询报修单 getOrderPage(params: { pageNum: number; pageSize: number; keyword?: string; status?: number }) { return request.getPageResultRepairOrderVO(/repair-order/page, { params }); }, // 维修工接单 acceptOrder(orderId: number) { return request.post(/repair-order/${orderId}/accept); }, // 维修工完成维修 completeOrder(orderId: number, comment: string) { return request.post(/repair-order/${orderId}/complete, { comment }); }, // 学生取消报修 cancelOrder(orderId: number) { return request.post(/repair-order/${orderId}/cancel); }, };3. 学生提交报修页面组件 (views/Student/RepairSubmit.vue)template div classrepair-submit-container el-card classbox-card template #header span提交报修申请/span /template el-form :modelform :rulesrules refformRef label-width100px el-form-item label报修标题 proptitle el-input v-modelform.title placeholder请输入报修问题摘要如宿舍空调不制冷 / /el-form-item el-form-item label宿舍房间 proproomId el-select v-modelform.roomId placeholder请选择房间 el-option v-forroom in roomList :keyroom.id :labelroom.fullName :valueroom.id / /el-select /el-form-item el-form-item label问题描述 propdescription el-input v-modelform.description typetextarea :rows4 placeholder请详细描述故障现象... / /el-form-item el-form-item label上传图片 el-upload action# :auto-uploadfalse :on-changehandleFileChange :file-listfileList list-typepicture-card :limit3 el-iconPlus //el-icon /el-upload /el-form-item el-form-item label预约时间 el-date-picker v-modelform.appointmentTime typedatetime placeholder选择预约维修时间可选 value-formatYYYY-MM-DD HH:mm:ss / /el-form-item el-form-item el-button typeprimary clicksubmitForm :loadingsubmitting提交/el-button el-button clickresetForm重置/el-button /el-form-item /el-form /el-card /div /template script setup langts import { ref, reactive, onMounted } from vue; import { ElMessage, ElUploadFile, type FormInstance, type FormRules } from element-plus; import { Plus } from element-plus/icons-vue; import { repairOrderApi } from /api/repairOrder; import { roomApi } from /api/room; // 假设有获取房间列表的API const formRef refFormInstance(); const submitting ref(false); const roomList refany[]([]); const form reactive({ title: , roomId: undefined as number | undefined, description: , appointmentTime: , }); const rules: FormRules { title: [{ required: true, message: 请输入报修标题, trigger: blur }], roomId: [{ required: true, message: 请选择宿舍房间, trigger: change }], description: [{ required: true, message: 请输入问题描述, trigger: blur }], }; const fileList refElUploadFile[]([]); // 处理文件选择 const handleFileChange (file: ElUploadFile) { // 这里可以预览或限制文件大小/类型 console.log(file changed, file); }; // 加载房间列表 const loadRooms async () { try { const res await roomApi.getMyRooms(); // 假设此API返回学生所属房间 roomList.value res; } catch (error) { console.error(加载房间列表失败, error); } }; // 提交表单 const submitForm async () { if (!formRef.value) return; await formRef.value.validate(async (valid) { if (!valid) { ElMessage.warning(请完善表单信息); return; } submitting.value true; try { // 处理图片上传实际项目中需先上传到文件服务器获取URL const imageUrls fileList.value.map(f f.url).join(,); const submitData { ...form, imageUrls }; await repairOrderApi.submitOrder(submitData); ElMessage.success(报修申请提交成功); resetForm(); } catch (error) { console.error(提交失败, error); ElMessage.error(提交失败请重试); } finally { submitting.value false; } }); }; const resetForm () { formRef.value?.resetFields(); fileList.value []; }; onMounted(() { loadRooms(); }); /script style scoped .repair-submit-container { padding: 20px; } .box-card { max-width: 800px; margin: 0 auto; } /style4. 路由守卫与权限控制 (router/index.ts)import { createRouter, createWebHistory } from vue-router; import type { RouteLocationNormalized } from vue-router; const routes [ { path: /login, name: Login, component: () import(/views/Login.vue), meta: { requiresAuth: false } }, { path: /student, name: Student, component: () import(/layouts/StudentLayout.vue), // 学生端布局 meta: { requiresAuth: true, role: student }, children: [ { path: dashboard, component: () import(/views/Student/Dashboard.vue) }, { path: submit, component: () import(/views/Student/RepairSubmit.vue) }, { path: orders, component: () import(/views/Student/MyOrders.vue) }, ] }, // ... 维修工和管理员路由类似 ]; const router createRouter({ history: createWebHistory(), routes, }); // 路由守卫检查登录状态和权限 router.beforeEach((to: RouteLocationNormalized, from, next) { const token localStorage.getItem(token); const userInfo JSON.parse(localStorage.getItem(userInfo) || {}); // 如果目标路由需要认证 if (to.meta.requiresAuth) { if (!token) { // 未登录跳转到登录页 next(/login); return; } // 检查角色权限 const requiredRole to.meta.role; if (requiredRole userInfo.userType ! requiredRole) { // 角色不符跳转到无权限页面或首页 ElMessage.warning(无权访问此页面); next(/${userInfo.userType}/dashboard); // 跳转到对应角色的首页 return; } } next(); }); export default router;6. 系统运行与效果验证6.1 启动后端服务确保MySQL服务已启动并创建了数据库dorm_repair_db。在IDEA中找到主启动类DormRepairApplication.java右键运行。观察控制台日志看到类似Tomcat started on port(s): 8080的日志表示启动成功。可以在浏览器访问http://localhost:8080如果配置了简单的测试接口或使用Postman测试API。6.2 启动前端服务在dorm-repair-frontend目录下打开终端。运行npm run dev或yarn dev。控制台会输出本地访问地址通常是http://localhost:5173Vite默认端口。在浏览器打开该地址即可看到前端应用。6.3 功能验证流程登录使用不同角色的测试账号学生、维修工、管理员登录。学生端进入“提交报修”页面填写表单并提交。在“我的报修”页面查看刚提交的工单状态应为“待受理”。维修工端登录后在“待处理任务”列表中应能看到学生提交的工单。点击“接单”工单状态变为“维修中”。维修完成后点击“完成”填写维修备注状态变为“已完成”。学生端刷新“我的报修”页面看到工单状态已更新为“已完成”。可以对已完成工单进行“评价”。管理员端查看所有报修单的统计。管理用户和宿舍信息。7. 常见问题与排查思路问题现象可能原因排查方式解决方案前端访问后端API报跨域错误 (CORS)浏览器安全策略阻止跨域请求浏览器开发者工具Console或Network面板查看错误信息在后端SpringBoot中添加全局CORS配置类允许前端域名访问。前端页面空白控制台报JS错误1. 依赖未正确安装2. 组件引入错误3. TypeScript类型错误查看浏览器Console具体错误信息定位到文件和行号1. 重新运行npm install。2. 检查组件导入路径和命名。3. 根据TS错误提示修复类型。后端启动失败端口被占用8080端口已被其他程序使用查看启动日志中的错误信息1. 关闭占用端口的进程。2. 在application.yml中修改server.port为其他端口如8081。数据库连接失败1. MySQL服务未启动2. 连接URL、用户名、密码错误3. 时区配置问题查看后端启动日志中的SQL异常堆栈1. 启动MySQL服务。2. 检查application.yml中的数据库配置。3. 在连接URL中添加serverTimezoneAsia/Shanghai。MyBatis-Plus查询不到数据1. 实体类字段名与数据库列名未正确映射2. 表名未指定开启SQL日志(mybatis-plus.configuration.log-impl)查看实际执行的SQL1. 使用TableField注解指定映射关系。2. 使用TableName注解指定表名。文件上传失败1. 上传大小超过限制2. 服务器存储路径无写权限查看后端日志1. 调整spring.servlet.multipart.max-file-size。2. 检查app.upload-path配置的目录是否存在且有权限。前端路由跳转后页面空白1. 路由配置错误2. 组件未正确导出或引入查看浏览器Console和Vue Devtools中的路由状态1. 检查router/index.ts中的component导入路径。2. 确保Vue组件使用了script setup或正确导出了default。登录成功后Token无效1. Token未正确存储在localStorage2. 请求拦截器未正确添加Token3. 后端JWT解析失败1. 检查Application - Local Storage。2. 检查Network请求头中是否有Authorization。3. 查看后端日志。1. 确保登录接口返回Token后正确存储。2. 检查utils/request.ts中的拦截器逻辑。3. 检查后端JWT生成和验证的密钥是否一致。8. 项目优化与进阶建议毕业设计亮点完成基础功能后以下优化点可以让你的项目脱颖而出引入Redis缓存将频繁访问且变化不频繁的数据如宿舍楼列表、字典数据缓存到Redis减轻数据库压力。集成消息推送当工单状态变更如被接单、完成时通过WebSocket或第三方推送服务如极光推送实时通知学生和维修工。实现文件云存储将报修图片上传至阿里云OSS、腾讯云COS等对象存储服务避免占用应用服务器磁盘并提升访问速度。添加数据可视化使用ECharts等库为管理员后台添加统计图表如“每月报修量趋势”、“各类故障占比”、“维修工接单排行”等。编写单元测试为后端的Service层关键方法编写JUnit单元测试体现工程化思维。使用Docker容器化部署编写Dockerfile和docker-compose.yml将MySQL、Redis、后端应用、前端应用容器化一键部署展示运维能力。实现简单的权限控制(RBAC)不仅通过角色控制页面访问更细化到接口级别和数据级别例如维修工只能看到分配给自己的工单。接入第三方登录允许学生通过学校统一身份认证系统模拟或微信扫码登录。生成接口文档使用Swagger或Knife4j自动生成后端API文档方便前后端联调也体现专业度。9. 总结与学习路径建议通过这个“学生宿舍报修信息管理系统”的完整开发实践我们走通了一个典型前后端分离Web应用的全流程。从需求分析、技术选型、数据库设计到SpringBoot后端开发、Vue前端组件化实现再到最后的联调测试每一步都紧扣实际开发场景。这个项目最大的价值在于它的完整性和典型性。它几乎涵盖了本科阶段软件工程课程要求的所有核心知识点。在答辩时你可以清晰地阐述为什么选择这个架构前后端分离的优势数据库表是如何设计的ER关系、状态字段设计前后端是如何交互的RESTful API设计、Axios封装权限是如何控制的路由守卫、接口拦截项目有哪些可扩展性缓存、消息、云存储等优化方向对于学习者而言不要满足于仅仅复制代码跑通。建议你理解读懂每一行代码的作用特别是MyBatis-Plus的封装、Vue的响应式原理、Pinia的状态管理。改造尝试修改需求比如增加“紧急报修”类型并优先显示或者为维修工增加“签到打卡”功能。调试故意制造一些Bug如传错参数、关掉数据库学习如何根据错误信息排查问题。重构思考代码结构是否可以优化比如将一些工具函数抽离将复杂的组件拆分成更小的子组件。技术的学习在于举一反三。掌握了这个项目的精髓你就能快速上手开发其他类似的管理系统如实验室设备预约、图书借阅、社团活动报名等。项目的完整源码可以作为你技术学习的起点和未来求职时的一个扎实作品。建议你在开发过程中养成良好的代码注释和Git提交习惯这本身也是一项重要的工程能力。 30款热门AI模型一站整合DeepSeek/GLM/Claude 随心用限时 5 折。 点击领海量免费额度