
简介本资源是一套面向计算机专业本科生的毕业设计实战项目聚焦校园场景下的报修业务数字化管理完整呈现从需求分析到系统上线的全流程实现。资源包含基于Spring Boot后端与Vue前端的全栈代码、MySQL数据库脚本、系统部署说明文档及配套软件工程图表架构图、用例图、E-R图等覆盖系统管理、用户权限、维修类型/工具/记录/评价等核心模块可直接用于课程设计、毕设开发或教学参考。压缩包共694个文件含317个Java后端逻辑文件、104个Vue组件与页面、78个JS交互脚本、40个XML配置、5个YML环境配置及1个SQL建库脚本整体2.15MB结构清晰、模块解耦支持快速本地运行与二次开发。已有49人学习下载附带run.bat、package.bat等一键启停脚本及.env.development环境配置显著降低部署门槛。 去年年底帮学校信息化中心做内部工具时顺手把一套基于SpringBootVue的校园报修系统完整落地了代码、数据库脚本、部署文档都在手边。最近不少朋友在问这类管理系统从零到上线到底要经历哪些环节干脆把这套报修系统的设计与实现拆开写成一篇实操向总结覆盖需求分析、数据库设计、后端接口、前端页面、部署排错这几大块给正在做课设、毕设或者想接手类似管理系统的同学提供一份完整可参考的路线。这类系统最大的特点是业务模型典型、角色划分清晰、技术栈通用非常适合作为SpringBoot和Vue的实战练手项目。同时它又不像纯电商或社交系统那样业务链复杂一个新手在两周内完全能够走通全流程。我会把实际编码过程中踩过的坑、绕过的弯也一并写出来有些坑网上基本搜不到标准答案只能靠自己试。1. 系统需求拆解与整体设计思路1.1 校园报修的核心业务场景做任何系统之前先要搞清楚业务到底在解决什么问题。校园报修系统表面上是“学生提交故障、维修工处理故障”但把它放进真实的校园环境里看会发现涉及三类角色、多个流程节点和不少边界情况。第一类角色是报修人通常是学生或者老师。他们的诉求非常简单遇到灯管坏了、空调不制冷、门锁损坏、水管漏水这些情况能快速提交一条报修记录并且能看到这单子到底有没有人接、修到哪一步了。第二类是维修工他们需要看到分配给自己或者自己所在班组的工单处理完以后要填写维修结果、用料情况必要时上传维修前后的照片作为凭证。第三类是管理员通常是后勤或信息中心的老师他们负责分配工单、跟踪超时未处理的单子、统计各区域各类型的报修数据、管理维修工账号等。在设计系统时不能只盯着“提交-处理”这条主线还要考虑一些非常现实的场景。比如报修人提交单子以后很久没人接系统需要超时提醒维修工上门后发现缺少配件工单不能直接关闭要能挂起并标注原因管理员需要按宿舍楼、教学楼、办公楼不同区域查看报修密度用来判断哪些楼栋设施老化严重。这些需求如果前期不梳理清楚后面开发中反复改表结构是非常痛苦的。1.2 从需求到功能模块的转化把上面的业务场景落成功能模块我最终划分成五个核心模块这也是整套系统的骨架用户认证与权限管理登录、注册、退出、基于角色的访问控制RBAC不同角色登录后看到的菜单和操作按钮完全不同。报修工单管理工单的创建、查询、分配、接单、处理、完成、评价整个生命周期涉及的状态流转是系统核心逻辑。通知与消息提醒工单分配后维修工收到提醒、报修人提交后收到回执、超时工单推送警告实际开发中我用的是站内信WebSocket实时推送简单够用。统计报表管理员查看按日期、按区域、按类型的工单数量统计用ECharts画柱状图和折线图。系统管理用户管理、维修工信息维护、楼栋区域管理、故障类型字典维护。模块划分完成后再按角色画一遍操作流程就能把接口设计得很清晰。报修人端只有“我的报修”两个页面维修工端有“我的工单”和“历史记录”管理员端则集中了全量的管理和分配操作。1.3 为什么选SpringBootVue这套组合这套组合现在已经是Java全栈项目的绝对主流选型的时候我也没太多犹豫。SpringBoot负责后端接口层它内置Tomcat无需额外配置Web服务器就能跑起来而且Spring生态的成熟度让事务管理、参数校验、异常处理这些基础能力都能通过注解快速完成省去了大量样板代码。Vue侧用了Vue 3加Element Plus组件库覆盖了表格、表单、弹窗、上传、日期选择这些后台管理系统的高频组件美观度也够不用自己造轮子。对比一下其他方案会更理解这个选型优势。如果后端用SSHStrutsSpringHibernate配置繁琐、开发效率低现在基本没有新项目这么搞了如果用Node.js的Express或Koa后端开发快但Java系的同学维护起来不顺手而且学校里很多服务器环境对Java的运维经验更丰富。前端如果不选Vue选React语法上Hooks的思维门槛比Vue的选项式API高一些新手学习曲线更陡在校园管理系统这种CRUD为主的场景里Vue的上手效率确实更高。1.4 项目目录结构与技术栈版本规划开始写代码之前我先规划好了项目的整体结构。后端采用标准的Maven多模块结构虽然实际项目不算特别大但按controller、service、mapper、entity、config、common这几层分包后续扩展和维护会清晰很多。前端使用Vite作为构建工具比Webpack在开发环境下的热更新速度快了不止一个量级。技术版本我在项目里实际使用的是SpringBoot 2.7.18、JDK 1.8、MyBatis-Plus 3.5.3、MySQL 8.0、Vue 3.4、Vite 5、Element Plus 2.6。这里要特别提醒一句如果选SpringBoot 3.xJDK必须最低17同时javax包要换成jakarta包很多网上的老代码直接搬过来会报错。我建议做这类项目时尽量用2.7.x版本稳定且网上能找到的资料最多排错成本低。选定版本后把依赖统一写在pom.xml里避免依赖冲突。2. 数据库设计报修业务的表结构与核心关系2.1 核心表结构一览数据库设计是这类管理系统最见功力的部分。表设计得好业务代码写起来非常顺设计得不好后期要加字段、拆表、写各种奇怪SQL的时候就知道痛了。我最终设计了六张核心业务表和两张辅助表核心表分别是用户表、维修工信息表、报修工单表、工单日志表、故障类型表、楼栋区域表。用户表sys_user存储登录账号、密码BCrypt加密、姓名、手机号、角色类型。维修工信息表repairer和用户表做一对一关联额外存了工号、所属班组、擅长类型、当前状态空闲/忙碌。楼栋区域表building存校区、楼栋名称、楼层数。故障类型表fault_type做成了字典表方便在后台动态添加新的故障类别不必改代码。真正核心的是报修工单表repair_order我把字段设计成下面这样order_no工单号用时间戳加随机数生成全局唯一方便线下沟通时口头报号。user_id报修人ID关联用户表。building_id楼栋ID关联楼栋区域表。location_detail详细位置比如“3栋205室”、“图书馆2楼东侧走廊”。fault_type_id故障类型ID关联故障类型表。description故障描述允许报修人填写一两句话。image_urls图片路径允许多张用逗号分隔这是上传图片的凭证。status工单状态整型值0待分配、1待接单、2维修中、3待验收、4已完成、5已驳回这套状态机是整个系统的心脏。assign_to当前指派的维修工ID为0表示未指派。create_time、update_time创建时间和更新时间。finish_time完成时间用来计算超时时长。2.2 工单状态机与状态流转逻辑工单状态是这类系统最需要细抠的部分很多人在设计状态时只想到“待处理、处理中、已完成”三个状态但实际使用中远远不够。我在项目里把状态细化为六个每个状态之间的流转是有严格约束的。报修人提交工单后进入待分配0此时管理员在后台看到新工单并指定维修工分配后进入待接单1。维修工在移动端看到分配给自己但还未接单的工单点“接单”后进入维修中2。维修完成后维修工填写维修结果并提交工单进入待验收3此时报修人可以查看维修结果并确认确认后工单进入已完成4。如果管理员在审核过程中发现描述不清、位置不对或维修工反馈信息不足可以直接驳回5工单会退回到待分配状态。这个流程里有一个容易被忽略的细节状态变更不能只更新一个数字每一次状态流转都要写一条工单日志记录操作人、操作时间、从什么状态变成什么状态、备注内容。这个日志表在后期排查问题、用户投诉、责任界定时非常有用。比如学生说“我报修了怎么没人来”管理员一查日志就能看到工单分配给了谁、什么时候接单、为什么延误。没有这张日志表系统就是一个黑盒。2.3 数据库脚本与初始化数据写完建表语句一定要把初始化数据一并准备好。我所谓的准备好不是只在数据库客户端里手动插入几条测试数据而是要写成SQL脚本随项目一起提交到代码仓库里。这样任何一个人拿到项目执行一遍init.sql加data.sql就能把整个库建起来。项目中我会准备两个脚本一个是schema.sql负责建库建表一个是data.sql负责插入管理员账号、测试用户、故障类型字典、楼栋区域等基础数据。关于数据脚本有几个非常实用的建议。第一字符集统一使用utf8mb4而不是utf8因为utf8在MySQL里存不了emoji表情如果报修人描述故障时带了个emoji就插入失败换utf8mb4一劳永逸。第二所有表的存储引擎都指定InnoDB支持事务和外键约束在更新工单和写日志两个操作时要保证原子性。第三时间字段统一用datetime类型并设置默认值CURRENT_TIMESTAMP避免应用层到处传时间。第四为订单表的status、assign_to字段建索引因为统计和筛选场景非常高频不加索引数据量上来后查询会明显变慢。数据库连接配置我写在application.yml中这里有几个参数值得注意。时区参数必须加上serverTimezoneAsia/Shanghai否则Java连接MySQL 8.x时很容易出现8小时时差问题。参数useSSLfalse是因为本地开发和内网部署不需要SSL加密少了握手耗时。参数allowPublicKeyRetrievaltrue是MySQL 8.x在非SSL连接下必须加的不加会报Public Key Retrieval is not allowed。3. SpringBoot后端接口设计与核心业务实现3.1 后端分层架构与接口设计规范后端我按经典的Controller-Service-Mapper三层来组织在此基础上增加了Config层配置类和Common层统一返回结果、异常处理、工具类。Controller层只做参数接收和结果封装不写任何业务逻辑Service层负责事务管理和业务规则Mapper层使用MyBatis-Plus提供的基础方法复杂SQL才手写XML。统一返回结果这一块我定义了一个Result类结构为code、message、data三个字段。code为200表示成功业务异常返回400开头未认证返回401无权限返回403系统异常返回500。前端Axios拦截器只需要判断code是否为200就可以决定是否进入正常处理流程。这样设计的好处是前后端对接时沟通成本非常低前端看到401就跳登录页看到403就提示无权限其他情况下弹出message字段的内容。接口路径按资源命名例如/api/order/create、/api/order/list、/api/order/assign、/api/order/handle。所有接口统一以/api前缀开头方便Nginx做反向代理时直接按路径转发给后端服务。接口方法使用POST为主查询列表也可以使用GET但涉及状态变更的操作一律POST避免通过URL直接触发状态修改。3.2 报修工单核心接口的实现细节工单相关的接口是整个系统最核心的部分我在这里详细拆解几个关键接口的设计思路。提交报修接口的入参包含buildingId、locationDetail、faultTypeId、description、imageUrls用户信息从登录状态中获取不从前端传入这一点非常重要。如果从前端传userId有心人就可以伪造别人的身份提交工单导致系统数据混乱。获取用户身份的做法是前端登录成功后后端返回一个Token前端每次请求在请求头携带这个Token后端通过拦截器解析Token获得用户信息。这个项目里我用的是JWT无状态、不需要在服务端存session非常适合前后端分离架构。分配工单接口只有管理员角色能调用入参是orderId和repairerId。实现逻辑是开启事务先查询工单当前状态如果不是待分配状态则抛出异常然后更新工单的assign_to字段和status为待接单同时插入一条工单日志最后通过WebSocket给对应维修工推送一条新工单提醒。这几步操作必须在同一个事务中任何一个失败都要回滚否则会出现工单状态变了但日志没写、或者提醒推了但工单没分配成功的情况。处理工单接口的状态流转逻辑用状态机模式实现我在项目里写了一个简单的状态流转校验工具类传入当前状态和目标状态只有符合预设流转规则才允许执行。比如待分配状态可以直接跳到已驳回但维修中不能直接跳到已完成必须经过待验收。这样的设计虽然增加了少量代码但避免了业务规则混乱导致的脏数据。3.3 登录认证、权限校验与安全实践认证和权限我使用的是Spring Security加JWT的组合方案。用户名密码登录成功后后端生成一个Token返回给前端Token中只存放userId和角色信息不存放敏感数据。每次请求经过一个自定义的OncePerRequestFilter从请求头中取出Token并解析解析成功就把用户信息放进SecurityContext。放行规则使用AntPathMatcher配置/api/auth/login和静态资源放行其他接口全部需要认证。角色权限校验在Spring Security中通过PreAuthorize注解实现在Controller方法上标注PreAuthorize(hasRole(ADMIN))只有管理员角色才能调用。这里分享一个容易踩的坑Spring Security默认的角色前缀是ROLE_如果数据库里存的是ADMIN那么在权限表达式里要写hasRole(ADMIN)但JWT里存的权限集合要带上前缀。如果不带前缀或大小写不一致会一直得到403。我第一次调试接口时花了不少时间才定位到这个问题。密码存储直接使用BCrypt加密这也是Spring Security自带的能力。BCrypt每次加密同一个密码产生的hash都不同因为里面混入了随机盐但校验时能正确匹配。用BCrypt意味着数据库即使泄露也无法通过彩虹表还原出密码原文安全性比MD5加固定盐高很多。实际中我见过很多管理系统直接把明文密码存数据库这种习惯必须改掉。3.4 文件上传与图片访问的工程化处理报修单需要上传故障照片这就涉及文件上传和静态资源访问。上传接口接收MultipartFile检查文件类型和大小后存储到服务器指定目录。我在application.yml中配置了file.upload-dir/data/repair-system/upload图片按日期分子目录存放文件名用UUID重命名避免中文文件名和重名覆盖的问题。数据库中存的是相对路径如/2025/06/01/xxx.jpg访问时由Nginx映射磁盘目录。安全性上要注意两点。第一文件类型只允许常见的jpg、png、webp格式大小限制在5MB以内前端上传前先做一次校验后端还要再做一次校验不能完全相信前端的校验结果。第二文件存储路径不允许用户直接传入而是由后端根据日期和UUID生成防止路径穿越攻击。有些攻击者会在文件名里加入../尝试写入服务器任意目录后端重新命名后这个攻击面就完全封死了。3.5 全局异常处理与日志记录后端异常如果不能统一处理前端就会收到各种格式乱七八糟的错误信息对用户体验影响很大。我实现了一个全局异常处理器使用RestControllerAdvice注解捕获三类异常业务异常、参数校验异常和系统异常。业务异常是我在Service层主动抛出的包含明确的错误信息例如“该工单当前状态不允许此操作”参数校验异常由Valid注解触发会把校验不通过的具体字段名返回给前端系统异常属于未预料的错误返回统一提示并记录完整堆栈日志。日志记录使用SLF4J加Logback按天滚动生成日志文件生产环境下日志级别设为INFO。我在工单状态变更、用户登录、权限拒绝这几个关键位置加了操作日志使用Slf4j实现类中直接调用log.info。互联网上很多项目没有打日志的习惯到了线上出问题就只能瞎猜这是非常糟糕的实践。写日志并不是为了好看而是为了问题发生时能还原现场所以日志至少要包含操作人、操作时间、操作内容和请求参数。4. Vue3前端页面开发与核心交互实现4.1 前端工程结构与开发环境准备前端工程使用Vite创建命令是npm create vitelatest repair-front -- --template vue。创建完成后安装Element Plus、Axios、Vue Router、Pinia这几个核心依赖。Element Plus是UI组件库Axios用于请求后端接口Vue Router管理页面路由Pinia做全局状态管理存用户信息和登录状态。开发环境的跨域问题在vite.config.js中配置代理解决。因为开发时前端运行在5173端口后端运行在8080端口不同端口之间请求属于跨域。我在vite.config.js的server.proxy中将/api前缀的请求代理到http://localhost:8080这样前端代码里写接口路径时直接用相对路径/api/xxx即可。生产环境部署时Nginx再将/api请求反代到后端服务跨域问题在生产环境也不存在。这里多说一句开发环境的配合问题很多人在开发时喜欢在前端所有请求中写上完整的http://localhost:8080地址这样做开发时能跑但部署到生产环境就必须把所有地址改成生产域名非常麻烦。正确的做法是前端代码中只写/api相对路径开发用Vite代理生产用Nginx代理前后端解耦换环境只需要改代理配置不需要动代码。4.2 路由守卫、Axios拦截器与登录态管理路由守卫是前端安全的第一道关卡。我定义路由时将需要登录的页面设置meta.requiresAuth为true在全局前置守卫中判断如果访问的页面需要登录且本地没有Token就跳转到登录页并把原目标地址通过query参数传给登录页如果已经登录且访问的恰好是登录页则直接跳转首页。注意路由守卫只是用户体验层面的控制真正的安全校验还是以后端的Token解析为准前端守卫只能起到分流作用。Axios拦截器我封装了两个方向。请求拦截器在每次发送请求前把Token从Pinia中取出放到请求头Authorization字段。响应拦截器做统一处理返回code 200时直接返回data数据返回401时清除本地登录状态并跳转登录页返回其他错误码时通过Element Plus的ElMessage弹出错误提示。这个封装让页面代码里几乎不需要写try-catch来处理基础错误业务代码只关心成功后的数据。Pinia的管理逻辑很简单store中存放userInfo和token登录成功后写入并持久化到localStorage。页面刷新时从localStorage恢复状态因为刷新页面会清空内存中的数据如果不恢复每次刷新都要重新登录。刷新时还需要调用一次获取用户信息的接口把用户的最新角色和权限重新拉一遍避免权限变更后前端还是旧状态。4.3 报修人端报修提交与工单进度跟踪报修人的核心交互是提交报修和查看进度。报修提交页面使用表单组件包含楼栋选择级联选择器先选楼栋再选楼层房间、故障类型下拉框、文字描述文本框、图片上传组件。图片上传组件使用Element Plus的el-upload配置action为后端上传接口地址设置headers传入Token设置limit最多3张图。上传完成后获取返回的图片路径存入表单的imageUrls数组中提交报修时一并传给后端。工单进度展示这块我用时间线组件展示工单的完整生命周期。根据后端返回的状态字段和日志列表把“提交报修”、“等待分配”、“维修工接单”、“维修中”、“待验收”、“已完成”这些节点按时间顺序渲染在时间线上当前状态高亮。学生提交后打开页面就能一目了然地知道自己的单子处于哪个环节比反复给后勤打电话催问体验好得多。这也是这个系统上线后学生反馈最满意的功能之一。查看工单详情时还会把维修工填写的处理结果、用料说明和维修照片展示出来。如果状态是待验收页面底部显示“确认完成”和“申请驳回”两个按钮学生确认后工单才能真正关闭。这里要说明的是驳回操作不是为了让学生随意退单而是给了一个反馈渠道防止维修工没有真正解决问题但直接点了完成学生有申诉的余地。4.4 维修工端工单列表与移动端适配维修工端主要是两个页面待处理工单列表和历史工单列表。待处理工单列表中展示的是指派给自己的工单每个卡片显示楼栋位置、故障类型、提交时间并有一个“接单”按钮。接单后工单进入维修中状态维修工填写处理说明、可选上传维修后的照片提交后工单进入待验收。在移动端适配时我使用了视口meta标签和Flex布局卡片式设计在手机上看起来也很工整。因为很多维修工文化水平参差不齐用电脑并不方便所以维修工端的页面我重点做了简化处理。所有操作都是大按钮加简单提示文字避免复杂的表单和多余的交互。接单、提交完成、查看详情这三大操作放在最显眼的位置。实测之后维修工们反馈基本不需要培训就能上手这也说明了界面设计不是越炫越好符合用户习惯才最重要。4.5 管理员端工单分配、实时监控与统计图表管理员端功能最密集包括工单管理、用户管理、维修工管理、楼栋管理、故障类型管理、数据统计六个子页面。工单管理页面是核心表格展示所有工单支持按状态、楼栋、时间范围筛选。管理员选中一条新工单后点击分配按钮弹出对话框选择维修工后端接口执行分配逻辑。表格中对于超时未处理的工单状态标签会变成红色并显示“已超时”字样提醒管理员优先处理。数据统计页面使用ECharts图表库调取后端统计接口获取数据后用折线图展示近七天的工单数量趋势、柱状图展示各楼栋报修数量TOP10、饼图展示故障类型分布。为了让统计更直观我还做了一个简单的仪表盘展示今日新增工单、待处理工单、维修中工单、本月完成率四个核心指标。管理员一打开页面就能对当前工作情况有整体了解而不是在一个列表里一条条翻数据。和前端统计图表配套的是后端统计接口使用MyBatis-Plus的QueryWrapper结合SQL聚合函数实现。比如统计各楼栋报修数量使用groupBy(buildingId)加selectCount返回一个Map列表。涉及时间范围查询时注意createTime比较的边界问题今天的数据需要取当天的零点到次日的零点最好在SQL中使用create_time #{startTime} AND create_time #{endTime}这种左闭右开的区间写法避免漏数据或重复数据。5. 部署上线从代码到可访问服务的完整流程5.1 后端打包与部署步骤部署的第一步是后端打包。在项目根目录执行Maven打包命令mvn clean package -DskipTests这里跳过测试是因为单元测试如果依赖数据库环境在打包机上跑可能会因为连不上数据库而失败。打包完成后target目录下生成一个repair-system.jar文件这个jar包是SpringBoot的Fat Jar内置了Tomcat容器可以直接用java -jar运行。生产环境我第一次部署时使用命令nohup java -jar repair-system.jar system.log 21 。nohup保证终端断开后进程继续运行标准输出和错误输出都重定向到system.log文件方便后续查看运行日志。这里要提醒几个细节jar包启动前确认application.yml中数据库连接地址是否已改为生产环境IP确认服务器JDK版本和打包时一致否则可能出现UnsupportedClassVersionError确认文件上传目录存在且Java进程有写入权限否则上传图片会报文件系统错误。如果服务器内存有限可以给JVM指定初始和最大堆内存例如-nXms256m -Xmx512m避免SpringBoot默认启动占用过大的内存拖垮整台服务器。在实际运维中有一个小建议是写一个start.sh脚本把启动命令和日志输出都固定下来以后每次重启只需要执行start.sh不需要重新敲一长串命令。5.2 前端构建与静态文件部署前端部署前执行npm run buildVite会将项目打包为dist目录下的纯静态文件包括HTML、JS、CSS和图片资源。将dist目录上传到服务器后我推荐使用Nginx托管静态文件并对/api路径做反向代理。Nginx配置的关键部分如下server { listen 80; server_name your-domain.com;root /data/repair-system/dist; index index.html; location / { try_files $uri $uri/ /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; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /upload/ { alias /data/repair-system/upload/; }}location /配置中的try_files是关键它解决了Vue Router history模式刷新页面404的问题。Vue单页应用的地址是前端路由控制的比如刷新/user/list时服务器上并没有这个真实文件try_files逻辑会先看$uri是否存在不存在就回退到index.html由Vue路由接管渲染。如果用的是hash模式则没有这个问题但URL中会有一个不太美观的#号。location /upload/配置将图片请求映射到磁盘目录这样学生提交的故障照片能通过http方式直接访问。如果漏掉这个配置图片路径在数据库里存了但浏览器加载不出来前端页面就会显示一堆裂图。5.3 部署环境下的配置差异化处理开发环境和生产环境的配置差异很大我的做法是使用多Profile配置。application.yml存放公共配置application-dev.yml和application-prod.yml分别存放不同环境的数据库连接、上传路径、日志级别。启动时通过--spring.profiles.activeprod参数指定使用生产配置开发时在IDEA中设置dev Profile。配置差异中需要重点关注的是日志级别和文件路径。开发环境日志级别设为DEBUG可以打出详细的SQL语句方便排错生产环境设为INFO避免日志量太大。上传路径开发环境设为项目目录下的upload文件夹生产环境设为/data/repair-system/upload。数据库连接也一样开发用本机的localhost生产用实际数据库服务器地址。5.4 云服务器部署的完整实操记录我在一台2核4G的云服务器上完整部署过一次这里把整个过程按顺序记录下来给第一次部署的同学一个完整参考。操作系统是CentOS 7.9先安装JDK 1.8和Nginx再安装MySQL 8.0然后上传jar包和dist目录修改Nginx配置最后启动服务。安装JDK时要注意CentOS自带的OpenJDK路径可能和预期不一致建议直接在Oracle官网下载JDK的tar.gz包解压到/usr/local/java目录后配置JAVA_HOME环境变量。MySQL安装完成后修改root密码、创建repair数据库、导入数据脚本。这里有一个经验是安装MySQL 8.0后必须把正确时区设置为系统时区在my.cnf中添加default-time-zone 08:00并在创建数据库时指定DEFAULT CHARACTER SET utf8mb4否则导入中文数据可能乱码。启动后端后通过curl http://localhost:8080/api/auth/login验证接口是否正常登录成功返回Token说明后端起服务成功。再访问服务器公网IP验证前端页面是否能打开、登录流程是否完整、上传图片是否能正常访问。如果前端页面能打开但接口请求失败优先查看Nginx的error.log和access.log确认代理配置有没有生效。6. 常见问题与排查技巧实录6.1 时间差8小时的经典问题这个是SpringBoot连接MySQL时最高频的问题之一。现象是前端页面上显示的时间比真实时间晚了8个小时。排查思路其实很清晰先确认MySQL中存的时间是否正确再确认后端日志中打印的时间是否正确最后确认前端接收到的时间是否正确。我在项目里遇到的原因是JDBC连接串没有配置时区参数MySQL默认使用系统时区本地系统是北京时间但JDBC以UTC时区解析导致相差8小时。解决办法有两个层面。第一数据库连接参数中加上serverTimezoneAsia/Shanghai第二在Jackson配置中设置时间格式化时区为Asia/Shanghai因为Java中Date类型序列化为JSON时也需要指定时区。两个配置都改掉后时间显示就正常了。6.2 前端刷新页面404的问题这个问题的现象是用户在系统内点击路由切换页面一切正常但一旦在某个子页面按F5刷新浏览器就报404。原因前文已经提到Vue Router的history模式依赖前端路由接管URL解析但Web服务器发现请求的路径没有对应文件就直接返回404。解决办法是Nginx配置中的try_files命令将请求回退到index.html。如果你用的是Tomcat部署前端静态资源则需要在Tomcat的web.xml中配置ErrorPage将404转发到index.html配置方式相对繁琐。因此我强烈建议前端静态文件统一交给Nginx托管不要扔进SpringBoot的static目录职责分离后部署更清晰也方便以后做CDN加速。6.3 文件上传超时或失败的问题文件上传失败通常有两类原因一是Nginx默认的client_max_body_size为1MB超过这个大小的请求会返回413错误。解决办法是在Nginx的http或server块中设置client_max_body_size 10m。二是后端SpringBoot默认的max-file-size为1MB需要在application.yml中配置spring.servlet.multipart.max-file-size和max-request-size。两个配置是独立的任何一个没有调大传大图片都可能失败。另外一个常见但不容易想到的问题是上传目录的写权限。以Nginx和Java进程运行的用户通常是nginx用户或系统普通用户必须有目标目录的写权限否则上传接口会抛出FileNotFoundException。我调试时遇到过一次最后用chmod -R 755给目录加了权限才解决。6.4 数据库连接池耗尽导致接口超时的排查当并发访问量较高且数据库慢查询较多时会出现接口响应越来越慢最终报连接池耗尽异常的情况。排查时先看数据库慢查询日志找耗时超过1秒的SQL语句再分析这些SQL的索引使用情况。本项目中最常见的慢查询是按时间范围查询工单时没有走索引因为create_time字段没有加索引。解决办法是给create_time字段加普通索引同时检查所有统计类SQL是否在where条件中使用了索引字段。另外一个容易被忽略的因素是连接池的初始大小和最大大小设置我在生产环境中把HikariCP连接池的maximum-pool-size从默认10调整为20把minimum-idle从默认10调整为5避免在低峰期也保持大量空闲连接占用数据库资源。6.5 权限校验失败或登录失效的问题登录后访问部分接口返回403通常是角色权限配置问题。检查的方式是先看数据库中用户角色字段的值再看后端权限表达式中写的角色名称确认两者一致且包含ROLE_前缀。如果使用的是自定义PermissionEvaluator还需要检查是否在Spring Security配置中正确注册。JWT登录失效的典型现象是系统用一段时间后操作跳回登录页。原因是Token有效期到了前端的Axios拦截器收到401后主动清除登录状态并跳转。解决办法是两种一种是延长Token有效期适合内部系统另一种是加入Token刷新机制前端在Token过期前通过刷新接口换取新的Token。因为是校园内部系统我采用了第一种方案把有效期设置为一周。如果你做的是面向大众的互联网产品建议使用滑动续期方案。写在最后的几点实操体会整个项目从需求梳理到最终部署我用了一个完整周期。走过全流程后的最大感受是这类管理系统的难点不在某个技术点而在前后端配合、状态设计、异常处理和部署排错这些细节上。很多同学做项目时重编码轻设计拿到需求就急着写代码结果中途频繁改表结构代码到处打补丁。如果能先花两天时间把角色、流程、状态、表单字段梳理清楚后面写代码的速度反而会快很多。关于报修系统本身如果后续想扩展可以考虑给维修工端做一个微信小程序版本维修工不需要下载App点开小程序就能收单和处理工单在校园场景下实际使用会更方便。后端接口已经按RESTful风格设计好小程序端完全可以直接复用现有接口。最后再分享一个部署层面的小技巧上线之前务必把生产环境的日志配置、数据库备份策略和启动脚本都准备到位不要图省事省略。系统可以没有多复杂的架构但不能没有日志和备份这是项目上线后能不能睡得着觉的关键。本文还有配套的精品资源点击获取