尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

SSM+微信小程序宿舍报修系统:从需求到部署全解析

SSM+微信小程序宿舍报修系统:从需求到部署全解析 做这类课设项目的学生应该不少宿舍报修系统是个非常典型的选题。表面上看就是个提交工单、处理工单的小功能但真正把前后端完整跑通、让小程序端能正常展示报修进度、让维修人员能接单派单涉及的技术点相当密集小程序页面生命周期、SSM框架的分层协作、微信登录换取用户身份、图片上传、数据状态流转还有联调时的域名校验和接口排查。这套基于SSM的宿舍报修系统我用微信小程序做用户端后端用Spring SpringMVC MyBatis跑通之后既能直接交作业也能作为简历上的完整项目经历。下面把这套系统的需求拆解、数据库设计、核心接口实现、小程序端踩坑记录以及源码怎么快速跑起来一次性说清楚。1. 项目概述与需求拆解1.1 这个系统解决的核心痛点宿舍报修这个场景传统流程一般是学生发现灯坏了、门锁坏了、水龙头漏水去楼下值班室填一张纸质单或者口头跟宿管说一句然后等维修师傅有空了再上门。这个模式最大的问题是信息断层报修单到底有没有提交上去维修师傅有没有看到修到哪一步了学生完全不知道。宿管那边单子多了也容易丢尤其是期末高峰期几张纸弄丢了学生等一周都没人来修然后就开始投诉。小程序版本的报修系统核心就是把这条线变成可视化的闭环。学生在小程序里选故障类型、填位置、拍照上传提交后就能看到工单状态从待接单变成维修中再到已完成。维修师傅在自己的小程序端或者后台能看到待处理工单按紧急程度排序处理。管理员则能看整体数据比如哪栋楼报修最多、哪个维修师傅处理速度慢、哪些报修超时了。信息一旦在线化责任就清楚了扯皮自然就少。这个项目适合谁如果你是刚学完Java Web、想做个完整项目练手的人或者正在选毕业设计题目再或者想拿来当作简历里的全栈实践这套系统都很合适。它的复杂度刚好卡在该有的都有、但不至于失控的位置表数量不多接口逻辑清晰小程序端也不算花哨可扩展空间又很大。1.2 用户角色与功能清单整个系统的用户角色在需求分析阶段就要定清楚不然后面接口权限会乱。我把角色拆成三类学生/报修人微信授权登录后能提交报修单选类型、写描述、传图片、查看自己的报修记录、查看工单状态、对完成的工单进行评价和确认关闭。维修师傅能看到自己被分配的工单或从待接单池里抢单支持调整状态已接单、维修中、已完成填写维修反馈。管理员/宿管维护楼栋、故障类型、维修师傅账号有权重新分单、查看全部工单、处理超时工单、看统计报表。功能梳理清楚之后前后端的页面和接口就有了依据。我把功能清单压缩成一张表可以直接用来检查自己做的系统有没有漏掉核心功能模块学生端维修端管理端登录微信授权登录账号密码登录账号密码登录报修提交工单、拍照上传、催单查看待接工单、接单强制分单处理查看进度、确认完工更新状态、填写反馈查看进展、超时提醒管理消息通知个人工作量用户管理、类型管理、报表评价打分、评价内容查看评价查看汇总评价有一点值得提醒很多第一次做这类系统的同学容易忽略角色权限的控制所有用户登录后都能调所有接口。虽然演示起来没问题但如果要做成真正能看的项目建议在拦截器里按照角色做接口访问控制这一步在答辩时很加分。2. 技术选型思路与数据库设计2.1 为什么用SSM而不是直接上Spring Boot现在很多新项目上来就是Spring Boot确实configurations省心很多。但我这里还是坚持用SSM理由很实际SSMSpring SpringMVC MyBatis的结构更显式Controller、Service、Mapper分层清清楚楚每个注解的作用都摆在你面前。对于学生和刚入门的人来说Spring Boot把太多东西自动配置好了你反而不清楚项目是怎么跑起来的。面试或答辩时老师问一句SpringMVC的请求流程是怎么走的如果你的项目是SSM你很容易接住如果是Spring Boot往往就只能答个自动配置然后卡住。用SSM做这套系统还有一个好处WEB-INF下的文件结构、web.xml配置、applicationContext.xml和spring-mvc.xml每个文件都有存在的意义。你可以真实感受到一个Java Web项目怎么从Servlet演进到框架整合。以后转Spring Boot你理解起来也会更快。配置层面典型的三件套spring-mvc.xml开启注解驱动、配置视图解析器、静态资源放行。applicationContext.xml扫描Service和Dao、配置数据源和事务管理器。mybatis-config.xml别名、驼峰映射、Mapper扫描。这三个文件之间的分工其实就是一个项目的骨架MVC管请求分发Spring管业务对象生命周期MyBatis管SQL映射。2.2 数据表设计从业务模型到建表语句系统核心涉及用户、报修工单、故障类型、工单日志、评价几张表。我实际建表时的核心字段如下这也是整个系统最需要想清楚的部分。用户表sys_user字段类型说明idint主键open_idvarchar小程序微信openid学生登录专用roleint角色1学生 2维修工 3管理员usernamevarchar登录名维修和管理员用passwordvarchar密码phonevarchar联系电话buildingvarchar楼栋信息学生填写roomvarchar宿舍号statusint是否启用报修工单表repair_order字段类型说明idint主键order_novarchar工单编号如BX20250601001user_idint报修人type_idint故障类型descriptiontext故障描述imagesvarchar图片路径逗号分隔addressvarchar具体位置statustinyint0待接单 1已接单 2维修中 3已完成 4已取消assignee_idint接单人create_timedatetime提交时间finish_timedatetime完成时间leveltinyint紧急程度故障类型表repair_typeid、name、sort。这个表很简单但别忘了因为小程序端的报修表单要动态加载故障类型下拉框。工单日志表order_log记录状态变更的历史比如谁在什么时间把工单从待接单改成了维修中。这个表是答辩时的亮点因为它体现了可追溯的设计思想。建表时最容易踩的坑是两个一是状态字段没有默认值导致插入时程序报错二是没有任何时间字段后面想看超时工单完全无从查起。建议create_time、update_time、finish_time这些字段从一开始就加上。SQL示例可以这样写CREATE TABLE repair_order ( id INT AUTO_INCREMENT PRIMARY KEY, order_no VARCHAR(32) NOT NULL, user_id INT NOT NULL, type_id INT, description VARCHAR(500), images VARCHAR(1000), address VARCHAR(255), status TINYINT DEFAULT 0 COMMENT 0待接单 1已接单 2维修中 3已完成 4已取消, assignee_id INT, level TINYINT DEFAULT 1, create_time DATETIME, finish_time DATETIME, KEY idx_user_id (user_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;3. 后端核心接口设计与实现3.1 SSM分层Controller-Service-Mapper怎么配合这套系统的后端接口我习惯按模块拆登录模块、报修模块、工单处理模块、统计模块。以提交报修为例完整走一遍SSM三层的代码组织方式。Controller层只负责接收参数、调Service、返回JSON不在里面写业务逻辑RestController RequestMapping(/api/repair) public class RepairController { Autowired private RepairService repairService; PostMapping(/submit) ResponseBody public Result submit(RequestBody RepairOrder order, HttpSession session) { Integer userId (Integer) session.getAttribute(userId); if (userId null) { return Result.error(未登录); } order.setUserId(userId); int id repairService.submitOrder(order); return Result.success(id); } }Service层承载核心业务比如生成工单编号、校验用户、初始化日志Service public class RepairServiceImpl implements RepairService { Autowired private RepairOrderMapper orderMapper; Autowired private OrderLogMapper logMapper; Override Transactional public int submitOrder(RepairOrder order) { order.setOrderNo(BX System.currentTimeMillis()); order.setStatus(0); order.setCreateTime(new Date()); orderMapper.insert(order); logMapper.insert(new OrderLog(order.getId(), 0, 提交报修)); return order.getId(); } }Mapper层就是MyBatis的接口加XML。注意这里我加了Transactional为什么因为submitOrder要同时写工单表和日志表任何一个失败都要回滚绝不能让工单创建成功但日志没写进去那样后面状态追踪就废了。Controller返回的统一Result对象也很关键。我建议统一成{code: 0, msg: success, data: {...}}的结构。这样小程序端解析数据就只需要关注code值判断成功失败不用每个接口都调整解析逻辑。这个习惯在联调时能省大量时间。3.2 工单状态流转从一个状态机说起报修工单不是简单的新增、查询它有一个明确的生命周期。我在设计的时候就规定死了状态的流转路径待接单0→ 已接单1已接单1→ 维修中2维修中2→ 已完成3待接单0→ 已取消4仅管理员操作或学生提交后2小时内可取消这个状态机为什么要提前定清楚因为如果你不在后端做状态校验就会出现学生直接调接口把待接单改成已完成这种离谱操作。我在Service层加了一个状态校验方法private static final MapInteger, ListInteger TRANSITIONS new HashMap(); static { TRANSITIONS.put(0, Arrays.asList(1, 4)); TRANSITIONS.put(1, Arrays.asList(2)); TRANSITIONS.put(2, Arrays.asList(3)); } public void changeStatus(int orderId, int targetStatus) { RepairOrder order orderMapper.selectById(orderId); ListInteger allowed TRANSITIONS.get(order.getStatus()); if (allowed null || !allowed.contains(targetStatus)) { throw new BusinessException(非法的状态流转); } // 执行更新并写日志 }状态机是我强烈建议每个做这类系统的人都写的部分。它把模糊的业务规则变成可执行的代码也让系统显得专业。答辩时你拿出这个设计来讲老师基本不会在业务层面挑刺。3.3 微信登录与Token处理小程序端没有传统的账号密码而是通过wx.login()获取临时code然后传到后端后端再调用微信的jscode2session接口换取openid。这里的核心问题是openid就是用户的唯一下标你要用它去查本地用户表如果查不到就自动注册一个新用户。需要特别注意的是微信登录接口的调用需要配置小程序的AppID和AppSecret。我在第一次调试时因为这个Secret配置错误导致一直报错排查了半天。建议在applicationContext.xml配置文件中把这两个值用占位符替代部署时再改成正式值避免源码泄露后被人恶意调用。拿到openid后我建议在后端维护一个Token存到Redis或者数据库返回给小程序端。小程序后续请求都带上这个Token后端拦截器校验通过后再放行。这里有一个高频问题直接用微信的session_key当登录态可以吗可以但不推荐因为session_key有自己的生命周期和更新机制业务登录态应该自己控制。4. 小程序端实现与踩坑记录4.1 页面结构与列表加载更多小程序端的页面结构不会太复杂我分成这几块首页推荐待办统计、报修提交页、报修记录列表页、工单详情页、个人中心页。报修记录列表用的是小程序最常见的下拉刷新 上拉加载更多模式。这是网络热词里经常被搜到的点因为很多人第一次写列表分页时直接一次性把数据全查出来导致页面卡顿。正确做法是后端接口接收pageNum和pageSize两个参数返回总条数和当前页数据GetMapping(/list) public Result list(RequestParam int pageNum, RequestParam int pageSize, RequestParam(required false) Integer status) { PageHelper.startPage(pageNum, pageSize); ListRepairOrderVO list orderMapper.selectList(status); PageInfoRepairOrderVO info new PageInfo(list); return Result.success(info); }小程序端配合onReachBottom触底加载onReachBottom() { if (this.data.pageNum * this.data.pageSize this.data.total) { wx.showToast({ title: 没有更多了, icon: none }); return; } this.setData({ pageNum: this.data.pageNum 1 }); this.loadList(); }有个坑必须说小程序请求接口时如果后端返回的JSON里用了Long类型的id比如雪花ID小程序端的number类型精度不够超过16位就会丢精度。我遇到时页面数据能查到但是点进去详情显示不出来。解决方案很简单后端返回时把id转成String。这个坑在真实项目里经常遇到值得记住。4.2 报修表单与图片上传报修表单里最有技术含量的是图片上传。用户可能选多张照片我们需要调用wx.chooseMedia选择图片然后一张张传给后端。上传时要注意不能直接用wx.uploadFile把文件传到服务端就算了后端还要处理文件保存路径、生成访问URL、把URL存到工单记录里。我这里给一个可以复用的处理思路后端创建一个独立的上传接口/api/common/upload用MultipartFile接收文件将文件保存到本地指定目录同时返回可访问的完整URLPostMapping(/upload) ResponseBody public Result upload(RequestParam(file) MultipartFile file, HttpServletRequest request) { if (file.isEmpty()) { return Result.error(文件为空); } String originalFilename file.getOriginalFilename(); String suffix originalFilename.substring(originalFilename.lastIndexOf(.)); String fileName UUID.randomUUID().toString().replace(-, ) suffix; String realPath request.getServletContext().getRealPath(/uploads/); File dir new File(realPath); if (!dir.exists()) dir.mkdirs(); file.transferTo(new File(dir, fileName)); String url /uploads/ fileName; return Result.success(url); }这里需要处理两个细节一是对上传文件做类型校验不能什么文件都收二是当图片数量多时前端要控制并发小程序端最常见的问题是用户一次性选了9张图然后前端用for循环并发上传把后端的Tomcat默认线程池打满导致请求超时。稳妥做法是做一个队列同时最多上传3个完成一批再传下一批。4.3 顶部导航栏与动态标题小程序端的顶部导航栏高度是一个容易被忽略了但实际很影响体验的参数。不同手机的胶囊按钮位置不一样如果你用自定义导航栏就需要通过wx.getMenuButtonBoundingClientRect()拿到胶囊按钮的位置再动态计算导航栏高度。这个在很多机型适配时相当关键。比如我一开始直接写了个固定高度结果在全面屏手机上自定义标题被状态栏挡住了按钮点不到。后来统一用下面的公式计算const menu wx.getMenuButtonBoundingClientRect(); const system wx.getSystemInfoSync(); const navBarHeight (menu.top - system.statusBarHeight) * 2 menu.height;还有个实用小技巧报修工单详情页可以动态设置标题比如用wx.setNavigationBarTitle({ title: 工单号 orderNo })这样用户分享页面时别人一眼就能看到这是哪个工单。做这个功能时别忘了在页面配置文件或者js里设置enableShareAppMessage不然分享按钮出不来。4.4 联调阶段怎么用抓包工具排查问题前后端联调是大学生做课设最痛苦的一步尤其是后端API报错但小程序端只显示request:fail。这种情况下我强烈建议学会用抓包工具比如Charles查看小程序发出的请求。注意这只是本地调试手段完全不涉及任何特殊网络配置纯粹是电脑上的调试工具。用法很简单开启抓包后你操作小程序就能看到它发出的每个请求的URL、请求头、参数、返回的JSON数据快速定位问题是出在前端参数传错了、后端报异常了还是根本没有发起请求。排查思路看请求有没有发出没发出就是前端代码逻辑问题。看请求URL对不对有没有404或者405。看请求参数传参是中文字符串还是JSON格式是否和后端接口匹配。看响应内容如果是后端500错误再去看后端控制台的具体异常栈。这里我碰到最高频的一个问题是请求头里没带Content-Type: application/json导致后端用RequestBody接参数时一直报HttpMessageNotReadableException。用小程序的wx.request提交JSON时必须显式设置headerwx.request({ url: BASE_URL /api/repair/submit, method: POST, header: { Content-Type: application/json }, data: orderData, success(res) { ... } });如果不加这一行小程序默认发的是application/x-www-form-urlencoded后端解析不到JSON对象。5. 源码跑通指南与二次开发扩展5.1 拿到源码后从零跑起来的五个步骤很多人拿到一套源码最头疼的是不知道从哪里开始。我这套系统的运行步骤其实也是所有SSM项目和小程序项目通用的流程照着做就能跑通第一准备环境。装好JDK 1.8、Maven 3.6、MySQL 5.7或8.0、Tomcat 8.5以及微信开发者工具。JDK版本不要装太新比如JDK 17配Tomcat 8.5会有兼容问题建议JDK 8最稳。第二导入数据库。用Navicat或者命令行执行项目根目录下的sql/dormitory_repair.sql脚本它会自动建库建表并插入初始数据。初始数据里自带了一个管理员账号、两个维修师傅账号登录密码一般是123456具体看项目说明文件。第三改配置文件。打开jdbc.properties把数据库地址、用户名、密码改成你自己的。再把wx-config里的AppID和AppSecret换成你的小程序账号的。如果你暂时没有小程序AppID可以先不用微信登录功能直接用测试账号登录接口但建议还是去微信公众平台注册一个个人开发者账号免费的。第四启动后端。用IDEA打开项目配置Tomcat把项目部署到Tomcat并启动。启动后浏览器访问http://localhost:8080/api/health如果能返回正常JSON说明后端起来了。第五导入小程序项目。在微信开发者工具中导入前端源码目录填写你的AppID然后在app.js里把BASE_URL改成你的后端地址。注意本地开发时小程序默认不允许请求http接口需要在开发者工具详情-本地设置里勾选不校验合法域名。不过这只是开发环境上线时域名必须是HTTPS且在小程序后台配置过。5.2 可以继续扩展的方向这套源码跑通后我不建议直接交差就完事哪怕只是为了学习也可以试着扩展几个方向给自己加加分消息通知工单状态变化时通过小程序订阅消息推送给学生这是很实用且常见的功能能在用户粘性方面讲故事。统计报表基于订单表按楼栋、按维修类型做聚合统计用ECharts在小程序里画出饼图和柱状图。这个扩展能直接体现数据分析能力。超时自动处理用定时任务扫出超过48小时未完成的工单自动转给管理员避免工单卡死。Redis缓存把高频访问的故障类型列表和待接单列表缓存起来减少数据库压力。虽然宿舍规模下用不上但思路可以写进项目文档作为亮点。我自己实际做这套系统时最后悔的一件事是没有从一开始就留出order_log这个扩展点后面加上去要改一堆代码。你现在在做的话建议把日志表从一开始就建好这会让系统显得完整很多。还有一个经验就是代码和数据库字段的命名一定要有统一规范。我早期是userName和user_name混着用后来排坑排到崩溃最后还是全改成驼峰命名并在MyBatis里开启驼峰映射才彻底解决。建议你从一开始就统一用驼峰并且每次改表结构马上同步更新XML映射文件不要拖一拖就出问题。最后再分享一个小技巧如果调试时频繁改动后端代码不要每次都手动重启Tomcat用IDEA的DevTools或者装一个JRebel插件能自动热部署开发效率直接翻倍。这套系统的源码结构不复杂理清前后端数据流之后你完全可以在此基础上加入自己的功能把它变成真正属于自己的实战项目。
返回列表