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

资讯详情

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

微信小程序扫码点餐系统实战:uni-app+SpringBoot+Vue完整方案

微信小程序扫码点餐系统实战:uni-app+SpringBoot+Vue完整方案 简介这是一套面向计算机专业本科生毕业设计的微信小程序扫码点餐系统完整工程涵盖用户端uni-app、管理端Vue与后端服务SpringBoot解决中小型餐饮门店数字化点餐、订单管理与菜品可视化运营的实际需求。资源包共454个文件7.05MB包含59个Java后端业务类如Order、Dish、JwtUtils、19个Vue管理页面组件、45个JS逻辑脚本、112个XML配置与Mapper文件、27张JPG运营图及配套SQL、YML、JSON等配置资源结构清晰前后端分离明确便于理解全栈开发流程与权限控制实现。已有83人学习下载提供可直接运行的三端联动代码含扫码生成、订单状态流转、分类管理、JWT鉴权等核心模块适合作为毕设参考或全栈开发入门实践项目。 去年我帮本地一家餐饮连锁店落地了一套扫码点餐系统从需求梳理到正式上线前后折腾了一个多月。这段时间里踩过不少坑也沉淀了不少经验。今天把这套“微信小程序扫码点餐系统”的完整思路和实操细节整理成文涵盖uni-app小程序端、SpringBoot后端、Vue管理端三部分希望能给正准备做类似项目的朋友一些参考。这套系统解决的是餐饮门店最日常的痛点顾客扫码后自主看菜、加购、下单后台实时接单、管理菜品。门店不用再依赖纸质菜单反复更换前台也不用扯着嗓子喊单。整个过程降本增效很明显尤其在高峰期和疫情期间的无接触场景下价值非常突出。适合的人群也很明确——想快速落地扫码点餐需求的技术团队、接外包项目的开发者、以及餐饮行业里有一定技术基础的管理者。无论你是写前端还是后端这篇内容都可以直接拿来当项目蓝本。1. 项目整体架构与核心技术栈选型1.1 三端架构的职责划分与数据流这套系统从物理上分成三个端顾客使用的微信小程序端、商家使用的Vue管理端、以及支撑两端的SpringBoot后端服务。三端各司其职通过HTTP接口完成数据交换。小程序端负责扫码识别桌号、展示菜品、管理购物车、提交订单、发起支付管理端负责菜品上下架、订单状态处理、营业数据查看后端则统一处理业务逻辑、数据存储与第三方依赖如微信支付、消息推送。数据流大概是这样的顾客用微信扫桌子上的二维码小程序拿到桌号参数后进入点餐页面从后端拉取菜品分类和菜品列表加购和下单后订单数据写入数据库管理端轮询或通过WebSocket感知新订单商家在管理端操作订单状态状态变更再写回数据库小程序端通过查询接口刷新订单进度。这里有一个细节值得注意绝大多数扫码点餐系统不会用小程序实时监听订单状态而是采用“查询轮询”的方式因为实时推送需要维护长连接成本高、复杂度大对初创项目和中小门店来说性价比不高。还有一个比较关键的选型问题为什么后端只用SpringBoot而不额外引入微服务原因很简单——业务规模没到那个量级。一个单体应用配合好数据库索引和缓存完全能支撑单店过万日活的点餐场景。过度设计只会增加部署和运维成本这是我在大量外包项目中总结出的经验。如果你未来确实要扩展多门店SpringBoot单体可以先按模块拆分后面再平滑演进。1.2 为什么选uni-app而不是原生小程序市面上的扫码点餐小程序大多数是微信原生开发但我这次选择uni-app核心原因有三个第一uni-app基于Vue语法前端团队不需要额外学习WXML和WXSS上手成本极低第二它的跨端能力非常强同一套代码未来可以无损编译到支付宝小程序、百度小程序、H5甚至是App对多端业务拓展极为有利第三uni-app的生态插件丰富扫码、支付、地图、图表等常见功能都有成熟组件没必要从零造轮子。当然原生开发也有它的优势比如性能和微信API的深度契合。但对扫码点餐这类以列表展示和表单提交为主的轻交互场景uni-app的性能完全够用。真机实测中冷启动速度、页面切换流畅度都能达到正常商用标准。再说uni-app对微信小程序的兼容处理已经很成熟了像uni.scanCode这类常用API都是直接封装好的。需要留意的是uni-app虽然跨端方便但有些微信小程序特有的能力还是需要用条件编译来适配。我举一个实例微信小程序的button组件有open-typegetPhoneNumber这样的专属属性在编译到H5时就会失效。这种情况下代码中要用#ifdef MP-WEIXIN包裹否则会报警告甚至白屏。1.3 SpringBootVue管理端的分工逻辑管理端为什么单独用Vue写而不直接塞进小程序这个问题的答案很简单管理端的使用者是店员和老板他们的工作场景在电脑上需要看大屏、快速处理订单。小程序页面承载不了这么重的工作台也不方便多窗口操作。Vue生态成熟配合Element UI或Ant Design Vue这类组件库一周左右就能把管理后台的框架搭起来。SpringBoot和Vue的配合方式本质上是一个标准的前后端分离项目SpringBoot只提供RESTful APIVue通过Axios发送请求两者通过JSON通信。这里要特别强调一个点——前端必须处理好Token鉴权。我的做法是小程序登录后后端生成一个Token返回给前端前端存起来每次请求带上管理端则是账号密码登录后返回Token存储在Vuex和localStorage里路由前置守卫统一校验登录态。如果不做这一步你的接口就等于是裸奔任何人用curl就能拉走全部订单数据。2. 小程序端扫码进店与点餐主流程2.1 扫码带参进入页面scene参数与二维码约定扫码点餐的第一步是把桌号和店铺信息“塞”进二维码里。这里有一段比较容易被忽略的细节。微信小程序生成二维码有两种方式一种是wx.getQRCode生成小程序码另一种是普通的URL链接。我推荐使用小程序码因为它可以直接通过微信扫一扫打开使用体验更好。关键问题是参数怎么传。微信小程序码有一个限制scene参数最长只能32个可见字符。所以不能把太复杂的数据塞进去。我的做法是约定一个简单的编码规则scene001_002第一位是店铺ID第二位是桌号。解析时用decodeURIComponent解码一下再分割就能拿到对应的店铺和桌号。实际编码时通常还需要做一层映射比如把tableId映射成短编码避免直接在URL里暴露自增主键也算是一层基础的安全防护。伪代码如下// 小程序端扫码后处理 onLoad(options) { let scene decodeURIComponent(options.scene); let arr scene.split(_); if (arr.length 2) { this.shopId arr[0]; this.tableNo arr[1]; this.getDishList(); } }服务端生成小程序码时路径指向点餐页面scene字段按照上面的规则生成。这张码打印出来后贴在每张桌子上顾客微信一扫就自动跳转到对应店铺的对应桌号这一整套流程就是扫码点餐的入口。2.2 点餐页核心交互分类、购物车与库存点餐页的核心交互有三个模块左侧的菜品分类、右侧的菜品列表、底部的购物车栏。分类和菜品一般一次性从后端拉取没必要做成分页加载——因为一家中餐厅的菜品数量通常在一两百个左右一次性拉取反而能减少请求次数、提升操作流畅度。购物车的设计需要动点脑筋。很多人第一反应是做在服务端用户每点一次加购就发请求。这样做的缺点很明显网络延迟会严重影响点餐体验而且请求频繁会给后端造成无用压力。我的做法是把购物车保存在小程序本地用uni.setStorageSync存起来。顾客加购、减购、修改数量这些操作全部走本地状态只有在下单时才把最终数据一次性提交给后端。这样既快又稳而且彻底避免了下单时数据不一致的问题。库存的处理稍微复杂一点。对于未支付订单菜品数量不算实际占用库存但如果是线下门店一些限量菜品比如每日限定10份是需要提前扣减的。我的方案是限量菜在加购时前端先查一次库存如果剩余量不足则禁止加购下单成功后再真正扣减。扣减库存用数据库的乐观锁机制防止超卖。这个细节后面会详细说。2.3 提交订单与支付闭环的实现思路提交订单是用户操作链路的终点也是整个系统中业务逻辑最集中的一环。在小程序端用户点击“去结算”后需要把购物车里的菜品数据、桌号、备注、总金额一起打包发给后端。后端校验菜品是否仍然在售、库存是否充足、价格是否被篡改然后再正式创建订单。这里一定要做一件很多人会忽略的事情金额校验。小程序端展示的价格只是给用户看的后端必须根据菜品ID重新从数据库查询最新价格然后逐条计算订单总价。如果把前端传来的总金额直接入库那是非常危险的——恶意用户完全可以通过抓包修改金额用1分钱买到一份红烧肉。支付环节我接入的是微信支付JSAPI。流程大致是后端调用微信统一下单接口拿到预付单号前端用wx.requestPayment调起支付面板。支付成功后微信会异步回调后端接口后端收到回调后校验签名、确认金额再将订单状态更新为已支付。这一整套流程的时序关系必须理清楚支付结果不能完全依赖前端的成功回调必须以后端收到的微信回调为准。否则一旦微信回调因为网络问题延迟订单状态就可能会错乱。3. SpringBoot后端核心接口与业务实现3.1 项目结构与数据库设计后端我采用经典的分层架构Controller层接收请求、Service层处理业务逻辑、Mapper层操作数据库。模块上按业务域划分不按技术类型硬拆。比如点餐相关的接口统一放在order包下菜品相关放在dish包下这种组织方式比单一工具类堆砌更容易维护。数据库设计上核心表有这几张店铺表shop、菜品分类表category、菜品表dish、订单表orders、订单明细表order_detail、用户表member。这里重点说一下订单表的设计。订单表里除了常规的订单号、金额、状态外一定要冗余存储店铺ID和桌号字段。很多新人在设计时会纠结是否要关联查询店铺表和桌号表但从实际使用场景出发订单列表的查询频率极高冗余字段能避免大表关联显著提升查询速度。订单号我建议用时间戳加随机数的方式生成格式类似20241012103045234567包含年月日时分秒和随机位。这样既保证了全局唯一又能通过订单号快速定位下单时间。不要用数据库自增ID直接当订单号因为订单号通常需要展示给用户自增ID太容易暴露订单量而且在大并发下也容易产生安全问题。3.2 下单接口的并发与事务处理下单接口是整个后端系统最核心的接口也是并发压力最大的地方。高峰期一群人同时点餐如果代码写得不对非常容易出现超卖、重复下单、库存错乱等问题。我在这里重点讲两个关键点事务和锁。事务是必须的。整个下单流程涉及多个数据库操作查询菜品、校验库存、创建订单、插入明细、扣减库存。这些操作必须在一个事务里任何一个步骤失败都要整体回滚绝不能让数据库出现半个订单。锁的选型要仔细。对于扣减库存最简单可靠的方式是用数据库的乐观锁。比如菜品表里加一个version字段扣减时执行这样的SQLUPDATE dish SET stock stock - #{count}, version version 1 WHERE id #{dishId} AND stock #{count} AND version #{version};执行完毕后检查影响行数如果为0说明库存不足或版本号不匹配直接抛异常回滚整个事务。这种方式没有引入任何额外中间件实现简单性能也足够。只有当单店并发量极高时才需要考虑引入Redis分布式锁但从我实际接触的大量餐饮项目看还远远用不到那一步。3.3 订单状态流转与通知机制订单状态是一个状态机必须严格定义不能随意跳转。我的定义是待支付0→ 已支付1→ 制作中2→ 待取餐3→ 已完成4。另有已取消-1和退款中-2两种异常状态。状态流转的规则是只有特定状态才能流转到下一个状态比如已取消的订单不能直接变成已完成这在代码里用一个状态机校验方法统一处理。通知机制的实现我建议先上简单方案管理端定时轮询订单状态。具体做法是管理端每5秒发起一次查询拉到新订单就播放提示音并弹窗提醒。这种方案的好处是零依赖、零成本而且不需要维护长连接。有的朋友一上来就上WebSocket结果发现部署复杂、断线重连逻辑难写项目周期硬生生拉长了两周。当然如果门店对实时性要求确实高比如后厨屏幕需要秒级刷新订单那再用WebSocket也不迟。后端用Spring的WebSocketHandler实现管理端用原生WebSocket客户端连接逻辑本身不复杂。我的建议还是那句话先上轮询等业务量证明轮询不够再升级不要提前为不存在的性能问题付费。3.4 管理端接口与权限校验管理端的接口和小程序端的接口虽然共用同一个后端服务但必须做好权限隔离。我的做法是小程序用户走/api/customer/**前缀管理端走/api/admin/**前缀。两个前缀的接口各自使用独立的拦截器管理端接口强制校验JWT Token和用户角色。权限上我分了两种角色店长和店员。店长可以操作菜品管理、查看营业报表、处理退款店员只能接单、修改订单状态。这个权限模型在数据库里用一个role字段区分然后在Service层做权限校验。权限校验是绝对不能省的现实中我就见过一家门店因为管理端接口没做权限控制店员误删了全部菜品信息最后只能靠备份恢复的场景。另外管理端登录还需要加一个“验证码防暴力破解”机制。我用的是简单的图片验证码后端生成验证码图片前端点击刷新登录时校验。这套机制虽然基础但能挡住大量自动化攻击尝试。4. Vue管理端订单管理与菜品运营4.1 管理端技术选型与工程结构管理端我选择了Vue3 Vite Element Plus的组合。Vue3的Composition API对复杂业务逻辑的组织更友好Vite的开发启动速度远超WebpackElement Plus的组件覆盖了后台管理90%以上的常见需求。Vue2虽然还有大量存量项目但新项目实在没必要再往旧技术栈里钻。工程结构按功能模块划分views下分订单管理、菜品管理、分类管理、数据统计等目录api目录下按模块封装Axios请求store目录用Pinia管理登录状态和全局信息。一个很重要的约定是所有Ajax请求必须走统一的封装函数统一处理Token携带、错误提示、401跳转登录。如果每个页面都单独写请求代码后期维护就是一场灾难。接口请求的封装大概是这样的// api/request.js import axios from axios; import { ElMessage } from element-plus; const service axios.create({ baseURL: /api/admin, timeout: 10000 }); service.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers[Authorization] Bearer token; } return config; }); service.interceptors.response.use( response response.data, error { if (error.response?.status 401) { router.push(/login); } else { ElMessage.error(error.response?.data?.message || 请求失败); } return Promise.reject(error); } );4.2 订单列表实时刷新轮询还是WebSocket管理端最常见的需求就是新订单提示和订单状态实时更新。这个需求的实现方式我在前面提到过默认用轮询。具体实现是用一个定时器每5秒调用一次订单查询接口比对返回的数据与当前列表是否存在差异有差异就刷新视图并播放提示音。代码不复杂但这里有一个需要注意的性能问题轮询接口一定要做好条件筛选比如只查询今天的数据只查询未完成的订单避免每次拉全量数据造成不必要的数据库压力。如果你确实想用WebSocket做实时推送我的建议是只在管理端使用小程序端还是继续走查询逻辑。菜品的上下架、订单状态更新都通过WebSocket推送给管理端浏览器收到消息后自动刷新页面。这里必须要处理断线重连否则店员把电脑合上再打开连接就断了订单就收不到了。用heartbeat机制定期发送心跳包发现连接异常就自动重连这是WebSocket方案里最容易被忽略的坑。4.3 菜品及分类管理的数据联动菜品管理模块解决的是门店日常运营的高频操作新增菜品、调整价格、修改分类、上下架、设置库存。这里有一个数据联动细节需要注意菜品被订单引用后不能物理删除只能逻辑下架。如果直接DELETE掉菜品记录历史订单的明细就会变成空引用数据完整性直接崩塌。所以在菜品表设计时我加了一个status字段0表示下架、1表示上架删除操作全部转换成更新操作。分类管理更简单主要就是排序和增删改。但有一个建议分类一旦创建不要轻易改名。因为顾客的浏览习惯和店员的点单习惯都会锚定在分类名称上频繁改名会造成认知混乱。如果确实要调整建议在非营业时间操作避免影响正在点餐的顾客。菜品图片的管理我采用的方案是图片上传到服务器指定目录数据库只存相对路径。Vue管理端通过http://域名/upload/xxx.jpg拼接完整访问地址。这里一定要处理好跨域问题通常Nginx里配置静态资源路径和反向代理规则就行。5. 联调、部署与常见问题排查5.1 本地联调常见拦路虎本地开发时第一大坑就是跨域问题。Vue开发服务器默认跑在localhost:5173SpringBoot跑在localhost:8080两者的端口不同浏览器直接请求就会被CORS拦住。解决方案有两种一是后端配置全局CORS允许指定源跨域访问二是在Vite配置代理把/api前缀的请求转发到后端地址。我推荐第二种因为生产环境也要走Nginx代理本地和线上保持一致更不容易出问题。另一个高频问题是小程序开发者工具里请求localhost接口时提示“不在以下request合法域名列表中”。这是因为微信小程序默认不允许请求http://localhost接口。解决方案是打开开发者工具的“详情”设置勾选“不校验合法域名、web-view业务域名、TLS版本以及HTTPS证书”。这一步只是开发期配置上线前必须换成正式的HTTPS域名并在小程序后台配置好业务域名否则真机扫一扫会直接白屏或者请求失败。我实际测试时经常遇到一个很奇怪的现象小程序在开发者工具里一切正常但预览到手机变成白屏。这种情况90%以上是因为接口请求的地址写死了localhost手机上访问的自然还是手机自己肯定不通。解决方法是把请求地址做成环境变量根据编译模式自动切换。5.2 线上部署的关键配置线上部署我采用的方案是单台云服务器 Nginx SpringBoot Jar包 Vue静态文件。SpringBoot打包成Jar包用java -jar命令跑起来监听8080端口。Vue项目执行npm run build生成dist目录上传到Nginx的静态目录。Nginx配置里主要做两件事第一把/api开头的请求反向代理到8080端口的SpringBoot服务第二把根路径的请求指向Vue的index.html同时配置好前端路由的history模式回落。如果门店要求更强的稳定性可以再加一层守护机制用systemd服务管理Jar包的启动和崩溃自动重启。这个对餐饮门店非常重要——店员不会去服务器上敲命令重启服务如果服务半夜挂了第二天营业就会直接瘫痪。我配置过很多次只需要写一个简单的systemd unit文件设置Restartalways基本就能保证服务异常退出后自动拉起。这一步看起来不起眼但对于商用系统来说是刚需。小程序线上还有一个流程要提前走在小程序管理后台配置request合法域名必须是HTTPS的并且需要备案。这一步往往会被新手忽略等到提审时才被发现白白拖延上线时间。5.3 高频问题速查表这里整理一份我在开发和测试中反复遇到的高频问题速查表问题现象可能原因解决方案小程序编译到真机白屏请求地址写死localhost改为环境变量根据编译环境切换域名扫码进入后桌号是空的scene参数超过32字符或未解码简化scene内容统一用编码规则下单提示库存不足乐观锁更新影响行数为0检查SQL条件和事务是否提交订单金额不对后端未重新计算金额以后端计算的金额为准前端金额仅展示管理端图片不显示静态资源路径或跨域错误检查Nginx静态资源别名和CORS配置服务半夜挂了没人知道缺少守护进程用systemd管理开启自动重启微信支付回调收不到回调地址不可公网访问确保回调地址支持HTTPS且能被外网访问这个表格是我在实际项目中真实遇到过的场景汇总。很多人会觉得这些问题小但就是这些小问题会让一个看起来很完善的项目在线上翻车。我的经验是每次上线前都拿这个表过一遍能省很多麻烦。6. 完整的实操总结与我的经验6.1 给第一次做扫码点餐项目的朋友的建议如果你是从零开始做扫码点餐我的第一个建议是先做一个最小可用版本不要一上来就贪大求全。第一版只需要包含用户扫码点餐、创建订单、管理端查看订单和修改状态这四个核心功能。支付、会员、营销、打印小票这些功能都可以在第二期再加。过早引入复杂功能只会拖慢项目进度还容易让核心功能的质量打折扣。第二个建议是老生常谈但真的很重要尽早联调不要等前后端都写完了再对接。我见过太多团队前后端各写各的到联调那天发现接口字段对不上、状态码不统一然后花大量时间返工。正确的做法是前后端先约定好接口文档哪怕用Swagger或简易的Markdown也行然后并行开发每周至少联调两次。这能省下至少三分之一的开发时间。第三个建议是提前想好异常处理机制。餐饮行业的网络环境和使用人群都比较多变顾客可能在点餐中途退出、支付成功但回调超时、店员误操作。这些都必须在代码里写好兜底逻辑。比如支付回调超时的情况我额外写了一个定时任务每隔一段时间扫描超过N分钟仍处于待支付状态的订单主动调用微信查询接口确认最终支付结果。6.2 这个项目的扩展思路扫码点餐系统跑通后扩展空间非常大。目前最实用的三个方向是对接后厨打印机、会员储值与卡券营销、多门店连锁管理。后厨打印机通过后端接入商用的云打印服务比如飞鹅云订单创建后自动打印到后厨这个需求几乎每家餐饮店都会提。会员储值则需要在用户表增加账户余额字段配合微信支付完成充值流程。多门店则在现有表结构上增加shop_id做数据隔离管理端支持按门店切换。这些扩展方向的共同点是核心订单流程不用大改只是在现有框架上追加能力。这也印证了当初做单体应用、保持业务模块清晰划分的决定是正确的。做项目就是这样架构设计不需要多么炫酷关键是要为未来的变化留好余地。我个人的体会是扫码点餐这类项目最大的难点并不在某个技术点本身而在于把用户操作、后端业务、商家管理三个环节粘合得足够顺滑。任何一个环节出现体验断裂整套系统都会被认为是“不好用”。所以开发过程中要有全局视角多站在使用者的角度去走一遍完整流程发现问题及时调整。如果你正准备做这个方向的项目希望这篇内容能帮你少走一些弯路快速把一个能真正跑起来的系统交付出去。本文还有配套的精品资源点击获取
返回列表