这类校园宿舍报修小程序,核心解决的是学生报修流程繁琐、信息不透明、维修进度难追踪的问题。如果你正在做毕业设计,或者想快速搭建一个能跑通、能演示、能写进简历的完整前后端项目,这个基于 SpringBoot3、Vue3 和微信小程序的组合,是一个相当务实的选择。它最大的价值在于,把“管理系统开发”这个宽泛的课题,落地到了一个有明确用户、有完整业务流程、技术栈也足够主流的真实场景里。
很多人一上来就纠结技术细节,比如 Vue3 的 Composition API 怎么用,SpringBoot3 的新特性是什么。我的建议是,先把项目骨架搭起来,让报修、受理、处理、评价这个核心流程能跑通。技术是为业务服务的,这个项目的业务逻辑清晰,正好适合用来练手和展示你的全栈能力。
下面,我会按照从零开始搭建一个可运行、可演示的毕设项目的顺序,把环境准备、前后端开发、联调测试和部署上线的关键环节拆解清楚。重点不是罗列所有代码,而是告诉你每个阶段要做什么、为什么这么做、以及最容易卡住的地方在哪里。
1. 先理清业务,再动手建库建表
做任何管理系统,最怕的就是一上来就敲代码。对于宿舍报修系统,你得先想清楚,有哪些角色,每个角色要干什么,数据怎么流转。
1.1 核心角色与业务流程
通常,这个系统至少包含三类用户:
- 学生:发起报修、查看进度、确认完成、进行评价。
- 维修工/管理员:查看报修单、接单、处理、填写维修结果。
- 系统管理员:管理用户、楼栋、宿舍信息,分配维修工,查看统计报表。
业务流程很简单,但必须闭环:
- 学生报修:选择楼栋、宿舍号,填写故障描述,可上传图片。
- 工单生成与分配:系统生成工单,可自动或由管理员分配给维修工。
- 维修处理:维修工接单,前往维修,完成后填写处理结果。
- 学生确认与评价:学生收到完成通知,确认维修结果,并评价。
- 工单完结:状态更新为“已完成”,数据进入统计。
这个流程决定了你数据库表的设计核心。
1.2 数据库表结构设计要点
不要追求大而全,先保证核心流程跑通。下面这几张表是骨架:
- 用户表 (
sys_user):区分学生、维修工、管理员。字段至少包括:ID、用户名、密码(加密)、角色、手机号、所属楼栋/宿舍(对学生和维修工重要)。 - 楼栋/宿舍表 (
dorm_building,dorm_room):管理物理位置。楼栋表存楼号、名称;宿舍表关联楼栋ID,存房间号。 - 报修工单表 (
repair_order):最核心的表。字段包括:order_id: 工单号(可规则生成,如BX20240520001)。student_id: 报修学生ID。room_id: 报修宿舍ID。fault_desc: 故障描述。fault_images: 图片URL(多个用逗号分隔,或另建表)。status: 状态(枚举:待受理、已受理/维修中、待确认、已完成、已取消)。handler_id: 维修工ID。handle_result: 维修结果描述。handle_images: 维修后图片。student_confirm: 学生是否确认(布尔值)。rating: 评分(1-5星)。comment: 评价内容。- 各种时间戳:
create_time,accept_time,finish_time,confirm_time。
- 通知表 (
sys_notice):用于系统公告或工单状态变更推送(小程序模板消息)。
为什么这么设计?
status字段是驱动整个流程的关键,前端所有列表筛选(如“我的报修”、“待处理工单”)和后端状态机流转都靠它。- 时间戳不仅用于记录,更是后期做“平均处理时长”等统计报表的数据基础。
- 图片字段存储URL,而不是二进制数据。这意味着你需要一个文件存储服务。对于毕设,我强烈建议使用本地存储或集成像MinIO这样的开源对象存储,它兼容S3协议,部署简单,比直接存数据库或服务器本地目录更规范,也更容易扩展到云存储。
-- 以报修工单表为例的简化建表语句 CREATE TABLE `repair_order` ( `id` bigint NOT NULL AUTO_INCREMENT, `order_no` varchar(32) NOT NULL COMMENT '工单编号', `student_id` bigint NOT NULL COMMENT '报修学生ID', `room_id` bigint NOT NULL COMMENT '宿舍ID', `title` varchar(255) DEFAULT NULL COMMENT '报修标题', `fault_desc` text COMMENT '故障描述', `fault_images` text COMMENT '故障图片URL,逗号分隔', `status` tinyint NOT NULL DEFAULT '0' COMMENT '状态:0待受理 1已受理 2维修中 3待确认 4已完成 5已取消', `handler_id` bigint DEFAULT NULL COMMENT '维修工ID', `handle_result` text COMMENT '维修结果', `handle_images` text COMMENT '维修后图片URL', `student_confirm` bit(1) DEFAULT b'0' COMMENT '学生是否确认', `rating` tinyint DEFAULT NULL COMMENT '评分1-5', `comment` varchar(500) DEFAULT NULL COMMENT '评价', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `accept_time` datetime DEFAULT NULL, `finish_time` datetime DEFAULT NULL, `confirm_time` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uniq_order_no` (`order_no`), KEY `idx_student_id` (`student_id`), KEY `idx_handler_id` (`handler_id`), KEY `idx_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报修工单表';2. 搭建后端:SpringBoot3 + MyBatis-Plus + 权限控制
后端是业务逻辑的核心。用SpringBoot3可以快速搭建RESTful API。这里的关键是分层清晰和统一响应。
2.1 项目初始化与依赖选择
使用 Spring Initializr 或 IDEA 创建项目,选择:
- Spring Boot 3.x(如 3.2.5)
- Java 17(SpringBoot3 要求至少 Java 17)
- 依赖:
Spring Web,MyBatis Framework,MySQL Driver,Lombok。
然后,在pom.xml中手动加入这些对开发效率提升巨大的依赖:
mybatis-plus-boot-starter:简化CRUD。hutool-all:工具类库,处理日期、加密、HTTP请求等。jjwt-api,jjwt-impl,jjwt-jackson:用于JWT令牌生成与验证。knife4j-openapi3-jakarta-spring-boot-starter:生成API文档(替代以前的Swagger)。commons-lang3:字符串等工具。
为什么用MyBatis-Plus?因为它能让你避免写大量简单SQL,专注复杂业务。比如,工单的分页条件查询,用它的QueryWrapper可以几行代码搞定。
2.2 核心配置与包结构
保持清晰的包结构:
src/main/java/com/yourdomain/dormrepair/ ├── config/ // 配置类(WebMvc, MybatisPlus, 跨域, 安全) ├── controller/ // 控制器,接收请求,调用Service ├── service/ // 服务接口 │ └── impl/ // 服务实现 ├── mapper/ // MyBatis Mapper接口 ├── entity/ // 实体类,对应数据库表 ├── dto/ // 数据传输对象(用于API入参出参) ├── vo/ // 视图对象(用于返回给前端的数据封装) ├── common/ // 通用类(常量,枚举,统一响应,工具类) └── DormRepairApplication.java关键配置:
application.yml中配置数据库连接、MyBatis-Plus(开启驼峰映射、逻辑删除等)。- 配置跨域(CORS),允许微信小程序的前端域名访问。
- 配置JWT密钥和过期时间。
- 配置静态资源路径(如果你打算后端直接提供上传文件的访问)。
2.3 实现核心业务接口
围绕RepairOrder实体,你需要实现以下主要接口:
- 学生端:
POST /api/repair/order:提交报修单(需处理图片上传)。GET /api/repair/order/my:分页查询我的报修单。GET /api/repair/order/{id}:查看报修单详情。PUT /api/repair/order/{id}/confirm:确认维修完成。POST /api/repair/order/{id}/rate:评价。
- 维修工/管理员端:
GET /api/repair/order/list:分页查询所有工单(可按状态筛选)。PUT /api/repair/order/{id}/accept:接单(将状态从“待受理”改为“已受理”)。PUT /api/repair/order/{id}/finish:完成维修(填写结果,状态改为“待确认”)。
- 公共:
POST /api/upload:统一的文件上传接口。GET /api/dorm/rooms:根据楼栋获取宿舍列表(用于报修时选择)。
图片上传接口的实现要点:
@PostMapping("/upload") public Result<String> uploadFile(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return Result.fail("文件不能为空"); } // 1. 生成唯一文件名(防止覆盖) String originalFilename = file.getOriginalFilename(); String fileExt = FilenameUtils.getExtension(originalFilename); String newFileName = IdUtil.fastSimpleUUID() + "." + fileExt; // 2. 确定存储路径(例如:/upload/2024/05/20/) String today = DateUtil.today().replace("-", "/"); String relativePath = "upload/" + today + "/" + newFileName; File destFile = new File(uploadBasePath, relativePath); // uploadBasePath 是配置的根目录 // 3. 确保目录存在 if (!destFile.getParentFile().exists()) { destFile.getParentFile().mkdirs(); } // 4. 保存文件 try { file.transferTo(destFile); // 5. 返回访问URL(例如:/upload/2024/05/20/xxx.jpg) return Result.success("/" + relativePath); } catch (IOException e) { log.error("文件上传失败", e); return Result.fail("上传失败"); } }注意:在生产环境或想更规范,应该用MinIO。将上面的本地保存逻辑,替换为 MinIO 客户端的putObject调用,返回的则是 MinIO 的访问地址。
2.4 权限控制与JWT
小程序登录后,后端会得到一个code,用它向微信服务器换openid和session_key。这个openid就是用户的唯一标识。
- 用户首次登录,用
code换openid。 - 根据
openid查询用户表,不存在则自动注册(插入一条学生记录)。 - 生成JWT令牌(Payload里可包含userId, role),返回给小程序。
- 小程序后续请求,在
header的Authorization字段携带Bearer {token}。 - 后端通过一个
JwtAuthFilter拦截请求,验证token,并将用户信息存入SecurityContext或ThreadLocal。 - 在Controller方法上使用自定义注解如
@RequiresRoles("student")或@RequiresLogin进行权限校验。
为什么用JWT而不是Session?因为RESTful API是无状态的,JWT更适合。小程序将token存在本地storage,每次请求带上即可。
3. 开发前端:Vue3 + Vite + 微信小程序
前端分为两部分:微信小程序(学生/维修工使用)和Web管理后台(管理员使用)。两者可以共享后端API。
3.1 微信小程序端开发要点
小程序端主要给学生和维修工使用。
技术选型:原生小程序开发或使用
uni-app。对于毕设,原生开发足够,也更直接。使用微信开发者工具。登录流程:
// pages/login/login.js wx.login({ success: (res) => { if (res.code) { // 将code发送到自己的后端 wx.request({ url: 'https://your-api.com/api/auth/login', method: 'POST', data: { code: res.code }, success: (resp) => { // 后端返回token和用户信息 wx.setStorageSync('token', resp.data.token); wx.setStorageSync('userInfo', resp.data.userInfo); wx.switchTab({ url: '/pages/index/index' }); } }) } } })请求封装:封装
wx.request,统一添加AuthorizationHeader,处理401跳转登录。const request = (options) => { const token = wx.getStorageSync('token'); if (token) { options.header = { ...options.header, 'Authorization': `Bearer ${token}` }; } return new Promise((resolve, reject) => { wx.request({ ...options, success: (res) => { if (res.statusCode === 200) { resolve(res.data); } else if (res.statusCode === 401) { // token失效,清除并跳转到登录页 wx.removeStorageSync('token'); wx.redirectTo({ url: '/pages/login/login' }); reject(new Error('未授权')); } else { reject(new Error(res.data.message || '请求失败')); } }, fail: reject }); }); };主要页面:
- 首页:展示公告、快捷报修入口、我的报修状态概览。
- 报修页:表单页面,选择楼栋宿舍(联动选择器)、填写描述、上传图片(使用
wx.chooseImage和wx.uploadFile)。 - 我的报修列表页:上拉加载更多,按状态筛选。
- 报修详情页:展示详细信息、进度时间线、操作按钮(确认、评价)。
- 维修工主页:待处理工单列表、进行中工单列表。
- 工单处理页:维修工填写处理结果、上传维修后照片。
图片上传:小程序端用
wx.uploadFile,注意一次只能上传一个文件,需要循环处理多个文件。地图功能:如果需求有“报修时定位”,可使用微信小程序的
wx.getLocation获取坐标,或集成高德/腾讯地图的小程序SDK展示位置。注意:获取用户位置需要权限声明。
3.2 Vue3管理后台开发要点
管理后台给系统管理员使用,功能更复杂,适合用Vue3 + Element Plus。
项目初始化:使用
Vite创建项目,更快更轻量。npm create vite@latest dorm-repair-admin -- --template vue cd dorm-repair-admin npm install npm install element-plus axios pinia vue-router状态管理:使用
Pinia管理用户状态、全局配置。比Vuex更简单。路由与权限:定义路由表,在路由守卫里根据用户角色判断是否能访问某些页面(如
/admin开头的页面需要管理员角色)。API封装:使用
axios拦截器统一添加token、处理错误。核心页面:
- 登录页:管理员账号密码登录。
- 仪表盘:展示统计卡片(今日报修数、完成率、平均处理时长)、图表(ECharts)。
- 工单管理:表格展示,支持多条件筛选(状态、楼栋、时间)、分页、批量操作(分配维修工)。
- 用户管理:对学生、维修工、管理员进行CRUD。
- 楼栋宿舍管理:树形或列表管理。
- 系统公告管理:发布公告,小程序端可拉取显示。
使用JSX/TSX?对于毕设,用SFC(单文件组件)足够了。除非你特别熟悉React风格,否则不必强求JSX。
富文本编辑器:如果公告需要富文本,可以使用
@wangeditor/editor,它兼容Vue3,比较简单。
4. 前后端联调、测试与部署
这是从“能跑”到“能演示”的关键一步。
4.1 联调环境准备
- 后端:在
application.yml中设置spring.profiles.active=dev,配置开发环境数据库。使用Knife4j访问/doc.html查看和调试接口。 - 前端(管理后台):在
vite.config.js中配置代理,解决跨域。export default defineConfig({ // ... server: { proxy: { '/api': { target: 'http://localhost:8080', // 后端地址 changeOrigin: true, } } } }) - 小程序端:在微信开发者工具中,设置不校验合法域名(开发阶段),或将后端地址添加到小程序后台的
request合法域名中(需要HTTPS)。
4.2 联调核心流程
- 用户登录:调通小程序登录,获取token。
- 报修流程:
- 小程序:选择宿舍 -> 填写信息 -> 上传图片 -> 提交。
- 后端:接收数据,创建工单,状态为“待受理”。
- 管理后台:管理员登录,在工单列表看到新工单,点击“分配”给维修工。
- 后端:更新工单状态为“已受理”,
handler_id更新。 - 维修工小程序:在“待处理”列表看到工单,点击“接单”或“开始处理”。
- 后端:状态可改为“维修中”。维修工完成后,填写结果,上传图片,点击“完成”。
- 后端:状态改为“待确认”。
- 学生小程序:收到通知(或主动刷新),在“待确认”列表看到工单,点击“确认完成”。
- 后端:状态改为“已完成”。学生随后可评价。
- 重点测试:
- 图片上传与回显(路径是否正确)。
- 工单状态流转是否严谨(比如,学生不能确认一个“待受理”的工单)。
- 列表分页、筛选是否正常。
- 不同角色权限控制(学生不能访问管理后台接口)。
4.3 部署上线(用于演示)
毕设答辩需要演示,因此需要将项目部署到公网。
- 后端部署:
- 购买一台云服务器(学生有优惠)。
- 安装JDK17、MySQL、Nginx。
- 将SpringBoot项目打成Jar包:
mvn clean package。 - 上传Jar包到服务器,使用
nohup java -jar your-app.jar &运行。 - 使用Nginx反向代理到
http://localhost:8080,并配置SSL证书(HTTPS是微信小程序的要求)。
- 前端管理后台部署:
- 执行
npm run build生成dist静态文件。 - 将
dist目录上传到服务器,用Nginx配置一个静态站点即可。
- 执行
- 小程序部署:
- 在微信公众平台配置后端API的HTTPS域名。
- 提交代码审核(审核通过后才能发布线上版,但开发版和体验版可供答辩老师扫码体验)。
- 数据库:将本地数据库导出为SQL,在服务器上导入。注意修改生产环境的数据库连接配置。
4.4 常见问题与排查
- 小程序真机预览报错“不在以下 request 合法域名列表中”:检查后端域名是否已配置到小程序后台,并且是HTTPS。开发阶段可先在开发者工具设置里勾选“不校验合法域名”。
- 图片上传后无法访问:检查Nginx配置,是否将
/upload路径映射到了后端服务或文件存储的实际目录。如果是MinIO,检查桶策略是否为公开或已正确配置访问密钥。 - 后端接口返回404或500:先看后端控制台日志。常见原因:
@RequestMapping路径写错;数据库连接失败;MyBatis映射文件找不到。 - 跨域问题:确保后端已正确配置CORS,允许小程序和后台管理站的域名。Nginx反向代理也可能需要添加CORS头。
- JWT令牌失效:检查令牌生成和验证的密钥是否一致;检查令牌是否过期;检查前端请求头格式是否正确(
Bearer token)。 - 管理后台页面空白或JS/CSS加载失败:检查Nginx配置的
root是否正确指向dist目录;检查Vite build后资源路径是否正确(base配置)。
这个项目麻雀虽小,五脏俱全。做完它,你不仅能展示SpringBoot、Vue3、小程序这些技术点的使用,更能体现你对一个完整业务系统的设计、开发和部署能力。从建表到接口,从前端到部署,每一步都有明确的产出物,这正是毕业设计最看重的“系统性”。