微信小程序在线订餐系统全流程开发实践与源码解析

微信小程序在线订餐系统全流程开发实践与源码解析

, name, phone, , city, ,

这里我想特别说两个设计点。

第一,订单里的地址和菜品信息为什么不做关联查询,而是用快照字段。因为下单之后,商家可能修改菜名、价格,用户地址也可能变更,如果订单直接关联实时数据,历史订单就会显示错乱。所以我在 里存了 ,在 里冗余了 和 price。这在你写确认订单接口时可以一次性把快照数据组装好,查询时直接读取,速度快也不会被后续修改影响。

第二,购物车到底要不要存数据库。很多传统电商系统会要求用户换设备后购物车还在,所以购物车表必须存在。但点餐场景里用户更在意快速、轻量,我做了折中:购物车数据默认存小程序本地 ,提交订单时一次性同步到后端生成订单。这样既保证了体验,又不会给数据库增加大量无关请求。如果你需要做“多端同步购物车”,再把它迁到服务端也不迟。

还有一张 单例表用来存店铺基础信息,比如店名、营业时间、公告、配送费、起送价。这种表只有一行数据,但几乎所有订单和首页接口都要读取,把它做成一个缓存对象放在 Redis 里效果最好。

2. 核心功能模块拆解与关键实现 2.1 微信登录和用户信息:新规下的正确姿势

微信登录在早期项目里很简单:前端调用 wx.login 拿到 code,后端拿 code 去微信接口换 ,然后创建用户,返回自定义 token。但现在平台规则改了不少,如果你直接照抄旧教程,很容易在审核阶段被拒。

现在用户头像和昵称的标准做法是:

注意,wx. 这个接口在基础库 2.21.2 之后就逐步收紧了,不能像以前那样弹窗拿用户头像昵称。我在开发时一开始没注意,测试机上还能弹窗,上传到体验版就发现拿不到完整信息,后来查文档才确认是平台策略调整。

登录流程本身并没有变,核心步骤是:

前端通过 wx.login 获取临时 code 后端调用 接口,用 code 换 和 后端用 在数据库查找用户,不存在则创建 生成自定义 token(我用的是 JWT),返回前端 前端把 token 存到 ,后续所有请求 里带上

还有一个容易被忽略的点:手机号获取。个人主体小程序无法直接获取用户手机号,需要企业主体,并且绑定通过认证的微信开放平台账号。我在商家版里没有强依赖手机号登录,而是让用户填写手机号作为联系方式,否则一个小白开发者跑个人项目会卡在这里很久。

2.2 点餐页与购物车:规格选择、数量管理、角标联动

菜品页面看着简单,其实坑点很多。首先是规格(SKU)的处理。同一道菜可能有大份、小份、加辣、不加辣,价格还不一样。前端页面不能只展示菜品基础价格,而是根据用户选择动态变化。

这里我用了“菜品 SPU + 规格 SKU”两层结构。菜品主表 存基础信息和默认价,子表 存具体规格。前端点击“选规格”时弹出一个底部面板,里面用单选方式列出所有规格,用户选定后价格变成对应 SKU 价格,再把 SKU 加入购物车。

购物车我直接存在小程序本地 ,数据结构大致是这样:

[
  {
    "skuId": 1001,
    "dishId": 10,
    "dishName": "宫保鸡丁",
    "specName": "大份",
    "price": 28.0,
    "quantity": 2,
    "image": "/images/dish_10.png"
  }
]

之所以把 、price 这些冗余字段也存本地,是为了购物车列表渲染时不需要频繁请求后端。每次加购、改数量、删减我都同步更新 ,同时用全局事件或页面 刷新底部的购物车栏和角标数量。

需要提醒的是,本地购物车和真实价格之间一定要在后端做二次校验。也就是说,即使前端传一个改小后的价格过来,下单接口也要根据数据库里的 SKU 价格重新计算一遍总价,否则用户可以通过修改请求参数来低价拿菜。这个校验务必放在服务端。

2.3 确认订单与支付:状态机和回调处理

确认订单页是信息最密集的页面:收货地址、配送费、商品明细、备注、实付金额。提交订单后,后端要完成一件非常重要的事情:创建订单并把状态机管理起来。

我的订单状态设计如下:

订单状态是有限状态机,用户取消只能影响待支付的订单,商家接单后就不能随意取消,需要走申请退款流程。支付回调到达后,状态从“待支付”变成“待接单”,并给商家发送订阅消息。

微信支付的流程分三步:

后端调用微信支付“统一下单”接口,传入订单号、金额、回调地址、,得到支付参数 后端把支付参数返回给小程序端,小程序端用 wx. 拉起支付 支付成功后,微信服务器请求后端回调地址,回调里验签并更新订单状态

支付回调是整条链路里最容易出问题的环节。回调接口必须是公网 HTTPS 地址,而且不能做任何业务跳转,只能返回 XML 或纯文本告诉微信“我收到了”。我在回调里做的第一件事是校验签名,第二件事是判断订单当前状态,如果已经是“已支付”,直接返回成功,避免重复处理。这是典型的幂等处理。

实际开发中还发现一个现象:回调接口偶尔会延迟几秒甚至几十秒才到达。所以我在订单详情页加了一个“刷新状态”的逻辑,用户支付成功后如果没有立刻看到状态变化,可以手动刷新,或者依赖订阅消息推送。光靠回调不轮询,用户会以为支付失败了。

2.4 商家端与订阅消息:让接单通知不漏

大部分教学项目只做了用户端,但一套点餐系统如果没有商家接单入口,根本跑不起来。我在这套系统里做了一个简单的商家端小程序页面,和用户端共用一套 UI 框架,只是角色不同。

商家登录后看到的是订单列表,实时刷新待接单订单。点击订单可以查看详情,包括商品明细、用户地址、备注。核心操作有三个按钮:接单、开始制作、完成。每完成一步,订单状态更新,同时给用户发一条订阅消息。

订阅消息是现在替代模板消息的唯一方案,流程是:

用户端提前调用 wx.age 请求授权,订阅“订单状态通知” 后端在下单或状态变更时调用 .send 接口,传入用户 和模板 ID 用户端收到消息后点开即可跳转小程序

这里有个特别需要注意的规则:用户授权订阅只是“一次性的”,每次发送之后剩余次数就减少,除非用户再次点击订阅按钮。所以不能假设用户一定收到消息,订单列表的轮询还是要保留。我在提交订单页放了一个“接收订单通知”的开关微信小程序在线订餐系统全流程开发实践与源码解析,用户勾选时才发起订阅请求,至少能提高一点送达率。

商家端还可以扩展菜品管理,我做了上架、下架、修改库存、设置当日售卖状态。当天售罄的菜品不需要删,直接下架就行。采购库存预警也可以做,但那是后话java微信订餐系统源码,先把核心闭环跑通。

3. 核心代码实现与调试实战 3.1 小程序端请求封装与页面结构

小程序端我做的第一件事是把 wx. 封装成公共方法,统一处理 token、错误码、加载态。如果不做这层封装,页面里每调一次接口都要写一大段重复代码,维护成本极高。下面这个封装可以直接抄下来用:

// utils/request.js
const BASE_URL = 'https://yourdomain.com/api';
function request({ url, method = 'GET', data = {} }) {
  return new Promise((resolve, reject) => {
    wx.request({
      url: BASE_URL + url,
      method,
      data,
      header: {
        'Content-Type': 'application/json',
        'token': wx.getStorageSync('token') || ''
      },
      success: (res) => {
        const { code, msg, data: result } = res.data || {};
        if (code === 0) {
          resolve(result);
        } else if (code === 401) {
          // token 失效,跳转登录
          wx.removeStorageSync('token');
          wx.navigateTo({ url: '/pages/login/login' });
          reject(new Error(msg));
        } else {
          wx.showToast({ title: msg || '请求失败', icon: 'none' });
          reject(new Error(msg));
        }
      },
      fail: (err) => {
        wx.showToast({ title: '网络异常', icon: 'none' });
        reject(err);
      }
    });
  });
}
module.exports = { request, BASE_URL };

接线上环境时,把 换成你自己的域名。小程序后台的“服务器域名”必须配置 HTTPS 域名才能发起正式请求,这一点在后面调试那里我再细说。

页面目录我按功能拆成了这几个:

商品列表页里最常见的逻辑就是“加购”,这里有一个容易出错的点:同一道菜的不同规格,必须当作不同的购物车行来处理,否则切换规格时数量会叠加。加购时先判断当前 skuId 是否已经在购物车中存在,存在就 + 1,不存在就新增一条记录。

3.2 后端登录接口与统一返回格式

后端我没有把逻辑堆在一个 里,而是按照“ -> -> ”三层拆开。这里拿登录接口举例,它是所有用户请求的第一步,也是很多新手理解后端分层最好的入口:

@RestController
@RequestMapping("/api/user")
public class UserController {
    @Resource
    private UserService userService;
    @PostMapping("/login")
    public Result login(@RequestBody LoginRequest request) {
        String token = userService.login(request.getCode());
        return Result.success(token);
    }
}

层里做的事才是核心:拿 code 调微信接口,解析 ,查数据库,生成 JWT。这里需要引入 或者自己写一个简单的 去请求微信接口,返回结果里如果出现 ,要先把错误原因记录到日志里,否则后面排查登录问题会完全没有抓手。

返回格式我统一封装成下面的结构:

{
  "code": 0,
  "msg": "success",
  "data": {}
}

code 为 0 表示成功,非 0 表示业务错误;401 统一在拦截器里处理,前端 封装里已经对这个状态做了判断。全局异常处理器负责把未捕获的异常转成统一格式,避免后端一报错前端就收到一个无法解析的 HTML 页面。

JWT 拦截器也是整个后端的关键。我写了一个 的拦截器,对所有 /api/** 请求做 token 校验,放行 /api/user/login、支付回调等公开接口。拦截器里从 取出 token,解析出 后放入 ,后续业务代码直接取当前用户,代码会干净很多。

3.3 真机调试与网络抓包定位

小程序开发里我最常用的调试步骤是:先用开发者工具的模拟器把页面逻辑跑通,再用真机预览解决真机环境下才出现的问题。模拟器里正常、真机报错的案例我遇到太多,最典型的就是用户授权弹窗和支付流程,这两类功能模拟器和真机表现差异很大。

真机调试时我一般这样做:

把“详情 -> 本地设置 -> 调试基础库”调到最新稳定版本,避免因为基础库版本过低缺失新 API 真机上开启调试模式,用微信开发者工具扫码后打开 ,实时查看前端日志 前端报错信息不直观时,去后端服务器上看日志,把参数打印出来对比 需要分析网络请求是否被拦截或参数是否异常时,用抓包工具观察完整的请求与响应

这里我想专门说一个常见错误::fail url not in list。这个报错的意思是,小程序的 域名没有配置到微信公众平台的合法域名列表中。解决方法是登录微信公众平台,在“开发管理 -> 开发设置 -> 服务器域名”里加上你自己的 HTTPS 域名。需要注意,开发阶段可以在开发者工具里勾选“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”,但真机预览和正式版必须配置真实域名。

还有个容易出错的地方是 wx.login 拿到的 code 一会儿能用一会儿不能用。这个 code 有效期只有 5 分钟,而且是一次性的。如果你在测试时把 code 打到了日志里,第二次去查数据库或重放请求就会发现 一直是 null。这不是代码问题,是 code 已经被消耗了。

3.4 顶部导航栏适配和单选框细节

微信小程序的顶部导航栏自适应问题,几乎每个做自定义导航栏的人都会遇到。不同型号手机的刘海屏高度不一样,不能把导航栏高度写死。我的处理方式是读取胶囊按钮的位置信息来动态计算:

const menu = wx.getMenuButtonBoundingClientRect();
// menu.top 是胶囊按钮上边界距离屏幕顶部的距离
// menu.height 是胶囊按钮高度
// 导航栏高度 = menu.top + (menu.height - 状态栏高度) * 2 + 状态栏高度

在自定义导航栏的场景下,我会把状态栏高度和导航栏高度存到全局变量,页面里用占位 view 撑出空间,避免页面内容被刘海屏挡住。

单选框在小程序里也踩过坑。原生的 radio 组件样式不统一,在很多机型上无法完美适配。菜品规格选择我建议用 view 自定义单选按钮,选中状态加一个边框变化就能实现,代码简单而且视觉效果好。这个交互在商家端设置营业状态时也用到了。

自定义单选按钮模板:

<view class="spec-item {{selectedSkuId === item.id ? 'active' : ''}}"
      bindtap="selectSku" data-id="{{item.id}}">
  {{item.specName}}

CSS 里给 . 加一个主题色边框和背景色就完成了,比用原生 radio 好看得多。

4. 文档编写与源码交付规范 4.1 怎么写才能让人几分钟跑起来

源码交付时如果只丢一堆代码文件,接手的人大概率会问你好几个“怎么跑”。所以我每次交付都会写 ,并且要求能达到“一个从没看过这个项目的人,照着说明十分钟内能启动起来”的标准。

的开头放项目简介和模块截图,然后是技术栈清单、目录结构说明、环境要求。最关键的是“快速开始”这一节,必须写清楚每一步:

创建 MySQL 数据库,导入 sql/init.sql 修改后端 .yml 里的数据库密码、微信 AppID、、支付商户号 启动后端工程,看到启动成功日志 用微信开发者工具导入 目录,在 app.js 里把 改成你的接口地址 编译运行,用测试账号登录

很多新手以为这一节“不用说”,但恰恰是它决定了项目能不能被别人复现。我还在 末尾加了一个“常见问题”表格,把我在调试中遇到的报错和解决方案直接放进去。

4.2 接口文档、数据库文档和部署文档三件套

除了 ,我还维护了三个配套文档,这是源码交付的完整闭环。

接口文档我用 表格维护,每个接口包含:请求方法、URL、请求参数、返回示例、错误码。不需要引入 这类重型工具,对小程序这种小型项目来说,文档能随时维护、能查就行。我特别强调要把“鉴权要求”写清楚,哪些接口需要带 token,哪些是公开接口,调试的时候一眼就能知道。

数据库文档直接建一个 doc/.md,把每张表的字段名、类型、长度、注释、索引都记录下来。这个文档的价值在于,后面改需求时不用把所有表结构重新看一遍,而且不同开发者之间不会出现“你以为的字段和实际字段不一致”的问题。

部署文档我写的是从零到上线的过程:购买云服务器、安装 、拉取项目镜像或上传 jar 包、配置 Nginx 反向代理、申请 HTTPS 证书、配置微信公众平台服务器域名。小程序要求所有请求域名必须是 HTTPS,而且证书必须有效,所以这块是一步都不能省的。

4.3 源码交付的目录规范与隐私底线

源码交付不是把文件夹一压缩就完事,目录结构和代码整洁度直接影响接手人的第一印象。我的目录一般长这样:

miniprogram/         小程序前端源码
backend/             后端 Spring Boot 工程
sql/                 MySQL 初始化脚本
doc/                 接口文档、数据库文档、部署文档
README.md
.gitignore

有几个底线原则必须强调。

第一,密钥不能进仓库。微信小程序的 、支付商户密钥这些一旦泄露java微信订餐系统源码,后果很严重。正确做法是放到 -prod.yml 环境变量或者配置中心里,Git 仓库里只放模板文件。

第二,. 要提前配好。Java 的 /、小程序的 /、IDE 的 .idea/ 和 ./ 都要排除。否则别人 clone 你的仓库时会多出一堆无用的本机文件。

第三,数据库初始化脚本必须是可重复执行的。我在 init.sql 开头写了 DROP TABLE IF ,这样无论数据库有没有旧数据,都能重新初始化一遍。如果是交付给真实商家的系统,这个脚本要改成增量迁移版本,避免误删数据。

5. 常见问题与排查技巧实录 5.1 登录态失效、用户信息拿不到

这类问题我遇到得最多,表现形式也五花八门。有人反馈“小程序打开后一直转圈”,有人反馈“头像昵称是空的”,还有人反馈“偶尔能登录,偶尔失败”。

排查顺序我一般这样:

还有一个隐蔽的坑:开发者在工具里调试时,如果“本地设置”里勾选了“不校验合法域名”,有时候会误以为网络没问题,但切到真机后立刻暴露出域名未配置的问题。所以真机调试要放在正式验证环节,不要全程只依赖模拟器。

5.2 支付掉单怎么办

支付掉单是线上系统最揪心的问题。用户付了钱,但订单状态还是“待支付”,商家不接单微信小程序在线订餐系统全流程开发实践与源码解析,用户开始投诉。

我处理掉单的思路有三个层面:

后两个层面是长期稳定运行的关键。定时任务对账可以说是兜底方案java微信订餐系统源码,没有它,任何一次回调丢失都会变成一笔“糊涂账”。

5.3 图片上传后不显示

菜品图片是点餐系统的门面,所有图片上传到服务器后要保存一个可访问的 URL。这里最常见的问题是:开发环境图片能显示,部署后图片全裂了。

原因基本就两个:

我的习惯是项目里统一一个常量叫 ,所有图片接口返回完整 URL,前端不再自己拼接。这样哪个环境出问题,改配置一处就能解决。

5.4 新版小程序无法即时生效

小程序发布新版本后,用户端不会立刻更新,很多人还跑在旧版本上。如果你急着修复线上问题,这个小细节会让人很头疼。我在 app.js 的 里加了 的处理:

const updateManager = wx.getUpdateManager();
updateManager.onCheckForUpdate((res) => {
  if (res.hasUpdate) {
    updateManager.onUpdateReady(() => {
      wx.showModal({
        title: '更新提示',
        content: '新版本已经准备好,是否重启应用?',
        success: (res) => {
          if (res.confirm) {
            updateManager.applyUpdate();
          }
        }
      });
    });
  }
});

这个代码加上之后,用户打开小程序时会收到更新提示,一键重启进入新版本。虽然微信最终都会自动覆盖旧版本,但主动弹窗能显著减少用户停留在旧版本的时间,减少很多不必要的麻烦。

最后再分享一个我个人的体会:做这类带支付、带后台、带文档的小程序项目,真正难的不是某一个技术点,而是把用户端体验、商家端效率、代码可维护性、文档清晰度全部串起来。我做完这套系统后,最大的收获不是代码量,而是养成了一个习惯——每写一个功能模块,先问自己三个问题:这个流程会不会崩?别人接不接得住?文档要不要补?如果你也准备做类似项目,建议你从一开始就把这三件事放在心上。

公告:
1. 本站所有资源来源于用户上传和网络,如有侵权请联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系站长处理!
6. 本站不售卖代码,资源标价只是站长收集整理的辛苦费!如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
7. 站长QQ号码 2205675299

资源库 - 资源分享下载网 » 微信小程序在线订餐系统全流程开发实践与源码解析

常见问题FAQ

关于资源售价和售后服务的说明?
本站所有资源的标价均为本站收集资源的辛苦费,不代表资源本身的价值。软件是高智慧高价值的商品,不可能是白菜价。本站资源标价只是赞助费用,收取的赞助费仅用来维持本站的日常运营!毕竟收集整理资料需要投入云计算资源和站长大量的精力。
代码有没有售后服务和技术支持?
由于代码的运行具有不可预见性,本站不保证代码完整可运行,不提供技术支持和售后服务。 本站原创代码都是站长自己开发的,可以有偿提供技术支持服务。 网站里标明【亲测】的代码都是站长亲测过的,其他的代码由于精力有限,没有一一测试,不能保证代码就一定能够使用,更没有技术支持服务,下载前请自行斟酌。
有没有搭建服务?
由于搭建服务比较费时费力,所以本站除了原创代码外均不提供搭建服务。本站分享代码纯属兴趣爱好,不以盈利为目的,请勿咨询有没有搭建服务,谢谢理解。
链接地址失效了怎么办?
请带上资源链接地址联系客服,工作时间内我们看到后将第一时间回复。
关于解压密码
本站资源一般都没有加密,如果发现需要解压密码的,那么就输入 hao.35dc.com 试试。

发表评论

资源库,由老程序员细心甄别、精心筛选,只为提供优质的源码资源

关于我们 联系我们