微信小程序对接Java后端的家政系统实战
简介:本资源是一套完整的家政服务类毕业设计项目,面向计算机相关专业本科生及Java全栈初学者,聚焦微信小程序与Spring Boot后端协同开发的实战场景,解决家政预约、人员管理与用户咨询等典型业务需求。压缩包共1214个文件,涵盖119个Java后端逻辑类、134个Vue前端组件、175个JS交互脚本、231个PNG图标资源及86个WXML页面结构文件,辅以SQL建表语句、MP4演示视频与详细说明文档,整体体积32.55MB,结构分层清晰,便于理解前后端通信与权限控制机制。已有203人学习下载,资源提供可直接运行的源码、完整数据库脚本、管理员与用户双角色操作录屏,以及bat一键部署脚本(install/run/build),显著降低环境搭建门槛,适合课程设计复现、毕设参考与小程序+Java技术栈整合学习。
1. 微信小程序+Java家政系统毕业设计:不是套壳模板,是能跑通「预约-派单-评价」闭环的完整工程
你手头那份标着“微信小程序+Java后端”的家政项目压缩包,大概率不是网上搜来的空壳Demo——它真能完成一次从用户点击“保洁服务”、填写地址时间、下单支付,到后台管理员分派师傅、师傅接单确认、服务完成后双方互评的全流程。我去年帮三个学院指导毕设,翻过不下40个所谓“家政系统”,90%卡在「登录能进、首页能刷、但点预约就404」;而这个资源里,wxapp目录下有带wx.request真实调用后端接口的页面逻辑,springboot模块里OrderController.java里明明白白写着@PostMapping("/api/order/create"),数据库脚本schema.sql里连t_order_status_log这种状态流转日志表都建好了。它适合两类人:一是大三下刚学完Spring Boot和小程序基础、急需一个不踩环境坑、不缺关键链路、能现场答辩演示的毕设载体;二是想快速验证「小程序如何对接Java RESTful API」的初学者——别被标题里的“毕业设计”误导,它的接口设计、权限分层、事务控制,比很多小公司内部系统还扎实。
2. 源码结构拆解与核心链路还原:看清它为什么不是拼凑货
2.1 目录树即架构图:四个模块各司其职
打开.rar解压后的根目录,你会看到四个平行文件夹:wxapp(小程序前端)、springboot-backend(Java后端)、database(数据库脚本)、docs(文档与视频)。这不是随意堆放,而是典型的前后端分离毕业设计标准结构:
wxapp:基于原生微信小程序框架(非uni-app),pages/order/create下的create.js里wx.request({url: 'https://localhost:8080/api/order/create', ...})直接指向后端API,且所有网络请求都封装在utils/request.js中统一处理token;springboot-backend:Spring Boot 2.7.x + MyBatis Plus,pom.xml里明确依赖spring-boot-starter-web、mybatis-plus-boot-starter、spring-boot-starter-data-redis(用于存储验证码);database:包含schema.sql(建表语句)和init_data.sql(初始化管理员、测试用户、服务类型数据),其中t_user表有role ENUM('customer','worker','admin')字段,权限控制已落地;docs:演示视频.mp4实录了从微信开发者工具启动→登录→选择保洁→填写地址→下单→后台管理端查看订单→派单→师傅端接单→完成评价的全过程,时长6分23秒,无剪辑跳转。
提示:别急着跑起来!先看
springboot-backend/src/main/resources/application.yml里的spring.datasource.url——默认是jdbc:mysql://localhost:3306/home_service?useSSL=false&serverTimezone=Asia/Shanghai,这意味着你本地必须装MySQL 5.7+,且已创建home_service库。很多同学直接双击Application.java报错,根源就在这行配置没改。
2.2 关键链路代码精读:从下单到派单的三次状态跃迁
毕业设计最怕“功能看起来有,实际走不通”。我们盯住核心业务链路——用户下单后,订单如何从“待接单”变成“已派单”?这背后藏着三个关键节点:
2.2.1 小程序端:表单提交触发真实API调用
// wxapp/pages/order/create/create.js submitOrder() { const data = { serviceType: this.data.serviceType, address: this.data.address, timeSlot: this.data.timeSlot, remark: this.data.remark }; wx.request({ url: getApp().globalData.baseUrl + '/api/order/create', method: 'POST', data: data, header: { 'Authorization': wx.getStorageSync('token') }, // 携带JWT token success: (res) => { if (res.data.code === 200) { wx.showToast({ title: '下单成功', icon: 'success' }); setTimeout(() => wx.navigateBack(), 1500); } }, fail: (err) => console.error('下单失败', err) }); }这段代码的关键在于:
getApp().globalData.baseUrl从全局变量读取后端地址,避免硬编码;header里传Authorization,说明后端启用了JWT鉴权(springboot-backend里SecurityConfig.java配置了http.authorizeRequests());success回调里判断res.data.code === 200,而非只看HTTP状态码,说明后端返回的是统一响应体Result<T>。
2.2.2 Java后端:事务包裹的订单创建与状态初始化
// springboot-backend/src/main/java/com/example/controller/OrderController.java @PostMapping("/api/order/create") public Result<OrderVO> createOrder(@RequestBody OrderDTO dto, @RequestHeader("Authorization") String token) { // 1. 校验token并解析用户ID(省略JWT解析逻辑) Long userId = jwtUtil.getUserIdFromToken(token.replace("Bearer ", "")); // 2. 创建订单实体(含初始状态) Order order = new Order(); order.setCustomerId(userId); order.setServiceType(dto.getServiceType()); order.setAddress(dto.getAddress()); order.setStatus(OrderStatus.WAITING_ASSIGNMENT.getCode()); // 关键:初始状态为"待派单" order.setCreateTime(new Date()); // 3. 事务内保存订单 + 插入状态日志 try { orderService.save(order); // MyBatis Plus save方法 statusLogService.insertLog(order.getId(), OrderStatus.WAITING_ASSIGNMENT, "用户下单"); return Result.success(orderConverter.toVO(order)); } catch (Exception e) { throw new ServiceException("创建订单失败"); } }这里体现毕业设计应有的工程素养:
@RequestBody OrderDTO接收前端数据,OrderVO返回视图对象,DTO/VO分离清晰;OrderStatus.WAITING_ASSIGNMENT是枚举类定义的状态码,非魔法数字;statusLogService.insertLog(...)确保每次状态变更都有迹可循,答辩时可展示日志表。
2.2.3 管理后台:人工派单触发状态跃迁
管理员在/admin/order/list页面点击“派单”,调用的是另一个接口:
// springboot-backend/src/main/java/com/example/controller/AdminOrderController.java @PostMapping("/admin/order/assign/{orderId}") public Result<String> assignOrder(@PathVariable Long orderId, @RequestBody AssignDTO dto) { // 1. 查询订单(校验状态是否为WAITING_ASSIGNMENT) Order order = orderService.getById(orderId); if (!OrderStatus.WAITING_ASSIGNMENT.getCode().equals(order.getStatus())) { return Result.fail("订单状态异常,无法派单"); } // 2. 更新订单工人ID和状态 order.setWorkerId(dto.getWorkerId()); order.setStatus(OrderStatus.ASSIGNED.getCode()); order.setAssignTime(new Date()); orderService.updateById(order); // 3. 记录新状态日志 statusLogService.insertLog(orderId, OrderStatus.ASSIGNED, "管理员派单给工人ID:" + dto.getWorkerId()); return Result.success("派单成功"); }注意if校验:只有状态为WAITING_ASSIGNMENT才允许派单,这是状态机思想的落地。很多毕设漏掉这步,导致“已完工订单还能被重复派单”。
3. 本地运行四步法:绕过90%新手卡点的实操路径
3.1 数据库准备:用init_data.sql填平第一道坑
别自己手建表!直接执行database/init_data.sql(不是schema.sql单独执行)。原因:init_data.sql里包含INSERT INTO t_user (...) VALUES (...),(...),其中第一个用户是管理员账号(username='admin',password='$2a$10$...'是BCrypt加密后的密码),第二个是测试客户(username='testuser'),第三个是测试师傅(username='worker1')。如果你只跑schema.sql,表是空的,登录时永远提示“用户不存在”。
操作步骤:
# 1. 登录MySQL mysql -u root -p # 2. 创建数据库(字符集必须utf8mb4) CREATE DATABASE home_service CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # 3. 切换数据库并执行初始化脚本 USE home_service; source /path/to/your/database/init_data.sql;注意:
init_data.sql里密码是BCrypt加密的,明文是123456。管理员账号密码就是admin/123456,客户账号testuser/123456,师傅账号worker1/123456——这是硬编码在SQL里的,不是后端生成的。
3.2 后端启动:修改application.yml三处关键配置
springboot-backend/src/main/resources/application.yml需调整:
spring: datasource: url: jdbc:mysql://localhost:3306/home_service?useSSL=false&serverTimezone=Asia/Shanghai username: root # 改成你的MySQL用户名 password: 123456 # 改成你的MySQL密码 redis: host: localhost port: 6379 password: "" # 如果Redis没设密码,留空 # JWT密钥(必须改!否则token校验失败) jwt: secret: your_custom_secret_key_here_32_chars # 至少32位随机字符串 expire: 86400 # 24小时过期血泪经验:jwt.secret必须改!原包里可能是123456这种弱密钥,Spring Security的JWT工具类会因密钥长度不足直接抛IllegalArgumentException。我一般用Python生成:python -c "import secrets; print(secrets.token_urlsafe(32))"。
3.3 小程序调试:用微信开发者工具配置合法域名
微信小程序要求所有wx.request必须指向已配置的合法域名。本地开发时,需在微信公众平台后台设置:
- 登录 微信公众平台 → 开发管理 → 开发设置 → 服务器域名
- 在「request合法域名」中添加:
https://localhost(注意是https,不是http) - 重要:开发者工具中必须勾选「不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书」(右上角详情 → 本地设置)
否则wx.request会报fail net::ERR_CONNECTION_REFUSED,你以为后端没起来,其实是域名校验拦截了。
3.4 前后端联调验证:用curl绕过小程序界面直测接口
当小程序界面报错时,先用curl验证后端是否真通:
# 1. 获取用户token(模拟登录) curl -X POST "http://localhost:8080/api/auth/login" \ -H "Content-Type: application/json" \ -d '{"username":"testuser","password":"123456"}' # 返回示例:{"code":200,"data":{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}} # 2. 用token下单(替换上面返回的token) curl -X POST "http://localhost:8080/api/order/create" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -d '{"serviceType":"cleaning","address":"北京市朝阳区XX大厦","timeSlot":"2024-06-15 14:00"}'如果第二步返回{"code":200,"data":{...}},说明后端API完全正常,问题一定出在小程序端的网络配置或页面逻辑。
4. 避坑指南:答辩前必须扫清的五个致命细节
4.1 现象:小程序登录后首页空白,控制台报Cannot read property 'length' of undefined
原因:wxapp/app.js里onLaunch中调用getApp().globalData.baseUrl,但globalData未初始化。原包里app.js第12行有globalData: { baseUrl: '' },但部分同学解压时误删了这行。
解决:打开wxapp/app.js,确认App({对象内有globalData: { baseUrl: 'https://localhost:8080' },且baseUrl值与后端端口一致(默认8080)。
4.2 现象:后台管理端登录成功,但订单列表显示“暂无数据”,数据库里明明有订单
原因:springboot-backend/src/main/java/com/example/service/impl/OrderServiceImpl.java中listOrders()方法用了QueryWrapper,但条件eq("status", status)写成了eq("status", null),导致查不到任何记录。
解决:找到该方法,将queryWrapper.eq("status", status)改为queryWrapper.isNotNull("status"),或传参时确保status不为null(管理端列表应查所有状态,而非指定状态)。
4.3 现象:派单后师傅端收不到通知,WebSocket连接失败
原因:原包springboot-backend里WebSocket配置类WebSocketConfig.java被注释掉了,且pom.xml中spring-boot-starter-websocket依赖被移除。
解决:
- 取消
WebSocketConfig.java的注释; - 在
pom.xml中添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>- 小程序端
utils/websocket.js中wsUrl需改为wss://localhost:8080/ws/worker/(注意是wss,不是ws)。
4.4 现象:上传图片失败,后端报java.io.FileNotFoundException: /upload/xxx.jpg (No such file or directory)
原因:springboot-backend/src/main/resources/application.yml中upload.path配置为/upload/,但Linux/Mac系统下该路径不存在,且Java无自动创建目录权限。
解决:
- 方案A(推荐):在
application.yml中改为相对路径upload.path: ./upload/,Spring Boot会自动在jar包同级目录创建upload文件夹; - 方案B:手动创建
/upload目录并赋权chmod 755 /upload。
4.5 现象:演示视频里“评价功能”能点,但实际点击无反应
原因:wxapp/pages/order/detail/detail.js中onEvaluate()方法调用wx.navigateTo({url: '/pages/evaluate/index?orderId=' + this.data.order.id}),但/pages/evaluate/index页面不存在——原包里只有/pages/evaluate/create(评价提交页),缺少评价列表页。
解决:
- 复制
/pages/evaluate/create文件夹,重命名为index; - 修改
index/index.js中onLoad方法,增加根据orderId查询评价记录的逻辑; - 在
index/index.wxml中补充评价列表渲染(<view wx:for="{{evaluations}}" ...>)。
5. 进阶技巧:把毕业设计升级为可演示的“高光时刻”
5.1 用Postman自动生成API文档,答辩时直接投屏
别再手写Word文档!用Postman导入后端swagger-ui.html(启动后访问http://localhost:8080/swagger-ui.html):
- 在Postman中点击
Import→Link,粘贴http://localhost:8080/v3/api-docs(SpringDoc OpenAPI 3.0格式); - 导入后,Postman自动生成所有接口集合,每个接口含请求示例、参数说明、响应模型;
- 答辩时打开Postman,选中
/api/order/create接口,点击Send,实时展示JSON响应体——比截图更可信。
我从那以后,每次指导毕设都强制学生用Postman导出HTML报告(
Export→HTML),打印出来装订成册,评委老师翻两页就点头:“嗯,接口设计规范”。
5.2 给小程序加“离线缓存”,让演示不依赖网络
微信小程序默认关闭离线能力,但家政系统常需查看历史订单。在wxapp/app.js中加入:
// app.js onLaunch中添加 wx.getStorage({ key: 'orderList', success: (res) => { getApp().globalData.orderList = res.data; // 缓存订单列表 } }); // 在订单列表页onLoad中优先读缓存 onLoad() { const cached = wx.getStorageSync('orderList'); if (cached && cached.length > 0) { this.setData({ orders: cached }); } else { this.loadOrders(); // 再发起网络请求 } }, // 请求成功后写入缓存 loadOrders() { wx.request({ url: getApp().globalData.baseUrl + '/api/order/list', success: (res) => { if (res.data.code === 200) { wx.setStorage({ key: 'orderList', data: res.data.data }); this.setData({ orders: res.data.data }); } } }); }这样即使演示时断网,订单列表仍能显示——评委问“没网怎么办”,你指屏幕:“看,历史订单还在”。
5.3 后端加“慢SQL日志”,答辩时秀性能优化意识
在springboot-backend/src/main/resources/application.yml中开启MyBatis Plus慢SQL日志:
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: # 开启慢SQL记录(执行超100ms的SQL) log-exception: true log-slow-sql: true slow-sql-threshold: 100启动后端,故意在订单列表页筛选大量数据,控制台会输出:
==> Preparing: SELECT * FROM t_order WHERE status = ? AND create_time > ? ==> Parameters: 1(Integer), 2024-01-01(Date) [SQL Time] 128ms答辩时说:“我关注了性能,这里查订单用了索引(t_order(status,create_time)),但仍有128ms,下一步计划加Redis缓存热门订单”。
5.4 数据库加“唯一约束”,堵死重复下单漏洞
原包schema.sql中t_order表缺少对customer_id + service_type + time_slot的联合唯一索引,用户可能10秒内狂点下单按钮生成多条相同订单。手动修复:
-- 在MySQL中执行 ALTER TABLE t_order ADD UNIQUE INDEX uk_customer_service_time (customer_id, service_type, time_slot);然后在Java后端OrderController.createOrder()中捕获DuplicateKeyException:
try { orderService.save(order); } catch (DuplicateKeyException e) { return Result.fail("您已在该时段预约此服务,请勿重复提交"); }这个细节会让评委眼前一亮:“哦?他考虑到了并发场景”。
希望帮到你。
本文还有配套的精品资源,点击获取