简介:面向餐饮场景的微信扫码点餐/订餐系统毕业设计完整资源包,采用uni-app开发小程序端、SpringBoot实现后端接口、Vue搭建管理后台,适合Java方向毕业生或需要快速搭建点餐项目的开发者。在快节奏生活下,传统人工点餐常需排队或等待服务员,效率较低;本系统通过餐桌二维码让顾客自助点餐并备注留言,商家在管理端统一维护菜品与订单,可显著提升用餐体验和餐厅运营效率。资源包含完整前后端源码、MySQL数据库SQL脚本、毕业论文文档及运行截图,覆盖扫码桌号点餐、菜品管理、订单管理、分类管理等核心模块。压缩包共455个文件,主要类型包括Java与class后端代码、Vue/JS前端逻辑、XML配置文件、SQL数据库脚本、jpg/png图片素材及doc论文文档,整体约7.05MB,目录结构清晰便于按模块查阅。目前已有1292人学习浏览,适合Java毕业设计、课程实训或小型餐饮点餐项目二次开发,可帮助掌握微信小程序对接SpringBoot的完整流程、JWT权限校验及前后端分离项目部署等关键技能。
1. 微信小程序扫码点餐系统:看起来是点餐,实际是订单状态机的三端闭环
微信小程序扫码点餐这个选题,做过的都知道:把菜单搬进小程序只是表面,真正的难点在三处——扫码之后怎么确定是哪家店哪个桌、订单从待支付到已完成的状态怎么流转不丢、以及微信登录怎么在现在的接口规则下拿到用户身份。这套 uni-app + SpringBoot + Vue 的扫码点餐源码,恰好把这三件事串成一条完整链路:小程序端负责扫码进店和下单,SpringBoot 后端统一处理菜品查询与订单状态机,Vue 管理端负责菜品上架和订单处理。适合准备点餐、订餐类毕业设计的人,也适合想快速复用一个前后端分离小程序项目的开发者。
2. 系统拆解:uni-app点餐端、SpringBoot后端、Vue管理端的分工与数据流
这套系统拆开看是三个独立工程,跑起来是一条数据链。小程序端只负责把用户的操作翻译成HTTP请求;后端把业务规则全部收口,菜品查得到、订单建得成、状态改得对;管理端是给商家用的后台,只做菜品和订单的管理。三者之间没有硬耦合,全靠接口约定,所以就算你想把管理端从Vue换成别的框架,只要后端接口不动,小程序端完全不受影响。
2.1 前端选型:为什么是uni-app而不是原生小程序
这类毕设源码里,小程序端用uni-app写的比例很高。原因是它用Vue语法,前端不用专门学一套WXML和WXSS,编译一次就能同时产出微信小程序、H5和App三端代码。对这个点餐项目来说,uni-app还有一个实际好处:答辩演示时可以直接用H5形态在电脑浏览器里跑,不用现场把手机和电脑用微信开发者工具连起来。代价就是它比原生小程序多一层编译,遇到界面渲染异常时,先得判断是框架问题还是自己的代码问题。
点餐端的目录结构一般长这样:
order-app/ ├── pages/ │ ├── index/ # 扫码落地页与店铺首页 │ ├── menu/ # 菜品列表与分类 │ ├── cart/ # 购物车页面 │ ├── order/ # 订单列表与详情 │ └── mine/ # 我的页面 ├── api/ │ ├── request.js # 统一封装uni.request,集中管理baseUrl │ ├── dish.js # 菜品相关接口 │ └── order.js # 订单相关接口 ├── store/ # 购物车、用户信息的全局状态 └── App.vue # 应用入口逻辑说明:pages下的每个子目录对应一个页面,api目录把HTTP请求按业务拆成模块,store目录放跨页面共享状态。这里最需要关注的是api/request.js,之后改后端地址只需要动一个文件。购物车和用户信息必须放store,否则跳转一次页面数据就丢。
参数说明:request.js里核心看两个参数,baseUrl默认写成localhost,联调时必须改成电脑的局域网IP;timeout建议设10秒以上,扫码点餐场景里用户经常在弱网环境下使用。
选uni-app还有一个长远考虑:微信小程序的接口规则和用户授权方式这两年变动频繁,uni-app的社区跟进往往比单人项目快,遇到接口变更时搜索解决方案更容易命中。
2.2 后端分层:SpringBoot + MyBatis Plus 的经典结构
后端的技术栈是SpringBoot + MyBatis Plus,这是Java毕设里最常见的组合。分层上遵循Controller → Service → Mapper → Entity,每层各司其职。Controller只管接收HTTP参数和返回JSON,Service写业务规则,Mapper是数据访问层,Entity对应数据库表。
以菜品查询为例,Controller层典型写法:
@RestController @RequestMapping("/api/dish") public class DishController { @Autowired private DishService dishService; @GetMapping("/list") public Result getDishList(@RequestParam Long shopId, @RequestParam(required = false) Long categoryId) { List<Dish> list = dishService.getDishList(shopId, categoryId); return Result.success(list); } }逻辑说明:@RestController声明这是一个接口类,类上的@RequestMapping给所有接口统一加前缀。getDishList接收两个参数,shopId必传用来区分店铺,categoryId可传用来按分类过滤。返回体统一包一层,前端拿到的一律是code、message、data三段结构,判断code就知道请求是否成功。
参数说明:shopId是整个系统里最关键的业务参数,扫码点餐场景中一个小程序往往对应多个店铺甚至多个门店,所有核心查询都要按shopId过滤。如果源码里没有这个字段,说明是单店版,后面自己有需求时可以扩展。
Service层查询通常用MyBatis Plus的LambdaQueryWrapper:
public List<Dish> getDishList(Long shopId, Long categoryId) { LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Dish::getShopId, shopId) .eq(categoryId != null, Dish::getCategoryId, categoryId) .orderByAsc(Dish::getSort); return dishMapper.selectList(wrapper); }逻辑说明:eq的第一个参数是条件开关,categoryId为null时这段条件就自动跳过,省得写多个if分支。orderByAsc按sort字段升序,sort就是后台管理端设置菜品排序时写入的数字。
参数说明:MyBatis Plus默认开启驼峰转下划线,实体类里的shopId自动对应数据库表的shop_id列,除非列名确实异常,否则不要手动加@TableField去覆盖,写多了反而乱。
2.3 管理端:Vue 2 + Element UI 的菜品与订单管理
管理端用的是Vue 2搭配Element UI,目录里包含路由配置、API封装和页面组件。核心页面就两个:菜品管理页做增删改查,订单管理页处理状态流转。菜品管理页的表格操作列,几乎都要用插槽来放编辑和下架按钮,Vue 2里最典型的写法:
<el-table :data="dishList" v-loading="loading"> <el-table-column prop="name" label="菜品名称"></el-table-column> <el-table-column prop="price" label="价格"></el-table-column> <el-table-column label="操作" width="180"> <template slot-scope="scope"> <el-button type="text" @click="handleEdit(scope.row.id)">编辑</el-button> <el-button type="text" style="color:red" @click="handleDelete(scope.row.id)">下架</el-button> </template> </el-table-column> </el-table>逻辑说明:slot-scope是Vue 2里获取当前行数据的方式,scope.row就是当前遍历的行数据对象,取它的id传给编辑或下架方法。这是管理端表格操作列最常见的写法,掌握这一个插槽语法,基本能应付所有表格按钮场景——这也聊到了Vue面试题里总爱追问的插槽用法。
参数说明:width固定为180,避免两个按钮换行影响布局;handleDelete只是在前端调用接口,真正的删除逻辑在后端,前端不应该直接操作数据。
管理端路由就是Vue Router的标准用法,没有太多花活。倒是有个实际细节:如果管理端要部署到服务器子路径下,router要配置base,这是部署阶段才会踩的坑。
3. 把项目跑起来:环境准备、数据库初始化、双端启动与联调
拿到源码包之后,我一般会先干三件事:查README(如果有)、打开application.yml、看小程序端api目录下的request.js。这三处能暴露90%的坑:数据库连不上、接口地址不对、依赖版本冲突。先把这些确认了再启动,比直接点IDE的启动按钮效率高得多。下面按实际操作顺序说。
3.1 环境准备:JDK、Node、微信开发者工具的版本匹配
环境版本是第一个翻车点。后端SpringBoot项目建议用JDK 8,别看到JDK 17就往上装。源码的pom.xml如果写的是spring-boot-starter-parent 2.x,JDK 8是最稳的搭配。管理端是Vue 2项目时,Node建议装14或16,Node 18以上跑npm install经常报OpenSSL冲突,这是第一次启动失败的高频原因。
java -version node -v npm -v逻辑说明:三条命令分别确认JDK、Node和npm版本。java -version输出1.8.x说明是JDK 8,node -v显示v14或v16最合适。版本不合适时,硬跑下去要改不少依赖配置,代价远高于重装一个版本。
参数说明:注意不要只看Node主版本,npm版本随Node一起变化,如果npm install时提示npm版本过旧,用npm install -g npm升级npm本身就行。
3.2 数据库初始化:SQL脚本导入与自动建表
源码包里一般带db目录或SQL脚本。常见做法是先用Navicat或命令行建库建表,再改application.yml里的账号密码。如果源码没给脚本,后端又是MyBatis Plus 3.5.3以上,还有另一个省事的办法:让MyBatis Plus根据实体类自动生成建表SQL,这个功能在补表时很实用。
# 命令行方式导入SQL,注意把路径换成实际位置 mysql -uroot -p source /home/demo/order_system.sql;逻辑说明:source后面跟SQL脚本的绝对路径。执行前先确认MySQL服务已启动,root账号能正常登录。导入完成后检查表名是否和数据访问层里的实体对应,比如dish、orders、category,脚本执行到一半报错时不要直接跳过,往往后面还会连锁报错。
参数说明:如果脚本里已经包含CREATE DATABASE order_system,导入后无需再手工建库;如果只有CREATE TABLE,需要先用CREATE DATABASE建库再use进入,否则表会建到默认库里。
3.3 后端启动:application.yml中三个关键配置
启动后端前,必须检查application.yml里的三块内容:数据源、文件上传路径、微信小程序配置。这三样直接决定后面联调是否会翻车。
server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/order_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver file: upload-path: /home/demo/upload/ # Windows下改成 D:/upload/ wx: appid: your_appid secret: your_secret逻辑说明:三块配置分别对接MySQL、图片磁盘目录、微信登录接口。数据源URL里的serverTimezone=Asia/Shanghai是必备参数,不加的话日期字段会报时区错误。file.upload-path是图片上传落盘目录,这个路径必须和返回图片URL的前缀对应,否则管理端上传成功、小程序端访问时却404。wx.appid和wx.secret要换成自己的小程序账号信息,否则微信登录一定失败。
参数说明:密码一行的123456只是示例,以源码包里为准;upload-path不要放在target或编译目录下,mvn clean之后图片会被全部清掉。
后端启动命令:
mvn spring-boot:run逻辑说明:开发阶段用这一行,改动代码后重启速度快。它会在Maven编译后直接启动SpringBoot应用,控制台会打印端口等信息,看到Spring Boot Started就说明启动成功。
mvn clean package -DskipTests java -jar target/order-system-0.0.1-SNAPSHOT.jar逻辑说明:第一行打包,跳过测试以节省时间;第二行运行打出来的jar包。jar包名以pom.xml里的artifactId和version为准,如果找不到,去target目录下ls一下就知道。
参数说明:两个命令要在同一目录下执行,否则target路径对不上。
3.4 小程序端启动:HBuilderX导入与request地址修改
小程序端是uni-app工程,用HBuilderX导入即可。导入后先别急着点编译,打开api/request.js,把baseUrl改成后端电脑的局域网IP。
const request = (options) => { return new Promise((resolve, reject) => { uni.request({ url: 'http://192.168.1.100:8080' + options.url, method: options.method || 'GET', data: options.data || {}, header: { 'token': uni.getStorageSync('token') || '' }, success: (res) => { if (res.data.code === 0) { resolve(res.data.data); } else { reject(res.data); } }, fail: (err) => reject(err) }); }); };逻辑说明:url直接拼了局域网IP,这是微信开发者工具联调阶段的常规做法。微信小程序的正式环境要求接口必须是HTTPS,但开发阶段可以在工具里勾选“不校验合法域名”,所以http协议可以直接用。header里带token,从本地存储读取,登录接口返回的token就存在这里。
参数说明:192.168.1.100是示例,要替换成本机实际IP。特别注意两点:真机预览时不能用127.0.0.1,必须用电脑在局域网里能访问到的IP;手机和电脑要连同一个WiFi。
提示:如果你在真机上发现请求全部超时,先ping一下这个局域网IP通不通,很多时候是防火墙没放行8080端口。
图片路径也是这里的高频坑:如果小程序里的菜品图片是相对路径,图片前缀同样要拼上这个IP,否则进入菜单页面会全是裂图。
3.5 管理端启动:npm install、代理与源码分发
管理端是Vue 2工程,启动顺序是先装依赖、再起dev服务。把源码发给别人的时候记得删掉node_modules目录,只发源码,不然压缩包体积会大十几倍。对方拿到后自己npm install就行,这也是“Vue项目源码怎么发给别人”这个问题的标准答案。
npm install --registry=https://registry.npmmirror.com npm run dev逻辑说明:第一行指定npm镜像源,很多人在npm install这一步卡很久,就是因为默认源下载慢或个别包拉不下来。第二行启动开发服务器,Vue 2项目默认跑在8080端口,如果和后端端口冲突,在package.json里改dev脚本。
参数说明:镜像源按需添加,如果默认源速度正常,不加这一行也能装完。Vue 2项目的npm install如果报了OpenSSL相关的ERR_OSSL_EVP_UNSUPPORTED,基本就是Node版本太高,切回Node 16解决。
管理端接口地址一般写在vue.config.js的proxy里,这是前后端联调的关键一环:
devServer: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } }逻辑说明:proxy的意思,是管理端页面发起的/api路径请求都被转发到后端localhost:8080。管理端代码里写相对路径即可,不用把后端IP写死。后端换机器后,只需要改target一处。
参数说明:changeOrigin必须为true,作用是把请求头里的Host改成target域名,部分后端校验了Host头,不改会报跨域错误或直接被拒。
4. 关键链路:扫码进店、购物车、订单状态机与微信登录
跑通三端之后,这套系统真正核心的业务链路就剩四条:扫码进店、购物车、订单状态机、微信登录。前三条是点餐业务的命脉,第四条是小程序端所有用户识别的基础。下面拆开说每条链路代码怎么走,以及哪些地方容易漏。
4.1 扫码进店:scene参数与shopId的传递
微信小程序扫码进店,信息是通过小程序码的scene参数带进来的。常规做法是每个桌台生成一个带参数的小程序码,参数里编码shopId和tableNo,用户扫码后小程序冷启动,在onLoad里解析scene字段。
onLoad(options) { let scene = decodeURIComponent(options.scene || ''); // scene格式: shopId=1&tableNo=12 let params = {}; scene.split('&').forEach(item => { let parts = item.split('='); params[parts[0]] = parts[1]; }); this.shopId = params.shopId; this.tableNo = params.tableNo; this.getDishList(this.shopId); }逻辑说明:扫码进入小程序时,scene参数会经过URL编码,所以第一步是decodeURIComponent,然后按&拆成键值对。拿到shopId后立刻调用菜品列表接口,用户是无感的,不会看到空白等待页。tableNo在提交订单时一起回传后端,后端通过它知道这张订单是哪一桌下的。
参数说明:生成小程序码时scene有长度限制,实际约32个可见字符,所以只能传shopId和tableNo这类短ID,不要放中文字符串或长描述。另外,同一个用户扫同一张码多次,onLoad每次都会执行,要注意不要重复创建订单。
4.2 购物车:本地缓存还是后端暂存
购物车的实现方式,要去看源码的store目录。常见做法是前端本地缓存,因为点餐购物车的特点是:增删改非常频繁、用户可能中途退出、只有最终提交订单时数据才需要同步给后端。用本地缓存能降低后端压力,也省了设计购物车过期策略的麻烦。
const state = { items: uni.getStorageSync('cartItems') || [] }; const mutations = { addItem(state, dish) { let found = state.items.find(item => item.dishId === dish.id); if (found) { found.count++; } else { state.items.push({ dishId: dish.id, name: dish.name, price: dish.price, count: 1 }); } uni.setStorageSync('cartItems', state.items); } };逻辑说明:addItem先检查购物车是否已存在这道菜,存在就数量加一,不存在就追加一条新记录。每次变更后立刻写回storage,用户就算杀掉小程序进程再重进,购物车数据还在。价格在加入购物车那一刻就做快照,后续后台改了价格,这一单仍以加购时价格为准,这也是点餐系统的行业习惯。
参数说明:storage的key统一用cartItems,提交订单时也从这里读。如果源码支持多店铺,这个key要加上shopId后缀,比如cartItems_1、cartItems_2,否则用户在不同店铺间切换时购物车会串。
4.3 订单状态机:从待支付到已完成
订单状态是这套源码里业务含量最高的地方。常规状态流转是:待支付(0) → 已支付/制作中(1) → 已完成(2),中间还穿插已取消(-1)和退款中(3)。后端Service层通常维护一个带校验的状态更新方法:
public boolean updateOrderStatus(Long orderId, Integer fromStatus, Integer toStatus) { Order order = orderMapper.selectById(orderId); if (order.getStatus() != fromStatus) { return false; } order.setStatus(toStatus); return orderMapper.updateById(order) > 0; }逻辑说明:fromStatus和toStatus是成对出现的,调用方必须说清楚“我希望从哪个状态变成哪个状态”。如果当前状态已经不是fromStatus,说明请求已经失效,直接拒绝。这个写法可以挡掉大量重复提交和乱序请求,比无脑setStatus安全得多。
参数说明:实际业务中,已支付状态是后端收到微信支付回调后更新的,不是前端拿到支付成功就改。前端改状态只是界面显示,真正状态变更必须以支付回调为准。这一点答辩时讲清楚,会显得对业务链路有真实理解。
4.4 微信登录:wx.login换openid,手机号授权的新姿势
微信登录是踩坑高发区。老代码里常见的wx.getUserInfo拿用户昵称头像的方式,在新版微信里已经不再返回真实数据。正规做法是:wx.login拿到code,后端拿code去微信服务端接口换openid,然后由后端自己生成业务token返回给小程序。手机号获取也改了:现在用button的open-type="getPhoneNumber"触发,再由后端解密回调参数拿到手机号。
@PostMapping("/wx/login") public Result wxLogin(@RequestBody Map<String, String> body) { String code = body.get("code"); // 后端用code调微信服务端接口换openid和session_key String openid = wxService.code2Session(code); String token = jwtService.createToken(openid); return Result.success(token); }逻辑说明:code2Session是对微信服务端接口的封装,内部需要传appid和secret,换取成功后拿到openid。后端再用JWT生成业务token返回给小程序,小程序端后续所有请求都带这个token,后端解析token拿到openid,就知道当前请求是哪个用户发出的。
参数说明:手机号获取现在有门槛,个人主体的小程序开通不了获取手机号的能力,这是很多人测试时发现手机号一直拿不到的原因。如果源码里有手机号绑定逻辑,发布前先确认账号主体是否有权限,没有权限就改成手机号验证码方案,或者降级成“用户手动填写手机号”。
5. 避坑指南:跑通这套点餐源码的五个典型翻车现场
下面这五个坑,是不同电脑上跑同一套点餐源码时真实遇到过的。统一按“现象、原因、解决”三步写,方便对照排查。每一个都附了当时定位问题用的关键操作。
5.1 翻车一:springboot版本太高,MyBatis Plus starter拉不下来
现象:pom.xml里引入mybatis-plus-boot-starter后,要么mvn compile直接报找不到类,要么启动时报ClassNotFoundException。
原因:SpringBoot 3.x把javax包体系换成了jakarta,而老版本的MyBatis Plus starter还是按javax编译的,版本直接冲突。这种毕设源码大多是针对SpringBoot 2.x设计的,强行用3.x自然跑不动。
解决:优先切回SpringBoot 2.7.x配合MyBatis Plus 3.5.x。确实想用SpringBoot 3.x,就换mybatis-plus-spring-boot3-starter,同时检查druid数据源分页插件等配套依赖是否也有对应版本,只是改动面会变大很多。
5.2 翻车二:微信小程序顶部导航栏高度适配,按钮被顶出屏幕
现象:点餐页自定义了返回按钮和店铺名,在真机上打开,按钮紧贴状态栏甚至被系统时间覆盖。
原因:自定义导航栏时没有考虑状态栏高度。iPhone刘海屏状态栏约44px,Android一般20dp以上,前端硬编码一个固定高度必然适配失败。
解决:通过uni.getSystemInfoSync()动态读取statusBarHeight,把它作为导航栏padding-top的值。
const systemInfo = uni.getSystemInfoSync(); this.statusBarHeight = systemInfo.statusBarHeight;逻辑说明:页面加载时读一次状态栏高度存进data,模板里绑定到导航栏容器。不同机型高度不同,必须实时获取不能写死。这个属于微信小程序自定义导航栏的必修课,遇到导航按钮顶出去先看这个值。
5.3 翻车三:管理端图片上传了,小程序端却404
现象:管理端上传菜品图后回显正常,小程序端菜品列表图片全白。
原因:图片返回的URL是绝对路径,比如http://localhost:8080/upload/xxx.jpg。管理端跑在开发机上localhost没问题,但小程序端在开发者工具或真机里,这个地址指向的并不是后端服务器。
解决:图片上传保存路径和返回URL的base前缀都做成服务器地址配置项。小程序端访问图片时,前缀要拼后端所在机器的局域网IP或线上域名。还要注意上传目录别放在target里,重新打包后目录会被清空。
5.4 翻车四:订单超时未支付,定时任务没生效
现象:下了单不支付,等了很久订单还是待支付,自动取消完全没有触发。
原因:常见的三种。启动类上没加@EnableScheduling,导致定时任务注解没被扫描到。cron表达式写错,把每30分钟写成了每30秒,资源白白消耗。定时任务方法里只查了status等于待支付,但没判断订单创建时间是否超过15分钟,把刚新下的单也一起处理了。
解决:先确认启动类上有@EnableScheduling,再验cron表达式的执行频率。更稳的习惯是不完全依赖定时任务:下单后把过期时间作为参数,支付回调或用户查询订单时做懒判断,超时的自动置为已取消,这样即使定时任务挂掉也不会出现死订单。
5.5 翻车五:微信开发者工具里request域名校验卡住
现象:小程序端所有请求都报“不在以下request合法域名列表中”,接口全挂。
原因:微信开发者工具默认开启合法域名校验,开发阶段用的是http加局域网IP,肯定不在域名白名单里。
解决:在开发者工具右上角“详情”里的“本地设置”中勾选“不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书”。开发阶段一律勾选,上线前再把配置换成正式的HTTPS域名。
6. 进阶改造:从可用到好用,值得动手的三个小方向
源码跑通只是开始。如果你想在答辩演示或者简历项目描述里多两个亮点,我建议优先改这三个方向:菜品排序、订单语音播报、多门店支持。它们都不复杂,但每一个都能让系统看起来更像正式上线过的产品。
6.1 菜品排序:管理端拖拽排序与后端sort字段
菜品管理页目前大概率是按上架时间排列。升级方式是加一个sort字段,管理端用拖拽组件调整排序,后端更新sort值,小程序端查询时按sort升序返回。菜品排序在餐牌场景里几乎是刚需,招牌菜必须排在最前面。
wrapper.orderByAsc(Dish::getSort, Dish::getUpdateTime);逻辑说明:sort相同时,再按更新时间倒序,这样同一天手动调过的菜能保持相对顺序稳定。只需要在管理端加一个排序拖拽功能,数据库加一列,接口排序规则改一行,改动范围很小但演示效果很直观。
6.2 订单语音播报:小程序端订阅消息与管理端轮询
餐厅场景里,后厨需要听到新订单提醒。最简单的方式是管理端用一个轮询接口,每隔10秒查一次是否有新订单,查到后播放一段本地音频提示。不要一上来就做WebSocket,轮询够用且不容易出问题。如果想做到小程序端通知顾客取餐,可以接入订阅消息,但订阅消息有一次性模板限制,需要用户主动订阅,实际转化率不高,演示场景里慎用。
6.3 多门店扩展:把shopId从写死改成上下文参数
源码里如果shopId只是常量,扩展多门店会非常痛苦。建议把所有涉及shopId的接口和数据库查询都改成从请求参数或登录token中获取,并确保购物车缓存键带上shopId。多门店支持之后,管理端也可以按门店过滤订单和菜品,这个扩展会让项目在架构层面的评语好看很多。
从那以后,我每次拿到带小程序的毕设源码,都会强制先看三样东西:application.yml里的数据源和上传路径、request.js里的baseUrl、以及数据库脚本里的表名是否和实体对得上。三样看完再启动,翻车的概率能少一半。希望帮到你。
本文还有配套的精品资源,点击获取