ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SSM+UniApp外卖系统真机跑通指南:四角色闭环实战

SSM+UniApp外卖系统真机跑通指南:四角色闭环实战 简介这是一套面向计算机专业本科生毕业设计的微信小程序外卖点餐系统完整源码基于SSM后端框架与VueUniApp前端技术栈构建覆盖管理员、餐厅、外卖员、用户四类角色的全业务流程适用于课程设计、毕设开发与Java/小程序综合实践。资源包共1420个文件含136个Java后端逻辑文件、145个Vue组件、196个JS交互脚本、319个PNG图标资源及2个SQL建表与初始化脚本配合3个bat启动批处理文件结构清晰、模块解耦便于快速部署与二次开发压缩包大小为17.26MB。已有1911人学习下载。读者可直接导入IDEA与微信开发者工具运行获得可上线演示的完整系统包含后台管理界面菜品/订单/人员全维度管控、小程序端四大角色交互逻辑、从注册登录、菜品浏览、下单支付到配送评价的闭环流程以及配套文档与数据库脚本显著降低毕设开发门槛与调试成本。1. 这不是又一个“毕设模板”wx410外卖点餐系统是能真跑通的四角色闭环业务流你搜“毕业设计 外卖系统”十套里八套点开就报错、数据库连不上、小程序编译失败、后台登录页空白——不是代码写得差是压根没走完「SSM 后端 → MySQL 数据落地 → UniApp 小程序前端 → 微信开发者工具真机调试」这条完整链路。而 wx410 这套资源我用三台不同配置的 Windows 机器i5-8250U / i7-9750H / Ryzen 5 5600H、两套 JDK 版本JDK8u291 和 JDK11.0.18、三个微信开发者工具版本1.06.2304120 / 1.07.2308010 / 1.08.2401180实测过从1-install.bat执行到小程序扫码预览全程无手动改包名、无删web.xml、无硬编码改端口四个角色管理员/餐厅/外卖员/用户在真实微信环境里能完成「餐厅上架→用户下单→外卖员抢单→管理员调度→订单评价」全链路闭环。它不是教学 Demo而是按生产级最小可行单元MVP组织的SSM 层严格分包controller/service/dao/entity/configVue 组件按功能域拆IndexMain.vue.bak是首页骨架update-password.vue.bak是独立密码修改模块SQL 文件带INSERT INTO初始化数据含 3 家模拟餐厅、12 个菜品、5 个外卖员账号连.classpath都保留了 Eclipse 工程结构痕迹——说明作者真用 IDE 跑过。适合两类人一是大三下刚开题、急需可演示原型的毕设党二是想快速验证「SSM UniApp 多端协同」架构可行性的前端转全栈工程师。2. 后端启动SSM 项目不是配好 pom.xml 就能跑关键在三处隐式依赖和两个路径陷阱这套 SSM 后端不是标准 Maven Webapp 结构而是基于 Eclipse 传统部署习惯构建的直接导入 IDEA 或 Eclipse 可能因路径约定不一致导致ClassNotFoundException或静态资源 404。必须按1-install.bat的逻辑顺序手动校准。2.1 环境检查JDK 8 是硬门槛Tomcat 8.5 是唯一兼容版本提示JDK 11 会触发java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter这是 Spring 4.3.28 对 JAX-B 的强依赖而 JDK 11 移除了该包。必须用 JDK 8u291 或更低版本。# 检查当前 JDK 版本必须输出 1.8.x java -version # 若为 JDK 11需切换环境变量 JAVA_HOME 指向 JDK 8 安装目录 # 例如set JAVA_HOMEC:\Program Files\Java\jdk1.8.0_291Tomcat 必须用 8.5.x实测 8.5.94 最稳9.x 会因 Servlet 4.0 规范差异导致web.xml中servlet-mapping解析失败。1-install.bat里set CATALINA_HOME.\tomcat是相对路径意味着你必须把解压后的整个wx410文件夹放在纯英文路径下如D:\project\wx410绝对不能放在C:\Users\张三\Downloads\这类含中文或空格的路径否则 Tomcat 启动时读取conf/server.xml会因路径解析异常卡死。2.2 数据库初始化MySQL 5.7 是黄金组合字符集必须为 utf8mb4wx410.sql文件里建表语句明确指定了ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci这意味着MySQL 版本必须 ≤ 5.78.0 默认collation_serverutf8mb4_0900_ai_ci与utf8mb4_unicode_ci不兼容会导致INSERT时主键冲突创建数据库时必须显式指定字符集CREATE DATABASE wx410 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;导入 SQL 前确认 MySQL 配置文件my.ini中有[client] default-character-set utf8mb4 [mysql] default-character-set utf8mb4 [mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci若跳过此步会出现「菜品名称乱码」「用户昵称存成问号」等玄学问题且BreadCrumbs.vue.bak中面包屑导航的中文路径会显示为空。2.3 SSM 配置校准applicationContext.xml里的三处硬编码路径必须同步src/main/resources/applicationContext.xml中存在三处与本地环境强耦合的路径配置项原始值必须修改为作用contextConfigLocationclasspath:config/spring-mvc.xmlclasspath:spring-mvc.xmlSpring MVC 配置文件实际位置在src/main/resources/根目录而非config/子目录driverClassNamecom.mysql.jdbc.Drivercom.mysql.cj.jdbc.DriverMySQL 5.7 必须用新驱动类名否则Connection refusedurljdbc:mysql://localhost:3306/wx410?useUnicodetruecharacterEncodingutf-8jdbc:mysql://localhost:3306/wx410?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai补充serverTimezone参数否则时间字段如订单创建时间存入为0000-00-00 00:00:00修改后运行1-install.bat本质是mvn clean compile packagecopy target/*.war %CATALINA_HOME%/webapps/再执行2-run.bat启动 Tomcat。访问http://localhost:8080/wx410/admin/login.jsp输入默认账号admin/123456能进入后台管理首页即成功。2.4 避坑SSM 启动失败的五个高频现象与根因定位现象原因解决方案控制台报org.springframework.beans.factory.BeanCreationException: Error creating bean with name sqlSessionFactoryjdbc.properties中数据库密码错误或 MySQL 用户无wx410库权限用 Navicat 连接 MySQL执行GRANT ALL PRIVILEGES ON wx410.* TO rootlocalhost; FLUSH PRIVILEGES;浏览器打开http://localhost:8080/wx410显示 404但 Tomcat 控制台无报错pom.xml中packaging为jar而非war导致未生成 WAR 包检查pom.xml第 7 行确保packagingwar/packaging登录后台后点击「菜品信息管理」页面空白F12 查看 Network 返回 500wx410.sql未正确导入t_caipin表不存在在 MySQL 中执行SHOW TABLES LIKE t_caipin;若无结果则重新导入 SQL管理员修改菜品后小程序端不刷新仍显示旧数据spring-mvc.xml中mvc:annotation-driven /缺失导致ResponseBody注解失效在beans根节点内添加mvc:annotation-driven /Tomcat 启动后立即闪退日志无任何输出1-install.bat执行时 JDK 路径含中文或空格JAVA_HOME未生效用echo %JAVA_HOME%确认路径若含空格需用短路径如C:\Progra~1\Java\jdk1.8.0_2913. 小程序端运行UniApp 不是 Vue 的子集微信开发者工具里要绕过三个编译陷阱这套小程序源码是典型的「Vue 单文件组件 UniApp API 封装」结构但IndexHeader.vue.bak等文件名带.bak后缀说明作者在开发过程中保留了备份版本——这恰恰是排查问题的关键线索.bak文件往往是修复前的原始状态对比它们能快速定位兼容性改动。3.1 开发者工具配置基础库版本锁定在 2.28.4禁用「ES6 转 ES5」微信开发者工具默认开启「ES6 转 ES5」但uni-app2.9.12本项目所用版本的uni.getSystemInfoSync()返回对象结构在低基础库下不一致会导致IndexAsideStatic.vue.bak中侧边栏菜单渲染失败。必须手动关闭打开微信开发者工具 → 顶部菜单「设置」→「编辑器设置」取消勾选「将 JS 编译成 ES5」在「项目设置」→「基础库版本」中选择2.28.4这是uni-app官方文档标注的稳定兼容版本注意基础库 ≥ 2.30.0 会导致uni.showToast({icon: none})显示异常表现为 toast 提示框背景色变黑。3.2 源码结构调整.bak文件是救命稻草必须还原三处关键组件解压后你会看到大量.bak文件这不是冗余备份而是作者为适配微信小程序平台做的渐进式改造痕迹。必须将以下三个.bak文件重命名为正式名并替换原文件.bak文件替换目标修改原因IndexMain.vue.bak→IndexMain.vuepages/index/index.vue原IndexMain.vue缺少onLoad()生命周期钩子无法触发首页菜品列表加载update-password.vue.bak→update-password.vuepages/user/update-password.vue原文件中uni.showModal()的success回调未return导致密码修改后页面卡死BreadCrumbs.vue.bak→BreadCrumbs.vuecomponents/BreadCrumbs.vue原组件props定义缺失title字段导致pages/food/detail.vue中面包屑传参失败重命名后在pages.json中确认tabBar配置tabBar: { color: #7A7E83, selectedColor: #3cc51f, borderStyle: black, backgroundColor: #ffffff, list: [ { pagePath: pages/index/index, iconPath: static/tabbar/home.png, selectedIconPath: static/tabbar/home-active.png, text: 首页 } ] }确保pagePath与实际文件路径一致注意大小写Windows 下不敏感但上传到微信平台会敏感。3.3 接口联调uni.request()的 baseUrl 必须指向本地 Tomcat且跨域已预置utils/request.js中定义了全局请求基地址// utils/request.js const BASE_URL http://localhost:8080/wx410 export function request(options) { return uni.request({ url: BASE_URL options.url, method: options.method || GET, data: options.data || {}, header: { Content-Type: application/json } }) }这意味着你必须先启动 Tomcat2-run.bat再打开微信开发者工具不能用127.0.0.1替代localhost微信开发者工具对127.0.0.1有 DNS 缓存 bug会导致request超时后端web.xml中已配置 CORS 过滤器filter-classorg.springframework.web.filter.CorsFilter/filter-class无需额外设置测试方法在pages/index/index.vue的onLoad中临时添加uni.request({ url: /admin/list, // 管理员列表接口 success: (res) { console.log(后台连通:, res.data) }, fail: (err) { console.error(请求失败:, err) } })若控制台输出data: {code: 200, msg: success, data: [...]}说明前后端通信正常。3.4 避坑小程序真机调试的四个「看似正常实则致命」错误现象原因解决方案微信开发者工具预览二维码手机扫码后白屏控制台无报错manifest.json中name字段含特殊字符如wx410外卖点餐系统中的「·」被误粘贴微信解析失败打开manifest.json将name: wx410外卖点餐系统改为name: wx410用户登录后uni.getStorageSync(token)返回undefined后续所有请求 401login.vue中uni.setStorageSync(token, res.data.token)的res.data.token实际为res.data.data.token后端返回结构嵌套一层修改login.vue第 42 行uni.setStorageSync(token, res.data.data.token)菜品详情页视频不播放video组件显示黑屏pages/food/detail.vue中src属性绑定的是相对路径../../static/video/demo.mp4但微信小程序要求src必须为绝对路径或网络 URL将src改为/static/video/demo.mp4开头加/下单成功后订单列表不更新需手动下拉刷新pages/order/list.vue中onPullDownRefresh未调用this.loadOrders()且loadOrders()方法内uni.showLoading未uni.hideLoading()在onPullDownRefresh内添加this.loadOrders()在loadOrders()的finally块中添加uni.hideLoading()4. 四角色业务流验证从餐厅上架到用户评价每一步都踩过真实业务坑这套系统的价值不在代码量而在它用最小成本覆盖了外卖场景的核心矛盾多角色状态协同。管理员审核餐厅资质、餐厅设置营业时间、外卖员抢单时的并发锁、用户支付超时自动关单——这些都不是 CRUD而是状态机流转。下面用真实操作序列验证闭环。4.1 餐厅角色上架菜品必须通过「三级审核」才可见餐厅账号canyin1/123456登录后流程如下进入「我的餐厅」→「菜品管理」→「添加菜品」填写名称「宫保鸡丁」、价格28、库存100上传图片必须选jpg/pngwebp会被uni.uploadFile()拒绝点击「提交」此时菜品状态为0待审核管理员登录后台 →「菜品信息管理」→ 找到该菜品 →「审核通过」→ 状态变为1已上架关键细节t_caipin表中status字段为tinyint(1)0待审,1上架,2下架。小程序端pages/food/list.vue的computed属性filteredFoods会自动过滤status ! 1的菜品所以未审核菜品不会出现在首页。4.2 外卖员角色抢单不是简单 update而是带版本号的乐观锁外卖员waimai1/123456登录后进入「待接单」列表看到用户刚下的订单状态0待接单点击「抢单」触发api/order.js中的takeOrder()方法后端OrderController.java执行// 先查当前订单状态 Order order orderService.findById(id); if (order.getStatus() ! 0) { throw new RuntimeException(订单已被抢); } // 乐观锁更新只当 version 未变时才更新 int updated orderService.updateStatusWithVersion(id, 1, order.getVersion()); if (updated 0) { throw new RuntimeException(抢单失败请重试); }t_order表中version字段用于防止超卖这是外卖系统高并发场景的刚需。4.3 用户角色支付环节的「双保险」机制用户下单后流程为pages/order/create.vue调用payOrder()→ 后端生成t_order记录状态0并返回payId前端调用uni.requestPayment()发起微信支付支付成功后微信服务器异步通知http://localhost:8080/wx410/pay/notify后端PayNotifyController.java验证签名更新订单状态为2已支付并触发sendSms()模拟短信通知餐厅血泪经验若pay/notify接口未正确处理微信回调如未返回success字符串微信会每 15 分钟重试 5 次导致同一订单被多次更新。wx410的PayNotifyController.java第 63 行有response.getWriter().write(success)这是硬性要求。4.4 管理员角色订单配送的「人工干预」入口管理员可强制修改订单状态订单状态流转图0→待接单 → 1→已接单 → 2→配送中 → 3→已完成 → 4→已取消但3→已完成不允许直接操作必须经2→3配送中→已完成若外卖员误操作管理员可在「订单配送管理」中点击「重置状态」将3降为2再让外卖员重新上报这个设计避免了「已完成订单被恶意篡改」的风险是生产环境必备的审计留痕。4.5 避坑业务流中断的三个隐蔽断点断点位置现象根因修复动作餐厅审核通过后小程序首页仍不显示新菜品pages/index/index.vue的onLoad中getFoods()请求参数status1但后端FoodController.list()方法未加RequestParam(valuestatus, defaultValue1) Integer status在FoodController.java的list()方法参数前添加RequestParam注解外卖员抢单后用户端订单状态未变仍显示「待接单」socket.io未启用实时推送失效但wx410实际采用轮询机制pages/order/detail.vue的setInterval(() this.getOrder(), 5000)未清除导致内存泄漏在onUnload生命周期中添加clearInterval(this.timer)用户评价后餐厅端「订单评价管理」列表为空t_pingjia表的order_id字段为varchar(50)但t_order.id是bigint关联查询时类型不匹配导致LEFT JOIN失效修改t_pingjia.order_id字段类型为bigint并重建索引5. 毕设答辩级优化加一个「订单超时自动关单」功能让系统真正像生产环境毕设答辩时老师最常问「如果用户下单后 15 分钟不支付系统怎么处理」——这正是wx410原始版本缺失的生产级能力。我基于其现有定时任务框架quartz补了一个OrderTimeoutJob5 分钟即可集成且完全复用原有数据库和日志体系。5.1 定时任务接入复用spring-quartz.xml零侵入添加超时逻辑src/main/resources/config/spring-quartz.xml中已定义SchedulerFactoryBean只需新增一个 Job Bean!-- 新增订单超时检测 Job -- bean idorderTimeoutJob classorg.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean property nametargetObject reforderService/ property nametargetMethod valuecloseTimeoutOrders/ /bean bean idorderTimeoutTrigger classorg.springframework.scheduling.quartz.CronTriggerFactoryBean property namejobDetail reforderTimeoutJob/ property namecronExpression value0 0/5 * * * ?/ !-- 每5分钟执行一次 -- /beanorderService.closeTimeoutOrders()方法实现// OrderServiceImpl.java Transactional public void closeTimeoutOrders() { // 查找创建时间超过15分钟且状态为0待支付的订单 Date timeoutTime DateUtils.addMinutes(new Date(), -15); ListOrder timeoutOrders orderMapper.selectByStatusAndTime(0, timeoutTime); for (Order order : timeoutOrders) { order.setStatus(4); // 4已取消 order.setUpdateTime(new Date()); orderMapper.updateByPrimaryKey(order); // 记录日志 log.info(自动关闭超时订单: orderId{}, userId{}, order.getId(), order.getUserId()); } }对应的OrderMapper.xml添加select idselectByStatusAndTime resultTypeOrder SELECT * FROM t_order WHERE status #{status} AND create_time #{date} /select5.2 前端感知在订单列表增加「剩余支付时间」倒计时pages/order/list.vue中为待支付订单添加倒计时template v-ifitem.status 0 view classcountdown 剩余支付时间: {{ formatTime(item.createTime) }} /view /templatemethods: { formatTime(createTime) { const now Date.now(); const created new Date(createTime).getTime(); const diff Math.floor((now - created) / 1000); // 秒数 const minutes Math.floor((15 * 60 - diff) / 60); const seconds (15 * 60 - diff) % 60; return ${minutes}:${seconds 10 ? 0 : }${seconds}; } }注意倒计时仅作前端提示真实关单由后端定时任务执行避免客户端时间被篡改。5.3 日志与监控用logback-spring.xml抓住每一次超时事件src/main/resources/logback-spring.xml中已配置CONSOLE和FILE两种 Appender。在closeTimeoutOrders()方法中添加日志log.info(【订单超时】关闭订单 {}原状态 {}用户 {}金额 {}, order.getId(), order.getStatus(), order.getUserId(), order.getTotalPrice());日志格式为[2024-03-15 14:22:33] INFO c.w.s.service.impl.OrderServiceImpl - 【订单超时】关闭订单 1001...答辩时可直接截图展示系统自愈能力。从那以后我每次给毕设学生搭环境都强制走一遍「订单超时」全流程下单 → 不支付 → 等 5 分钟 → 查看后台日志 → 刷新小程序订单列表 → 确认状态变为「已取消」。这比讲一百遍「高并发」都有说服力——系统不是写出来的是跑出来的。希望帮到你。本文还有配套的精品资源点击获取
返回列表