☰
SSM+微信小程序设备报修系统:从毕设跑通到二次开发全指南
2026/10/7 12:49:55 网站建设 项目流程

简介:本资源是一套基于SSM框架与微信小程序的设备故障报修管理系统毕业设计完整项目,面向计算机相关专业需要完成毕业设计或课程设计的学生。项目已通过导师指导与答辩评审,获得97分高分评价,在Windows 10/11环境下严格调试,下载后可直接运行部署。压缩包共包含1216个文件,整体约46.16MB,涵盖Java后端源码、微信小程序端页面与逻辑、SQL数据库脚本、Vue前端组件、PNG与JPG界面截图、MP4演示视频以及论文文档和使用说明,前后端与小程序三端结构完整。资源中附有论文、部署教程与演示录屏,可帮助读者快速理解设备报修流程、权限管理与工单状态流转等核心模块,也便于对照源码梳理系统架构与数据库表设计。目前已有184人学习关注,适合作为毕业设计参考或课程设计模板使用。

1. 从一份毕设压缩包说起:SSM+微信小程序的设备报修系统到底能跑出什么

实验室的离心机坏了三天没人管,维修师傅说没收到单子,管理员说不知道谁在用——这种扯皮在高校和中小企业里太常见了。设备故障报修管理系统要解决的就是这件事:让报修、派单、维修、验收四个环节全部线上留痕。这套基于 SSM 加微信小程序的方案,后端用 Spring+SpringMVC+MyBatis 扛业务逻辑,前端用微信小程序做用户入口,扫码就能报修,不用装 App。它适合正在找 Java 毕业设计选题的本科生,也适合想用一套完整项目练手 SSM 全栈开发的人。你拿到的是一个压缩包,里面有源码、数据库脚本、论文、使用文档和演示视频,但怎么把它跑起来、改出自己需要的样子,才是真正要花时间的地方。

2. 把压缩包拆开看:SSM 后端和微信小程序前端怎么分工

2.1 为什么是 SSM 而不是 Spring Boot

这套项目选 SSM 而不是 Spring Boot,原因很直接:毕业设计答辩时老师要看你对 Spring 配置的理解,XML 配置虽然啰嗦,但能体现你清楚每个 Bean 是怎么装配的。Spring 负责 IoC 容器和事务管理,SpringMVC 处理 HTTP 请求映射和参数绑定,MyBatis 做 SQL 映射和结果集封装。三层各管一摊,出了问题排查路径清晰——接口 404 找 SpringMVC 的映射,SQL 报错找 MyBatis 的 Mapper 文件,事务不回滚找 Spring 的 AOP 配置。

微信小程序端负责用户交互,主要页面包括:报修提交页、我的报修列表、报修详情页、维修工接单页、管理员统计页。小程序通过 wx.request 调用后端 REST 接口,数据格式统一用 JSON。后端返回结构一般是{code: 200, msg: "success", data: {...}},前端根据 code 判断请求是否成功。

2.2 数据库表结构和核心字段

数据库通常包含五张核心表,建表时注意字符集用 utf8mb4,否则小程序端提交的中文备注可能乱码。

表名用途关键字段
user用户信息id, openid, name, phone, role
device设备台账id, device_no, device_name, location, status
repair_order报修工单id, device_id, user_id, fault_desc, status, create_time
repair_record维修记录id, order_id, repairer_id, result, finish_time
notice通知公告id, title, content, create_time

role 字段区分三种角色:0 普通用户、1 维修工、2 管理员。status 字段控制工单流转:0 待接单、1 维修中、2 已完成、3 已取消。这两个字段的设计直接决定了后面所有业务逻辑的走向,改需求时优先看它们。

2.3 后端接口分层与请求流转

一个典型的报修提交请求,从微信小程序发出到数据库落库,经过这些环节:

// RepairOrderController.java @RestController @RequestMapping("/api/repair") public class RepairOrderController { @Autowired private RepairOrderService repairOrderService; @PostMapping("/submit") public Result submit(@RequestBody RepairOrderDTO dto) { // 参数校验:设备编号和故障描述不能为空 if (StringUtils.isEmpty(dto.getDeviceNo()) || StringUtils.isEmpty(dto.getFaultDesc())) { return Result.error("设备编号和故障描述不能为空"); } // 调用 Service 层,内部会查设备是否存在、写入工单 return repairOrderService.createOrder(dto); } }

Controller 只做参数校验和路由转发,业务逻辑放在 Service 层。Service 里先根据 device_no 查设备表确认设备存在,再插入 repair_order 记录,同时往 notice 表写一条通知给管理员。这三步操作加@Transactional注解保证原子性,任何一步失败都回滚。

MyBatis 的 Mapper XML 里,insert 语句用useGeneratedKeys="true" keyProperty="id"回填主键,方便后续关联操作。查询列表时用<if test="status != null">做动态条件拼接,避免写多个查询方法。

2.4 微信小程序端的请求封装与页面跳转

小程序端不要在每个页面里裸写 wx.request,封装一个 request.js 统一处理 token 和错误提示:

// utils/request.js const BASE_URL = 'http://localhost:8080/api'; function request(options) { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + options.url, method: options.method || 'GET', data: options.data || {}, header: { 'content-type': 'application/json', 'token': wx.getStorageSync('token') || '' }, success(res) { if (res.data.code === 200) { resolve(res.data.data); } else if (res.data.code === 401) { // token 过期,跳转登录页 wx.redirectTo({ url: '/pages/login/login' }); reject(res.data); } else { wx.showToast({ title: res.data.msg, icon: 'none' }); reject(res.data); } }, fail(err) { wx.showToast({ title: '网络异常', icon: 'none' }); reject(err); } }); }); } module.exports = { request };

这个封装做了三件事:拼接 baseURL、自动带 token、统一处理 401 和业务错误。页面里调用就变成request({url: '/repair/submit', method: 'POST', data: form}),代码干净很多。注意wx.getStorageSync('token')在登录成功后写入,退出登录时清除。

页面跳转用wx.navigateTo保留当前页,用wx.redirectTo关闭当前页。报修提交成功后应该用 redirectTo 跳到列表页,避免用户点返回又回到提交页重复提交。

3. 从零跑通这套系统:环境搭建、数据库导入和前后端联调

3.1 开发环境版本选择和安装顺序

版本不匹配是新手翻车最多的地方。我一般按这个顺序装:

第一步,装 JDK 8。不要装 JDK 11 或 17,SSM 项目里的老版本 Spring 对高版本 JDK 支持不好,容易出现Unsupported class file major version错误。装完配好 JAVA_HOME 和 PATH,命令行java -version确认输出 1.8。

第二步,装 MySQL 5.7 或 8.0。5.7 更稳,8.0 注意驱动包要用com.mysql.cj.jdbc.Driver,连接 URL 要加serverTimezone=Asia/Shanghai,否则时间字段差 8 小时。

第三步,装 Maven 3.6+。配阿里云镜像加速依赖下载,在 settings.xml 的 mirrors 节点加:

<mirror> <id>aliyun</id> <mirrorOf>central</mirrorOf> <url>https://maven.aliyun.com/repository/public</url> </mirror>

第四步,装 IDEA 或 Eclipse。IDEA 导入 Maven 项目后等依赖下载完,如果 pom.xml 报红,右键项目 → Maven → Reload project。

第五步,装微信开发者工具。导入小程序代码时填的 AppID 可以用测试号,不影响本地调试。

3.2 数据库导入和连接配置修改

拿到压缩包后,先找到 sql 文件夹里的 .sql 文件。在 MySQL 里执行:

mysql -u root -p -e "CREATE DATABASE repair_db DEFAULT CHARACTER SET utf8mb4;" mysql -u root -p repair_db < repair_db.sql

导入完成后用SHOW TABLES;确认五张表都在。然后改后端配置文件,通常是src/main/resources/jdbc.properties或applicationContext.xml:

jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/repair_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai jdbc.username=root jdbc.password=你的密码

注意 URL 里的characterEncoding=utf8不能省,否则小程序端提交的中文故障描述存进去变问号。改完配置后,在 IDEA 里配置 Tomcat 运行,或者用 Maven 的 tomcat7 插件启动。

3.3 后端启动和接口自测

启动 Tomcat 后,浏览器访问http://localhost:8080/api/device/list,如果返回 JSON 数据说明后端通了。如果报 404,检查 web.xml 里 DispatcherServlet 的 url-pattern 是不是/,以及 SpringMVC 配置文件有没有被加载。

接口自测推荐用 Postman 或 curl。比如测试报修提交:

curl -X POST http://localhost:8080/api/repair/submit \ -H "Content-Type: application/json" \ -d '{"deviceNo":"DEV001","faultDesc":"屏幕不亮","userId":1}'

返回{"code":200,"msg":"success"}说明写入成功。去数据库SELECT * FROM repair_order;确认数据在。

3.4 微信小程序端配置和真机预览

小程序代码导入微信开发者工具后,第一件事是改utils/request.js里的 BASE_URL。本地调试用http://localhost:8080/api,但真机预览时 localhost 不通,要改成电脑的局域网 IP,比如http://192.168.1.100:8080/api。同时微信开发者工具里要勾选「不校验合法域名」,否则请求被拦截。

真机预览步骤:点开发者工具右上角「预览」,生成二维码,手机微信扫码。如果手机和电脑不在同一 WiFi 下,请求会超时。另外注意小程序基础库版本,在「详情」→「本地设置」里选一个较新的稳定版。

页面列表加载更多是常见需求,用onReachBottom生命周期实现:

Page({ data: { list: [], page: 1, hasMore: true }, onReachBottom() { if (!this.data.hasMore) return; this.setData({ page: this.data.page + 1 }); this.loadList(); }, loadList() { request({ url: '/repair/list', data: { page: this.data.page, size: 10 } }) .then(res => { this.setData({ list: this.data.list.concat(res.records), hasMore: res.records.length === 10 }); }); } });

hasMore的判断逻辑是:如果本次返回的记录数等于 pageSize,说明可能还有下一页;小于 pageSize 则没有更多了。这个判断比查总数再比较更轻量。

4. 改出你自己的版本:角色权限、工单状态机和消息通知

4.1 三种角色的权限控制怎么做

系统里有普通用户、维修工、管理员三种角色。权限控制分两层:后端接口层用拦截器校验 token 和角色,前端用条件渲染控制按钮显示。

后端拦截器实现:

public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token = request.getHeader("token"); if (StringUtils.isEmpty(token)) { writeError(response, 401, "未登录"); return false; } // 从 token 解析用户信息(实际项目用 JWT 或 Redis) User user = tokenService.parseToken(token); if (user == null) { writeError(response, 401, "token 无效"); return false; } // 管理员接口校验角色 String uri = request.getRequestURI(); if (uri.startsWith("/api/admin") && user.getRole() != 2) { writeError(response, 403, "无权限"); return false; } request.setAttribute("currentUser", user); return true; } }

前端页面里用wx:if控制按钮:

<view wx:if="{{userRole === 1 && order.status === 0}}"> <button bindtap="acceptOrder">接单</button> </view> <view wx:if="{{userRole === 2}}"> <button bindtap="assignOrder">派单</button> </view>

注意前端隐藏按钮只是体验优化,真正的安全边界在后端拦截器。只做前端控制的话,懂行的人直接调接口就绕过去了。

4.2 工单状态流转的完整逻辑

工单状态机是这套系统的核心。状态定义:0 待接单、1 维修中、2 已完成、3 已取消。允许的流转路径:

  • 0 → 1:维修工接单
  • 0 → 3:用户取消
  • 1 → 2:维修工提交维修结果
  • 1 → 3:管理员强制取消

后端在 Service 层做状态校验,不允许跳状态操作:

public Result acceptOrder(Long orderId, Long repairerId) { RepairOrder order = orderMapper.selectById(orderId); if (order == null) return Result.error("工单不存在"); if (order.getStatus() != 0) return Result.error("该工单已被接单或已取消"); order.setStatus(1); order.setRepairerId(repairerId); order.setAcceptTime(new Date()); int rows = orderMapper.updateById(order); if (rows > 0) { // 写入维修记录 RepairRecord record = new RepairRecord(); record.setOrderId(orderId); record.setRepairerId(repairerId); record.setStartTime(new Date()); recordMapper.insert(record); return Result.success(); } return Result.error("接单失败"); }

这段代码的关键点是先查再判再改,用状态值做乐观锁。如果两个人同时点接单,第二个人的order.getStatus()已经不是 0 了,会被拦截。更严谨的做法是在 update 语句里加WHERE status = 0,用数据库行锁保证。

4.3 消息通知的两种实现方式

用户提交报修后,管理员需要收到通知。两种做法:

第一种,轮询。小程序端定时调接口查未读通知数量,简单但费流量。适合通知实时性要求不高的场景。

第二种,微信订阅消息。用户提交报修时,后端调用微信的订阅消息接口,给管理员推送一条服务通知。需要在小程序后台申请模板,拿到 template_id,后端用 access_token 调subscribeMessage.send接口。

// 发送订阅消息 public void sendSubscribeMsg(String openid, String orderNo) { String accessToken = wechatService.getAccessToken(); String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken; Map<String, Object> body = new HashMap<>(); body.put("touser", openid); body.put("template_id", "你的模板ID"); Map<String, Object> data = new HashMap<>(); data.put("thing1", Map.of("value", orderNo)); data.put("thing2", Map.of("value", "新报修工单待处理")); body.put("data", data); // 用 RestTemplate 或 HttpClient 发送 POST 请求 }

订阅消息需要用户在小程序里主动点击授权,一次授权只能发一条。所以提交报修页要放一个「接收通知」的按钮,引导用户授权。

4.4 论文部分的写作切入点

压缩包里的论文不要直接抄。答辩老师最反感的就是查重率高的论文。建议从这几个角度改:

系统设计章节重点写状态机的设计理由,为什么用这四个状态而不是三个或五个,画状态流转图。数据库设计章节写字段选型,比如 fault_desc 用 TEXT 而不是 VARCHAR(255) 是因为故障描述可能很长。测试章节写你实际跑出来的 bug 和修复过程,比如中文乱码怎么解决的、token 过期怎么处理的,这些真实细节比虚构的测试数据有说服力。

5. 避坑与排查:跑这套系统最容易翻车的五个地方

5.1 中文乱码:从数据库到前端全链路排查

现象:小程序提交的故障描述存到数据库变成问号,或者后端返回的 JSON 里中文显示为\uXXXX。

原因:三个环节都可能出问题。数据库连接 URL 没加 characterEncoding、数据库表字符集不是 utf8mb4、Tomcat 的 URIEncoding 没配。

解决:按顺序检查。第一,jdbc.properties 里 URL 加useUnicode=true&characterEncoding=utf8。第二,建库时指定DEFAULT CHARACTER SET utf8mb4。第三,Tomcat 的 server.xml 里 Connector 加URIEncoding="UTF-8"。第四,SpringMVC 配置里加 StringHttpMessageConverter 指定 UTF-8。四个地方都对了,乱码问题基本绝迹。

5.2 跨域请求被拦截:小程序端报 request:fail

现象:微信开发者工具里请求后端接口,控制台报request:fail或net::ERR_CONNECTION_REFUSED。

原因:本地调试时 BASE_URL 写的是 localhost,但小程序运行环境不在电脑上。或者后端没开跨域支持。

解决:真机预览时把 BASE_URL 改成电脑局域网 IP,确保手机和电脑同一 WiFi。后端加 CORS 配置:

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*"); } }

另外微信开发者工具里勾选「不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书」。

5.3 MyBatis 映射文件找不到:Invalid bound statement

现象:启动不报错,但调接口时报Invalid bound statement (not found)。

原因:Mapper XML 文件没被编译到 target 目录,或者 namespace 和接口全限定名不一致,或者方法名和 XML 里的 id 对不上。

解决:第一,检查 pom.xml 的 resources 配置,确保src/main/java下的 xml 文件也被打包:

<resources> <resource> <directory>src/main/java</directory> <includes><include>**/*.xml</include></includes> </resource> </resources>

第二,检查 Mapper XML 的 namespace 是不是接口的全限定名。第三,检查<select id="selectById">的 id 和接口方法名是否完全一致,大小写敏感。

5.4 事务不回滚:数据写了一半

现象:报修提交时,工单表插入了但通知表没插入,数据不一致。

原因:Service 类没加@Transactional,或者异常被 catch 了没往外抛,或者方法不是 public。

解决:在 Service 实现类的方法上加@Transactional(rollbackFor = Exception.class)。注意rollbackFor要指定 Exception.class,默认只回滚 RuntimeException。如果方法里 try-catch 了异常,要么在 catch 里重新 throw,要么手动调TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。

5.5 小程序页面栈溢出:navigateTo 跳转超过十层

现象:点着点着页面跳不动了,控制台报navigateTo:fail page limit exceeded。

原因:wx.navigateTo保留当前页,页面栈最多十层。反复跳转不返回就会溢出。

解决:提交成功、登录成功这类不需要返回的场景用wx.redirectTo替换。或者在跳转前判断getCurrentPages().length,超过 9 就用 redirectTo。更彻底的做法是设计好页面层级,列表页到详情页用 navigateTo,详情页到编辑页用 navigateTo,编辑完返回用wx.navigateBack。

6. 让这套系统在答辩时多拿十分的两个技巧

6.1 用 Charles 抓包证明接口真的通了

答辩时老师问「你怎么证明前后端联调成功了」,光说不够,打开 Charles 抓包给他看。配置步骤:手机和电脑连同一 WiFi,Charles 设置代理端口 8888,手机 WiFi 高级设置里填电脑 IP 和端口 8888,然后在 Charles 里就能看到小程序发出的每个请求和返回。

抓包能看到的东西比日志更直观:请求头里有没有带 token、请求参数格式对不对、返回的 JSON 结构是什么、响应时间多少毫秒。如果某个接口返回 500,Charles 里能看到完整的错误堆栈,比在 IDEA 控制台翻日志快得多。

注意抓 HTTPS 请求需要在手机装 Charles 证书,iOS 还要在「关于本机」→「证书信任设置」里手动信任。这一步不做的话只能看到 CONNECT 请求,看不到具体内容。

6.2 给系统加一个数据看板页

答辩演示时,管理员登录后看到一个统计页:今日报修数、待接单数、已完成数、平均维修时长。这个页面用 ECharts 或简单的数字卡片实现,数据从后端聚合查询拿。

SELECT COUNT(*) AS total, SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) AS pending, SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) AS finished, AVG(TIMESTAMPDIFF(HOUR, create_time, finish_time)) AS avg_hours FROM repair_order WHERE DATE(create_time) = CURDATE();

这条 SQL 一次查出四个指标,后端封装成对象返回,前端用卡片展示。加这个页面的成本不到半天,但答辩时演示效果提升明显——老师能看到你不只是把 CRUD 跑通了,还做了数据聚合和可视化。

我自己的习惯是,每次跑通一个别人给的压缩包项目,第一件事不是改代码,而是先把数据库 ER 图手画一遍,搞清楚每张表的关联关系。画完再动手改,比直接看代码快得多。这套设备报修系统,核心就是 repair_order 表的状态字段和三个角色之间的权限关系,把这两条线理清楚,剩下的都是体力活。希望帮到你。

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

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

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

立即咨询