☰
微信小程序+SpringBoot+MySQL:宿舍报修系统开发全解析
2026/10/10 1:07:01 网站建设 项目流程

简介:一套面向毕业设计场景的宿舍报修系统小程序完整项目方案,包含微信小程序端、SpringBoot后端与MySQL数据库脚本,适合计算机相关专业学生用于毕设参考或前后端开发练习。压缩包共744个文件,大小43.59MB,文件构成覆盖开发全链路:161个svg与125个png提供界面素材,128个vue及22个wxml、23个wxss构建前端页面,101个java处理后端业务,66个js、30个json承担交互与配置,sql为数据库初始化脚本,另有mp4视频教程与论文相关材料。包内还附有1-install.bat、2-run.bat、3-build.bat一键脚本,便于快速安装启动。该项目针对宿舍报修管理中信息混乱、效率低等问题,集中管理报修工单、处理状态与反馈记录,可帮助理解小程序与SpringBoot前后端分离架构及MySQL表设计。目前已有262人学习下载,从零搭建毕设项目可直接使用完整源码与配套论文视频。

1. 宿舍报修系统小程序:一个毕设标题背后的完整技术链路

“宿舍报修系统小程序”这句标题,在毕业设计选题里出现频率相当高。你大概率见过宿舍楼管阿姨手里那个写满「灯管坏」「下水道堵」的登记本:问题记录得潦草,维修进度全靠催,学生不知道有没有人管,维修工跑空趟更是家常便饭。这个题目要做的,就是把这条手工链路搬到微信里:学生小程序提交报修单,管理员后台分配维修工,维修工上门处理完更新状态,学生确认并评价。标题里“微信小程序 + SpringBoot + MySQL”三个词,恰好就是当下最主流的“前后端分离”入门组合,代码量适中、论文结构清晰、答辩演示直观,所以它成了毕设常青树。这篇文章我按自己实际带项目的路线来讲,先把三层架构各管什么事说清楚,再一步步把工程跑起来,随后落到报修、上传、通知这些核心流程,最后把容易翻车的坑点挨个点名。

2. 三层结构拆解:小程序、SpringBoot、MySQL 各自的责任边界

很多同学拿到源码后第一件事就是打开微信开发者工具点了“编译”,看到报错后又去启动后端,两头折腾半天才跑起来,原因就是没先分清这三层分别解决什么问题。这一章先做静态拆解,把项目看成一栋房子的图纸再进门。

2.1 微信小程序端:页面、组件与 request 封装

小程序端本质上是一个“前台收银台”,负责展示数据和采集用户操作,几乎不应该放业务规则。我见过有同学把状态判断写死在页面里,比如判断报修单状态时直接比较数字“0、1、2”,结果后端状态意义一调整,前端逻辑全部作废。这里的原则是:小程序只做三件事——渲染、录入、转发。

页面结构一般是:首页放报修入口 + 公告轮播,报修提交页选择分类、填描述、传图片,报修列表页分页展示自己的工单,详情页看处理进度和维修工留言,个人中心管资料和登录状态。如果你拿到的源码里没有用组件化写法,我建议保留它原本的风格,毕设阶段不必强行重构。

所有请求走一个统一封装,这是第一个值得留意的代码点:

// utils/request.js const BASE_URL = 'http://localhost:8080/api'; // 本地联调地址,真机预览要换成电脑局域网 IP function request(url, method, data, needAuth = true) { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + url, method: method || 'GET', data: data || {}, header: needAuth ? { 'Authorization': wx.getStorageSync('token') || '' } : {}, success(res) { if (res.data.code === 200) { resolve(res.data.data); } else { reject(res.data); } }, fail(err) { reject(err); } }); }); } module.exports = { request, BASE_URL };

逻辑说明:wx.request原本是基于回调的写法,包成 Promise 之后页面里就能用async/await写同步风格,代码干净得多。Authorization头是登录后存储在本地的 token,后端靠它识别当前用户。

参数说明:BASE_URL是整个项目最容易改错的地方。本地联调用localhost没问题,但手机真机调试时,手机访问localhost会找到自己而不是电脑,必须改成电脑的局域网 IP,比如http://192.168.1.100:8080/api。这个问题后面避坑章节还会再点一次名。

2.2 SpringBoot 后端:分层、依赖与配置

后端按习惯拆成 Controller(接请求)、Service(写业务)、Mapper(操作 MySQL)三层。实体类用 JavaBean 配合 MyBatis-Plus,能省掉大量手写 SQL 的重复劳动。这里先给出一组最稳妥的依赖选择:

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> </dependencies>

逻辑说明:spring-boot-starter-web内置 Tomcat 和 Spring MVC;MyBatis-Plus 把单表 CRUD 简化成直接调用现成方法,不必手写XXXMapper.xml;Lombok 用注解批量生成 getter/setter;validation 依赖负责参数校验。这套组合是当前毕设里最不容易出错的配置。

选型理由:为什么推荐 MyBatis-Plus 而不是原生 MyBatis?时间有限,重点应放在报修业务的流转上,而不是花大量时间写基本的增删改查 SQL。MyBatis-Plus 的save()、selectById()等内置方法足够覆盖绝大多数场景,等答辩时老师问起底层原理,能答出“它在 MyBatis 上加了通用 Mapper 实现”就已经合格了。

2.3 MySQL 端:表结构设计与报修单状态机

看一个毕设源码,先看数据库脚本,往往就能判断出这个项目作者的工程能力。宿舍报修系统核心表大致是这几张:

表名核心字段设计意图
studentid, student_no, name, phone, dorm_building, dorm_room, openid学生档案,openid 关联小程序身份
repair_orderid, order_no, student_id, category, description, images, status, priority, repair_man_id, repair_man_remark, create_time, update_time, finish_time报修主流程
repair_manid, name, phone, skill_type, status维修工信息
admin_userid, username, password, role管理员账号,密码需要做加密
noticeid, title, content, create_time宿舍公告

报修单的status字段是整个系统的灵魂,常见状态机是:0 待受理 → 1 维修中 → 2 已完成 → 3 已评价,或者用户在待受理时主动取消变成 -1。为什么要单独设计order_no而不是直接用自增主键?因为自增 id 容易被外部遍历到,你传一个 id 到接口就能看到别人的工单,这属于接口越权问题。用随机单号再加一层权限校验,答辩时能加分不少。

3. 把工程跑起来:导入数据库、启动后端、联调小程序

拿到源码压缩包以后,我习惯按“数据库 → 后端 → 前端”的顺序启动,每一步都能独立验证成功再走下一步,最大程度避免“两头都在跑但谁也没通”的茫然状态。

3.1 导入数据库脚本

数据库脚本一般在sql/目录下。用 Navicat 或命令行导入都可以,我常用命令行:

mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS dorm_repair DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" mysql -u root -p dorm_repair < dorm_repair.sql

逻辑说明:第一条命令创建数据库,指定utf8mb4是因为它完整支持中文和特殊符号,避免学生提描述里带个表情符号就报错;第二条命令把整个脚本执行进去,脚本里通常包含建表语句和测试数据。

参数说明:一定注意utf8mb4与utf8的区别——如果原工程是用老版本 MySQL 生成的,可能写成utf8,本地用utf8mb4也兼容,反过来则可能报“字段长度超限”之类的畸形错误。导入时如果报错,往脚本头几行找原因,多半是“数据库已存在”或“表已存在”,删掉重建即可。

3.2 配置 application.yml 并启动后端

导入成功后再看后端配置:

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/dorm_repair?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB max-request-size: 20MB mybatis-plus: global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 configuration: map-underscore-to-camel-case: true

逻辑说明:数据源地址里serverTimezone=Asia/Shanghai必须保留,否则LocalDateTime与数据库交互可能出现时间差 8 小时的问题;MyBatis-Plus 逻辑删除配置能在开发期避免误删数据;驼峰映射开启后,数据库下划线字段自动对应实体类驼峰属性。

启动方式两种:IDEA 里直接运行带@SpringBootApplication注解的主类,或者命令行执行mvn spring-boot:run。看到 “Started” 日志说明后端启动成功,此时浏览器访问http://localhost:8080/api/health这类接口能返回 JSON,就证明 Spring 容器正常起来了。

3.3 小程序端改地址与首屏接口联调

后端起来后,把小程序端request.js的BASE_URL改成http://localhost:8080/api。在微信开发者工具里勾选“不校验合法域名”再编译,首页或者登录页能出现数据,项目就算整体跑通了。此时如果首页白屏,先打开调试器的 Network 面板看有没有请求、后端日志有没有报错——这是最有效的排查路径。

4. 核心流程落地:报修提交、图片上传与非功能设计

工程跑通只是开始。这一章把宿舍报修系统最核心的业务链路逐段实现,你要能对着代码讲清每一段的意义,答辩的底气就在这。

4.1 报修提交:后端接收与参数校验

先写后端接收端:

@RestController @RequestMapping("/api/repair") public class RepairController { @PostMapping("/submit") public R submit(@RequestBody @Valid RepairSubmitDTO dto, @RequestAttribute("userId") Integer userId) { RepairOrder order = new RepairOrder(); BeanUtils.copyProperties(dto, order); order.setStudentId(userId); order.setStatus(0); // 0 表示待受理 order.setOrderNo("R" + System.currentTimeMillis() + (int)(Math.random() * 900 + 100)); order.setCreateTime(LocalDateTime.now()); repairOrderService.save(order); return R.ok(order.getId()); } }

逻辑说明:前端传来的 DTO 只包含分类、描述、图片等表单数据,学生身份从 token 中解析出来放进userId,这样能防止用户伪造studentId。orderNo用时间戳加随机数生成,避免连续订单被遍历。status强制设为 0,保证新工单一定从初始状态开始。

参数说明:@Valid触发 DTO 里的校验注解,比如@NotBlank(message = "报修描述不能为空")、@Pattern校验电话格式。校验不通过时会自动抛出异常,配合全局异常处理器返回统一的错误 JSON,避免栈信息直接暴露给前端。

4.2 报修列表与状态流转

@GetMapping("/my") public R myRepairs(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size, @RequestAttribute("userId") Integer userId) { IPage<RepairOrder> pager = new Page<>(page, size); LambdaQueryWrapper<RepairOrder> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(RepairOrder::getStudentId, userId) .orderByDesc(RepairOrder::getCreateTime); repairOrderService.page(pager, wrapper); return R.ok(pager); }

逻辑说明:MyBatis-Plus 的Page对象配合page()方法直接返回分页结果,不再手写LIMIT offset, size。用orderByDesc按创建时间倒序,是新工单排在前面,方便学生看最新处理进度。这接口的userId同样来自后端解析的 token,而不是前端传来的参数。

状态流转的核心是后端统一控制:管理员接单时把status改成 1 并分配repairManId;维修工完成时改成 2 并记录finishTime;学生评价后改成 3。不要把这些写在小程序端,否则换一个入口或做后台管理页面时要改两处。

4.3 图片上传前后端完整链路

宿舍报修的痛点产物是“说不清楚坏哪儿了”,所以图片上传是刚需。后端实现:

@PostMapping("/upload") public R upload(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { throw new BizException("文件不能为空"); } String originalName = file.getOriginalFilename(); String ext = originalName.substring(originalName.lastIndexOf(".")).toLowerCase(); if (!Arrays.asList(".jpg", ".jpeg", ".png").contains(ext)) { throw new BizException("仅支持 jpg、png 格式图片"); } if (file.getSize() > 5 * 1024 * 1024) { throw new BizException("图片大小不能超过 5MB"); } String fileName = UUID.randomUUID().toString().replace("-", "") + ext; Path dest = Paths.get(System.getProperty("user.dir") + "/uploads", fileName); file.transferTo(dest); return R.ok("http://localhost:8080/uploads/" + fileName); }

逻辑说明:先做空值、格式、大小三重校验,再生成 UUID 文件名,避免中文文件名或重名导致覆盖。文件写到当前目录下的uploads文件夹,返回完整可访问的 URL。

坑点在于 SpringBoot 默认不认识这个uploads路径,直接返回的 URL 会 404。需要加一个配置类:

@Configuration public class WebConfig implements WebMvcConfigurer { @Value("${file.upload-dir:uploads}") private String uploadDir; @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/uploads/**") .addResourceLocations("file:" + System.getProperty("user.dir") + "/" + uploadDir + "/"); } }

逻辑说明:这段代码把/uploads/**的 URL 请求映射到本地磁盘目录,这样图片 URL 才能被浏览器访问。很多人上传成功却显示裂图,就是漏了这一步。

小程序端的传图代码:

function uploadImage(filePath) { return new Promise((resolve, reject) => { wx.uploadFile({ url: BASE_URL + '/repair/upload', filePath: filePath, name: 'file', header: { 'Authorization': wx.getStorageSync('token') || '' }, success(res) { const data = JSON.parse(res.data); if (data.code === 200) resolve(data.data); else reject(data); }, fail: reject }); }); }

逻辑说明:wx.uploadFile是微信专门用于文件上传的接口,不能用wx.request代替。name必须与后端@RequestParam("file")的参数名一致,这是前后端约好的“暗号”。

4.4 微信订阅消息与学生通知

维修工接单后如何通知学生?常见做法是微信订阅消息。学生提交报修时弹窗请求授权,授权一次换来一次发送机会。

// 伪代码:发送订阅消息 String accessToken = getAccessToken(); JSONObject body = new JSONObject(); body.put("touser", student.getOpenid()); body.put("template_id", "你的模板ID"); body.put("page", "pages/detail/detail?id=" + orderId); body.put("data", JSON.parse("[{\"key\":\"thing1\",\"value\":\"维修工已接单\"}]")); String result = HttpClientUtil.post( "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken, body.toString());

逻辑说明:access_token需要在后端用appid + secret调用微信接口获取,并且必须缓存起来,因为接口每天有调用次数限制。订阅消息的模板 ID 在小程序后台申请,每个模板对应固定的字段类型,thing1这类 key 是模板自带的。

实际做毕设时,这一步可以简化成“状态更新后学生在小程序内刷新看到进度”,毕竟订阅消息还需要申请小程序类目。但如果源码里带了完整的订阅消息实现,答辩时提一句“用微信订阅消息主动触达学生”会很加分。

5. 避坑清单:真机预览、图片 404、时区与登录态的四个高频问题

这个标题的源码我帮人调试过不少次,遇到的问题高度集中在这四个地方。按“现象 → 原因 → 解决”的顺序列出来,每一条都是血泪经验。

5.1 真机预览连不上后端

现象:模拟器一切正常,手机预览时首页转圈几秒后提示“网络异常”。

原因:手机上的localhost指向手机自己,不是开发电脑;而且小程序正式环境要求域名备案并配置 HTTPS,本地开发默认没有这些。

解决:开发阶段把BASE_URL改成电脑的局域网 IP 地址,比如http://192.168.1.100:8080/api,同时要保证手机和电脑连在同一个 WiFi。在“微信开发者工具 → 详情 → 本地设置”里勾选“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”,这样真机才允许往非 HTTPS 地址发请求。上线前必须换正式域名并申请 SSL 证书,否则无法过审核。

5.2 图片上传成功但页面显示 404

现象:后端日志显示文件已保存,数据库里也存了/uploads/xxx.jpg,打开图片 URL 却显示 404。

原因:SpringBoot 默认的静态资源路径只有classpath:/static/等,你上传到本地磁盘的uploads目录没有被映射成可访问的 URL。文件虽然写入了硬盘,但 HTTP 找不到它。

解决:在项目里加一个WebMvcConfigurer,用addResourceHandlers把/uploads/**映射到本地路径。具体代码就是 4.3 节给出的那段配置。做完之后重启后端,图片就能正常访问了,这是最容易漏的一步。

5.3 时间查询相差 8 小时

现象:数据库里存的时间是早上 8 点,程序读出来却显示当天零点。

原因:JDBC 连接串没有设置时区,MySQL 驱动默认用服务器本地时区,和 Java 的Asia/Shanghai对不上,导致读写之间差 8 小时。

解决:在数据源连接串末尾加上serverTimezone=Asia/Shanghai,再把 MySQL 的系统时区也设置为东八区。连接串改完重启后端即可。这一步同时也是保证LocalDateTime字段能正常存取的前提。

5.4 微信登录 code 二次使用报错

现象:小程序页面多次点击登录按钮,后端偶尔报invalid code,错误码 40029。

原因:微信的wx.login拿到的code是一次性的,换到openid之后再用同一个 code 去调微信接口就会失效。如果前端每次进页面都重新登录,后端就可能拿着旧 code 去换 openid,自然失败。

解决:小程序端登录成功后把后端返回的 token 存进wx.setStorageSync,后续所有请求只带 token;后端拦截器解析 token,解析成功后直接放行,不再重复调用微信接口。只有 token 过期或不存在时才走登录流程。这样既解决了 code 复用问题,也减少了对微信接口的无效调用。

6. 从能跑到能答辩:自测清单和生产化改造思路

很多人把毕设停在“能跑就行”,但答辩现场最容易暴露问题的恰恰是“没按真实流程走一遍”。我最后给一份带验证点的清单,帮你在上线演示前自查。

先做功能通路验收:用两个不同角色各注册一个账号,学生账号提交一张带图片的报修单,管理员账号看到待受理列表并接单,维修工账号更新状态为已完成,再用学生账号确认并评价。这条主链路能走通,系统最核心的演示就成功了。再做对抗性检查:提交空描述、传一个.exe文件、修改前端请求里的studentId,看后端是否都被拦截——这几点老师在答辩时非常喜欢现场试。

生产化改造层面,最少做三件事。第一件是改多环境配置:

# application-prod.yml server: port: 8080 spring: datasource: url: jdbc:mysql://你的云数据库地址:3306/dorm_repair?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: your_username password: your_password

逻辑说明:本地用application-dev.yml,部署到服务器时用--spring.profiles.active=prod切换,避免把本地密码误带到生产环境。第二件是引入 Nginx 做反向代理:Nginx 监听 443 端口,配置 HTTPS 证书后把/api/转发到后端的http://127.0.0.1:8080,同时拦截/uploads/做静态文件缓存,访问速度会明显提升。第三件事是给数据库做定期备份,写个简单的 Shell 脚本每天凌晨用mysqldump导出,压缩后保留最近 7 天。这三项做完,演示时即使老师问到部署运维,也能从容接住。

我自己的习惯是,每次拿到这类项目先在十分钟内跑通,再用半小时走一遍完整报修链路,最后才是看代码细节。这套流程走下来,再冷门的坑也有底气排查。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询