简介面向毕业设计与微信小程序开发学习者这份家政服务管理小程序资源基于微信小程序SSMVueMySql实现前后端分离覆盖用户端家政预约与支付、阿姨端审核与评价查看、管理端家政公司/阿姨/服务项目/留言管理等多类核心业务适合作为计算机专业毕业设计、课程设计或项目练手的完整参考。资源共1123个文件压缩包约38.52MB类型包括Java后台、SSM配置、Vue管理端页面、小程序wxml/wxss/js逻辑、数据库SQL脚本、毕业论文doc及视频演示mp4等整体目录结构清晰便于按模块查找和二次开发。已有228人学习下载。除可直接运行的工程源码外还配套建表脚本、开发环境配置、前后端联调思路与答辩展示材料能为从环境搭建到系统部署的整个过程提供一站式支撑尤其适合缺少完整毕设工程与文档的开发者对照学习。1. 家政服务管理小程序毕业设计难点不在写代码而在让五个进程各就各位如果你正对着“家政服务管理小程序-毕业设计基于微信小程序SSMVueMySql开发前后端分离”这个标题找落地路径先把风险值降下来这套组合的难点从来不在“写代码”而在让五个东西在同一台电脑上各就各位——微信开发者工具、后端Tomcat、MySQL实例、Vue后台管理端以及它们之间的网络连接。标题里的技术栈是毕业设计最常见的配方小程序给用户下单Vue后台给管理员接单派单SSM只提供JSON接口MySQL负责收口状态。这就是典型的前后端分离项目实战但比纯网页项目多了一道微信侧的联调门槛。本文面向两类人一类是要在答辩前半个月把项目跑起来、把论文写出来的本科生另一类是已经能写CRUD但想搞明白这套演示闭环里哪些配置在拖后腿的开发初学者。2. 架构先立住微信小程序 SSM Vue 的职责边界以及 MySQL 里那张订单表怎么建2.1 前后端分离的真正边界谁面向用户谁面向管理员谁只提供 JSON很多第一次做前后端分离的人会把“小程序里用 Vue 写页面”当成默认选项这是标题最容易误导人的地方。实际这套组合里的 Vue 不是跑在小程序里的而是用来做后台管理端的。小程序端负责用户能看到的那一面浏览服务、下单、支付、查订单Vue 管理端负责家政公司能看到的那一面接单、派单、改状态。两者共用同一套 SSM 接口。微信小程序本身是原生框架页面用 WXML WXSS JS 写它和 Vue 的模板语法确实有点像但运行环境完全不同不要试图在小程序里 import Vue。Vue 后台是单独的 Web 工程跑在浏览器里。这一层边界想清楚论文里的系统架构图也就顺了。三个端的关系可以概括成一张表写论文或者做开题答辩时能直接讲明白端技术职责典型页面用户端微信小程序原生浏览服务、下单、支付、评价首页服务列表、订单详情管理端Vue Element UI接单、派单、管理服务项目订单管理、服务分类管理服务端SSMSpring SpringMVC MyBatis只返回 JSON不渲染页面/api/order/create、/api/service/list后端“只提供 JSON”这句话是前后端分离的核心。 SSM 工程里不应该再有 JSP 或者 Thymeleaf 页面Controller 方法统一加 ResponseBody返回结构是固定的 {code, message, data}。小程序端和 Vue 端拿到同样的结构各自去渲染这才是分离的意义。2.2 为什么是 SSM 而不是 Spring Boot论文好写、依赖直观、排查链路短按当前的主流新项目几乎都直接上 Spring Boot但毕业设计题目列的是 SSM这其实不是坏事。SSM 的配置是显式的web.xml、spring-mvc.xml、mybatis-config.xml 各管一摊论文里“系统实现”那一章可以拆得很细每层一个 XML 文件讲一段结构越清晰反而越好写。相比之下 Spring Boot 大量自动配置跑起来快但论文里能写的东西少答辩被问“自动配置怎么生效的”时容易卡壳。SSM 的代价是初始化链条长。从 Tomcat 启动到一次请求进来经历 listener 加载 Spring 容器、DispatcherServlet 初始化、HandlerMapping 匹配、Controller 执行、Service 注入、Mapper 代理生成、连接池取连接。任何一环配错现象都是 404 或者 500而且报错日志往往指向 Tomcat 而不是你的代码新手容易在这上面耗半天。我的建议是如果题目允许换 Spring Boot换掉能省一天时间如果题目锁死 SSM就用 Maven 的 war 包方式部署不要用 IDE 内置 Tomcat 的“热部署”方式那会掩盖很多配置问题。2.3 家政业务的数据底座六张核心表与订单状态机的状态点家政服务管理小程序的数据模型比普通电商多一个维度服务不是实物商品它绑定了时间、地点和服务人员。所以订单表不能只存商品 ID 和数量还要存预约时间、服务地址和状态流转。常规做法是拆成六张表用户表 user、服务分类表 category、服务项目表 item、订单表 order_info、地址表 address、评价表 comment。其中 order_info 是核心它决定了整个演示闭环讲不讲得通。订单状态机建议只设五个状态点0 待支付、1 待接单、2 服务中、3 待评价、4 已完成、5 已取消。状态流是 0→1→2→3→4取消只能从 0 或 1 发生2 之后不允许取消。这个限制要在 Service 层做校验不能靠前端按钮隐藏来防。因为小程序端请求可以直接被构造绕过了界面就是绕过校验。状态机设计好了后续做后端接口、做演示预置数据都顺。2.4 建库建表 SQL 和两条容易忽略的 MySQL 参数数据库命名直接用 home_service_db表名字段名统一小写加下划线避免不同 OS 下大小写问题。下面是订单表和用户表的建表语句字段数量按毕设最小可用集设计不用过度设计CREATE DATABASE IF NOT EXISTS home_service_db DEFAULT CHARACTER SET utf8mb4; USE home_service_db; CREATE TABLE user ( id INT NOT NULL AUTO_INCREMENT, openid VARCHAR(64) NOT NULL COMMENT 微信openid唯一, nickname VARCHAR(50) DEFAULT , phone VARCHAR(20) DEFAULT , create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE order_info ( id INT NOT NULL AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL COMMENT 业务订单号, user_id INT NOT NULL, item_id INT NOT NULL, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待支付 1待接单 2服务中 3待评价 4已完成 5已取消, appoint_time DATETIME DEFAULT NULL COMMENT 预约上门时间, address VARCHAR(255) DEFAULT NULL, amount DECIMAL(10,2) DEFAULT 0.00, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_user_id (user_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;字段注释直接写进 DDL后面写论文画表格时能少绕弯路。order_no 用业务唯一键而不是 id是为了演示时给用户看“订单号”而不是自增主键更贴近真实。status 用 TINYINT 存数字不要存字符串这样状态机比较大小、扩展状态点都方便。注意 openid 必须加唯一索引一个微信号只能对应一个账号。建完库之后有两处 MySQL 参数值得提前调整。第一是 sql_modeMySQL 5.7 默认带 ONLY_FULL_GROUP_BY执行 GROUP BY 查询时如果 select 的字段不在 group by 里就会报错很多网上抄来的统计 SQL 直接跑不通可以在 my.ini 里把 sql_mode 改掉或者用 ANY_VALUE() 包一下字段。第二是 wait_timeout默认 8 小时Wi-Fi 环境下 MySQL 如果被系统休眠挂起第一次请求会卡十几秒才重连。这也是后面联调阶段最常见的翻车现场之一提前把连接池和 wait_timeout 的关系弄清楚能省很多排查时间。3. 微信小程序端从 app.json 到可下单首页的最小闭环3.1 项目骨架与底部 TabBar先让页面能翻得过去小程序端的第一步不是写页面而是把 project.config.json 和 app.json 配明白。直接用微信开发者工具新建一个“小程序”项目AppID 可以先用测试号等你要真机预览时再换自己注册的 AppID。app.json 里 pages 数组的第一项就是启动页这里容易踩坑如果想默认进首页就要把 index 放最前面而不是按目录顺序排。{ pages: [ pages/index/index, pages/category/category, pages/order/order, pages/user/user ], window: { navigationBarTitleText: 家政服务, navigationBarBackgroundColor: #1296db, navigationBarTextStyle: white }, tabBar: { color: #999999, selectedColor: #1296db, list: [ { pagePath: pages/index/index, text: 首页 }, { pagePath: pages/category/category, text: 分类 }, { pagePath: pages/order/order, text: 订单 }, { pagePath: pages/user/user, text: 我的 } ] } }这段配置里两个要点。tabBar 的 pagePath 必须同时存在于 pages 数组里否则开发者工具会直接报错。navigationBarTextStyle 只支持 black 和 white 两个值写其他颜色会被忽略。如果你想让首页有搜索框、需要自定义顶部导航就要在对应页面的 json 里单独配 navigationStyle: custom这个我们放在 3.3 节讲。先按默认导航跑通骨架是最稳妥的顺序。3.2 登录获取手机号getPhoneNumber 的 code 只能用一次微信小程序登录获取手机号是整套演示里最容易紧张的一环因为后端接口有没有写好你暂时还没法验证而前端这里一旦写错日志又不容易看明白。小程序登录涉及两个不同的 codewx.login 返回的 code 用来换 openid这是账号体系的基础getPhoneNumber 按钮返回的 code 用来换手机号它是一次性的同一个 code 只能调一次后端接口重复调用必然报错。// pages/user/user.js Page({ onLoad() { this.login(); }, login() { wx.login({ success: (res) { if (res.code) { wx.request({ url: http://127.0.0.1:8080/api/user/login, method: POST, data: { code: res.code }, success: (resp) { if (resp.data.code 200) { wx.setStorageSync(token, resp.data.data.token); } } }); } } }); }, onGetPhone(e) { // e.detail.code 只能用一次 wx.request({ url: http://127.0.0.1:8080/api/user/phone, method: POST, data: { code: e.detail.code }, success: (resp) { if (resp.data.code 200) { wx.setStorageSync(phone, resp.data.data.phone); } } }); } });这里的顺序是先用 wx.login 建立会话、拿 token用户点“微信一键登录”按钮时才去拿手机号。不要把换手机号放在 onLoad 里自动执行因为 getPhoneNumber 必须由用户点击按钮触发否则 detail.code 拿不到。注意 request 的 url 里现在写的是 127.0.0.1这只是让逻辑先跑通后面真机预览时必须改成局域网 IP否则手机会连不到你电脑上的 Tomcat这一点第 5 章专门讲。3.3 顶部导航栏高度与安全区自定义导航的第一道坎一旦页面要做顶部搜索框或者希望导航栏跟品牌色更融合你就要把“微信小程序顶部导航栏高度”这件事算明白否则做出来的页面在刘海屏上会直接撞进状态栏。默认导航栏是系统帮你算好的自定义导航栏则要自己处理状态栏高度和胶囊按钮位置。胶囊按钮是右上角那个圆形胶囊它和小程序页面内容之间的相对位置在不同手机上不一样所以必须动态获取。// utils/navbar.js function getNavbarHeight() { const menu wx.getMenuButtonBoundingClientRect(); const sys wx.getSystemInfoSync(); const statusBarHeight sys.statusBarHeight || 44; // 胶囊按钮垂直居中上下留白距离相等 const marginTop menu.top - statusBarHeight; const navHeight statusBarHeight menu.height marginTop * 2; return { statusBarHeight, navHeight, menu }; } module.exports { getNavbarHeight };计算逻辑的直观理解是导航栏整体高度 状态栏高度 胶囊按钮上下留白 胶囊按钮高度。因为胶囊按钮在导航栏里是垂直居中的所以它上方留白等于下方留白于是 menu.top - statusBarHeight 就是上方留白乘 2 把上下都算上。这套公式在 iPhone X 以后的全面屏和普通屏上都适用。如果页面是自定义导航推荐在页面的 data 里初始化这套值然后给导航 view 设置 padding-top: statusBarHeight 和 height: navHeight再在页面 json 里确认开的是 navigationStyle: custom顺序不能反先配 json 再写代码。3.4 首页服务列表与下单把 wx.request 封装成全项目唯一入口小程序端如果每个页面都直接写 wx.request后面换 baseURL、加 token 就要全局搜着改。常见做法是在 utils/request.js 里封装一个 Promise 版的请求函数所有页面都用它。封装之后后端返回的 {code, message, data} 结构也统一在这里解开页面代码只需要关心业务数据。// utils/request.js const BASE_URL http://127.0.0.1:8080/api; function request(url, method, data) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL url, method: method || GET, data: data || {}, header: { Content-Type: application/json }, success(res) { if (res.statusCode 200 res.data.code 200) { resolve(res.data.data); } else { reject(res.data); } }, fail(err) { reject(err); } }); }); } module.exports { request, BASE_URL };首页拿到服务列表渲染核心就是 onLoad 里调一次 GET 接口然后在 WXML 里用 wx:for 渲染卡片。下单则是在用户点“立即预约”时把 itemId、appointTime、address 三个字段 POST 给后端。这里有三件事必须做appointTime 不要传字符串就完事要统一格式为 yyyy-MM-dd HH:mm:ss否则后端解析 DateTime 会直接 400address 要么让用户从地址表选、要么让用户手动填不能在测试时写死否则订单详情页演示出来很假POST 的 header 里 Content-Type 必须是 application/json因为第四章后端接口用 RequestBody 接收如果漏了会报“Required request body is missing”。首页能渲染出服务列表、点击能调到下单页小程序端的“最小闭环”就算打通了。4. 后端 SSM 接口工程把家政订单做成能测试的 REST API4.1 SSM 工程怎么搭依赖、web.xml 与三层代码的顺序后端工程建议用 Maven 打成 war 包结构是标准的 Controller-Service-Mapper 三层。Controller 负责参数接收和结果包装Service 负责业务规则和事务Mapper 只跟数据库打交道。刚入门的人最容易把三者混在一起Controller 里写业务判断、Mapper 里写复杂逻辑、Service 形同虚设这样的代码跑起来确实能用但论文里没法写成“三层架构”答辩也会被问倒。pom.xml 里核心依赖就五个spring-webmvc、mybatis、mybatis-spring、mysql-connector-java、druid。jackson-databind 也要加进去它是 SpringMVC 把 Controller 返回值序列化成 JSON 的关键很多人漏了它导致接口返回的不是 JSON 而是字符串。数据库连接池用 Druid配置里至少包含 initialSize、maxActive、minIdle 三个参数测试时 minIdle 不要设 0否则空闲久了 MySQL 断开后要重新建连接就是之前提过的“第一请求卡十几秒”。web.xml 里要注册两个核心组件ContextLoaderListener 负责启动 Spring 容器DispatcherServlet 负责拦截所有 /api 请求。spring-mvc.xml 里开mvc:annotation-driven /和组件扫描mybatis-config.xml 里配置驼峰映射setting namemapUnderscoreToCamelCase valuetrue/。这个 setting 很关键它让数据库里 update_time 自动映射成 Java 属性的 updateTime不然你得在每个 resultMap 里手写映射。三层结构里 Service 接口和实现类可以分开写也可以写成一个类毕设建议分开论文里能多画一张接口图。4.2 统一返回 Result 让 Vue 和小程序端都不再各自解析接口返回值一定要做统一包装否则小程序端要根据每个接口的怪癖去处理数据。这个包装类所有 Controller 都用所以它要写成泛型并且提供静态工厂方法。约定 code 200 表示成功400 表示参数错误401 表示未登录500 表示系统异常。实际业务异常用 code 400 message 描述不要把异常堆栈直接抛给前端。public class ResultT { private Integer code; private String message; private T data; public static T ResultT ok(T data) { ResultT r new Result(); r.code 200; r.message success; r.data data; return r; } public static T ResultT error(String message) { ResultT r new Result(); r.code 400; r.message message; return r; } // getter / setter 省略 }这个问题有一个边界要注意Result.ok 传入 null 时JSON 序列化结果是data: null还是直接不包含 data 字段取决于 Jackson 的配置。小程序端的 request.js 里我们取了 res.data.data如果 data 字段缺失会得到 undefined页面容易报错。所以要么在 spring-mvc.xml 里配置 Jacksoninclude: ALWAYS要么约定后端返回 null 也包装成data: null。我一般会直接配置 Jackson 的 NON_NULL 为默认不忽略这样数据更可控。4.3 订单状态机Service 层加事务Mapper 层只做数据搬运订单创建接口是整套系统的核心演示点。Controller 层接收前端 POST 的 JSON 体Service 层先校验参数然后生成订单号、插入订单记录最后返回订单号给前端。这里最容易犯的错是Controller 里直接调用 mapper 插入数据。一旦后面要加“下单同时扣库存”“下单同时生成支付流水”这类多表操作没有 Service 层兜底事务就会出现一边成功一边失败的脏数据。Service public class OrderServiceImpl implements OrderService { Autowired private OrderMapper orderMapper; Transactional(rollbackFor Exception.class) Override public String createOrder(OrderCreateDTO dto) { // 1. 校验必填参数 if (dto.getItemId() null || dto.getAppointTime() null) { throw new BusinessException(服务项目和预约时间不能为空); } // 2. 生成唯一订单号时间戳 随机数 String orderNo H System.currentTimeMillis() String.valueOf((int) (Math.random() * 900) 100); // 3. 插入订单状态默认为 0 待支付 OrderDO order new OrderDO(); order.setOrderNo(orderNo); order.setItemId(dto.getItemId()); order.setAppointTime(dto.getAppointTime()); order.setAddress(dto.getAddress()); order.setStatus(0); orderMapper.insert(order); return orderNo; } }Transactional(rollbackFor Exception.class) 必须写 rollbackFor。Spring 默认只在抛出 RuntimeException 时回滚事务如果你业务里抛的是受检异常比如 IOException事务不会回滚数据就悄悄写进去了。这是事务注解里最经典的坑。状态流转时也建议加一个“期望状态”条件比如把订单从 0 改成 1update 语句要带 AND status 0这样并发情况下两个请求同时操作同一单只有一个能成功相当于用行级锁做乐观控制。这里不用上升到复杂分布式理论但能让答辩老师看到你有并发意识。4.4 MyBatis 动态 SQL排序字段与更常见的边界MyBatis 的 XML 是这一章里篇幅最大、最容易写错的地方。订单列表是个高频接口Vue 后台和小程序端都要用区别在于后台要分页、要支持按状态筛选小程序端只查当前用户的订单。两个接口可以共用同一个 Mapper 方法用动态 SQL 控制 WHERE 条件。这里有个小白必踩的坑前端传排序字段时ORDER BY 后面不能直接用#{}因为预编译占位符只能用在值的位置用在 ORDER BY 或表名上会直接报错。select idpageList resultTypecom.demo.entity.OrderDO SELECT id, order_no, user_id, item_id, status, appoint_time, address, amount, create_time, update_time FROM order_info where if testuserId ! null AND user_id #{userId} /if if teststatus ! null AND status #{status} /if /where choose when testorderBy amount ORDER BY amount ${orderDir} /when otherwise ORDER BY create_time DESC /otherwise /choose LIMIT #{offset}, #{pageSize} /select注意这里 orderDir 用的是${}因为方向 asc/desc 不是预编译占位符能处理的。用了${}就有 SQL 注入面所以必须在 Java 层做白名单校验只允许传 asc 或 desc其他一律按默认处理。排序字段本身也要白名单字段名不允许前端随便传。另外 MySQL 的 LIMIT 分页建议至少给 user_id 建索引否则订单量上来之后深分页会越来越慢这属于 MySQL 排序和分页的基础素养答辩时被问“订单多了怎么办”可以用这个顶住。5. 联调与避坑前后端拧成 demo 前必须处理的五处翻车现场5.1 本地联调最小配置域名校验、局域网 IP 与 Tomcat 端口前后端都写完进入联调阶段时很多人会在这里耗掉比写代码更多的时间。先明确一个事实小程序开发工具里跑通不等于手机里能跑通。开发工具里可以用 127.0.0.1 直连本机 Tomcat因为工具就跑在你电脑上手机预览时手机访问不到你电脑的 127.0.0.1必须把 BASE_URL 换成电脑在局域网里的 IP。比如电脑 IP 是 192.168.1.10那小程序端 request.js 里的 BASE_URL 就要改成http://192.168.1.10:8080/api并且保证手机和电脑在同一个 Wi-Fi 下。第二个拦路虎就是微信的域名校验。开发工具里默认会校验 request 合法域名本地调试时要打开“不校验合法域名”开关详情 → 本地设置 → 勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。这个开关只对开发工具和“预览”模式生效正式上线必须配 HTTPS 域名但毕业设计演示到预览这一步就够。手机上预览时还要在微信开发者工具的“真机调试”模式下操作不要直接扫“预览”二维码期待所有功能都正常。# 确认 Tomcat 已经启动并监听 8080 端口 netstat -ano | findstr :8080 # 如果是 Linux / macOS lsof -i :8080端口检查是联调第一动作。Tomcat 默认 8080如果本机 8080 被其他进程占用了要在 tomcat/conf/server.xml 里改 Connector 端口改成 8081 或 9090然后同步修改前端 BASE_URL。之前见过一个同学本机 8080 被某个服务占着Tomcat 启动日志滚动得飞快但 curl 接口却连不上他花了一晚上查代码最后发现是端口冲突这种玄学问题值得先检查。5.2 五条踩坑记录现象、原因、解决按这个顺序排查第一坑小程序请求后端开发工具 console 报“request:fail”。现象是请求没发出或立刻失败Network 面板里看不到任何响应。原因是 url 写成了 127.0.0.1 但开发者工具运行环境里 127.0.0.1 指向工具自身不是你的电脑也可能是“不校验合法域名”没打开。解决确认开关打开BASE_URL 改为电脑局域网 IP再不行就用开发者工具自带的“清缓存 → 清除网络缓存”重试。第二坑自定义导航栏在 iPhone 上文字“撞进”状态栏。现象是导航标题顶部被刘海挡住一部分。原因是导航栏高度写死成了 44px没有计算状态栏高度和胶囊按钮位置。解决用 3.3 节那段 getNavbarHeight 动态计算navigationStyle 必须设置为 custom并且页面内容的最外层 view 加上充足的 padding-top。第三坑第一次请求接口卡了十几秒才返回之后又正常。现象是 Tomcat 日志里能看到请求进来但响应延迟很大。原因是 MySQL wait_timeout 8 小时把空闲连接断了Druid 连接池里的旧连接未剔除第一次取连接时还拿着废连接去查库失败重试后才重建。解决Druid 配置里加 testWhileIdletruevalidationQuerySELECT 1timeBetweenEvictionRunsMillis 设为 60000让连接池定期探活。这就是绝大多数“系统偶尔慢一次”的根源。第四坑下单成功但订单列表查不到刚下的单。现象是订单详情页能看到列表页没有。原因是 Service 方法加了事务但没提交或者 MyBatis 二级缓存没刷新更多时候是查询接口 statestatus 只查了某个状态而下单默认 status0列表页筛选条件默认查了 status4。解决先在 Navicat 里看 order_info 表数据是否存在存在就是查询条件问题不存在查事务。把数据和代码分开排查别一上来就改代码。第五坑更新接口把 phone 字段更新成 NULL。现象是用户改了昵称结果手机号没了。原因是 MyBatis 的 update 语句用了set里固定if testphone ! null但前端把 phone 传成了空字符串字符串不等于 null 从而进入更新分支。解决判断条件改成phone ! null and phone ! 同时前端提交前做一次 trim。这个坑在 Vue 后台的表单提交场景里尤其常见因为 Element UI 的表单空值默认是空字符串而不是 null。5.3 如果 MySQL 装在 Docker 或远程 Windows连接串里的三点改法有些同学的数据库不是本机装的而是 Docker 容器里的 MySQL或者实验室远程 Windows 机器上装的 MySQL。这两种场景下SSM 的 JDBC 连接串写法有讲究。jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://192.168.1.20:3306/home_service_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password123456第一url 里的主机 IP 要改成 MySQL 所在机器的局域网 IP不能再写 localhost。第二Docker 容器里的 MySQL 必须做端口映射启动容器时加-p 3306:3306否则宿主机访问不到容器里的 3306。第三MySQL 8.0 的驱动类名是 com.mysql.cj.jdbc.Driver跟 5.7 的 com.mysql.jdbc.Driver 不一样如果用 8.0 却写老驱动名会直接 ClassNotFoundException。另外 serverTimezoneAsia/Shanghai 建议保留不当时区可能相差八小时订单里显示的时间全是错的。这些细节看起来不起眼却是联调阶段最常见的返工来源。6. 给答辩加分的验证技巧用预置数据把订单全链路跑出节奏演示最忌讳的是现场从零开始造数据那会暴露太多不可控因素。正确做法是在答辩前准备好一组覆盖所有状态节点的预置数据演示时按状态流一步一步点过去。建议准备四个订单一个待支付、一个待接单、一个服务中、一个已完成每个订单的金额、服务项目、预约时间都要逼真比如“3月15日 14:00 日常保洁 129.00”。预置数据可以用 SQL 脚本一次插进去INSERT INTO order_info (order_no, user_id, item_id, status, appoint_time, address, amount) VALUES (H20240615001, 1, 2, 0, 2024-06-16 14:00:00, 幸福小区 8-201, 129.00), (H20240615002, 1, 3, 1, 2024-06-16 15:00:00, 阳光花园 3-502, 89.00), (H20240615003, 1, 5, 3, 2024-06-17 09:00:00, 滨江公寓 2-1101, 199.00);演示时的操作顺序也很重要。先在小程序端走一遍完整的用户视角登录 → 首页浏览服务 → 选一个服务下单 → 看到订单状态变成待支付 → 点击支付逻辑模拟 → 状态变成待接单。然后切到 Vue 后台管理员看到待接单订单 → 接单 → 状态变服务中 → 再改已完成。期间把开发者工具的 Network 面板留在屏幕上指一下每个请求的响应时间让答辩老师看到前端确实在调后端接口而不是各演各的。最后用一个已完成订单落到“评价”页面把评价接口也演示一遍整个业务闭环就完整了。我的个人习惯是演示前一晚一定重新做一次“清空整个流程”的演练清小程序缓存、重启 Tomcat、用 SQL 把订单状态重置回初始值再全流程走一遍。因为开发过程中一定会在代码里写死过一些 token、写死过某个订单号这些黑匣子只在当时的上下文里好用清缓存之后立刻就暴露。第一次录演示视频时我就因为忘了关开发者工具的“不校验合法域名”开关导致手机端预览后所有请求全部失败这血泪体验至今记得。提前把预置数据、状态节点、Network 面板都准备好现场就不会慌。希望这篇能帮你的毕业设计少走几段弯路把真实的联调细节做好答辩时心里有底。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?