ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

微信小程序外卖点餐系统源码:SpringBoot三端架构与订单状态流转实战

微信小程序外卖点餐系统源码:SpringBoot三端架构与订单状态流转实战 简介本资源为基于微信小程序的外卖点餐系统毕业设计完整资料包面向计算机相关专业学生及Java全栈初学者解决传统餐饮点餐效率低、信息不透明等问题。系统前端采用微信小程序与Vue框架后端基于SpringBoot数据库选用MySQL涵盖用户浏览美食、下单购买、购物车与订单查询、优惠券查看以及商家美食信息管理、订单处理、优惠券配置和管理员分类审核、订单统计等模块可作为课程设计或毕业设计的参考方案。资源包为zip格式压缩包约33.44MB内含源码、数据库脚本与运行说明等文件便于快速部署与二次开发。目前已有84人学习下载适合需要完整项目实战、理解前后端数据交互与业务逻辑处理的学习者参考借鉴。1. 从一份能跑起来的外卖小程序源码说起很多做毕业设计或接私活的朋友都遇到过这种局面需求文档写得天花乱坠真到动手时卡在环境搭建、接口联调、数据库导入这些琐事上一周过去连登录页都没跑通。这份「基于微信小程序的外卖点餐系统」源码包恰好是冲着这个痛点来的——它把用户端、商家端、管理员端三套角色的完整业务链路都做完了前端是微信小程序加 Vue 技术栈后端 SpringBoot数据落 MySQL附带数据库脚本和运行说明。拿到手之后你不需要从零设计表结构也不用纠结订单状态怎么流转直接导入、改配置、跑起来就能看到一个能下单、能管理菜品、能核销优惠券的完整系统。它适合三类人赶毕业设计进度的学生、想拿一个成熟业务骨架做二次开发的开发者、以及需要快速验证餐饮类产品逻辑的创业者。下面我按「先看懂架构、再动手跑通、最后避开坑」的顺序把这份资源拆开讲。2. 三端角色与 SpringBoot 分层架构先看懂再动手2.1 用户、商家、管理员三端到底各管什么外卖点餐系统看着简单真正落地时最容易乱的就是权限边界。这份源码把角色拆得很清楚你导入数据库后能看到对应的角色表和权限字段。用户端跑在微信小程序里核心动作是浏览美食分类、把菜品加进购物车、提交订单、查看历史订单和优惠券。这里有个细节值得注意购物车数据在小程序端是本地缓存加服务端同步双写的也就是说用户退出小程序再进来购物车不会丢这个设计比纯本地存储靠谱得多。商家端负责的是美食信息维护、优惠券配置和订单处理。商家只能看到自己店铺的数据这个隔离是靠后端在查询时拼shop_id条件实现的不是靠前端隐藏菜单安全性上更稳。管理员端权限最大管美食分类、审核商家提交的信息、管理全平台优惠券和订单统计。三端共用一套 SpringBoot 后端通过角色字段做接口级鉴权。角色核心功能数据可见范围用户浏览、下单、购物车、订单查询、优惠券仅本人数据商家美食管理、优惠券配置、订单处理仅本店铺数据管理员分类管理、信息审核、订单统计全平台数据2.2 SpringBoot 后端的分层与接口组织后端用的是典型的 Controller-Service-Mapper 三层结构配合 MyBatis 做数据库映射。你打开源码的src/main/java目录能看到按模块拆分的包controller负责接收小程序请求service写业务逻辑mapper对应 SQL 操作entity是数据库实体类。这种分层的好处是改需求时定位快。比如要加一个「满减优惠」规则你只需要在CouponService里改计算逻辑Controller 层几乎不用动。常见做法是把订单金额计算、优惠券抵扣这些容易出错的逻辑单独抽一个工具类这份源码也是这么处理的。接口返回统一用了一个Result封装类包含code、msg、data三个字段。小程序端拿到code判断成功失败data里才是真正的业务数据。这个约定很重要后面你调接口时如果发现数据取不到先看code是不是 200。// 典型的 Controller 写法接收小程序端请求 RestController RequestMapping(/api/order) public class OrderController { Autowired private OrderService orderService; // 用户提交订单参数从请求体里取 PostMapping(/submit) public Result submit(RequestBody OrderDTO orderDTO) { // 校验购物车是否为空、收货信息是否完整 if (orderDTO.getItems() null || orderDTO.getItems().isEmpty()) { return Result.error(购物车为空); } // 调用 Service 层处理下单逻辑返回订单号 String orderNo orderService.createOrder(orderDTO); return Result.success(orderNo); } }这段代码里RequestBody表示参数以 JSON 格式传入OrderDTO是数据传输对象里面装了菜品列表、用户 ID、收货地址等。orderService.createOrder才是真正干活的地方它会做库存扣减、优惠券核销、订单号生成这些操作。你二次开发时如果要加「预约下单」功能就在这个 DTO 里加个时间字段然后在 Service 里判断即可。2.3 数据库表结构与关键字段设计数据库脚本在源码包的sql目录下导入 MySQL 后大概有十几张表。核心表包括用户表、商家表、美食表、分类表、购物车表、订单表、订单详情表、优惠券表。订单表的设计有个地方值得留意订单主表和订单详情表是分开的。主表存订单号、用户 ID、总金额、订单状态、创建时间详情表存每一道菜的名称、单价、数量。这样设计的好处是查订单列表时不用联表查菜品速度快查订单详情时再用订单号去详情表捞数据。订单状态字段用的是数字枚举常见做法是 0 待付款、1 已付款、2 配送中、3 已完成、4 已取消。你在改状态流转逻辑时一定要在 Service 层加状态校验防止出现「已取消的订单又被改成已完成」这种脏数据。-- 订单主表关键字段 CREATE TABLE orders ( id int NOT NULL AUTO_INCREMENT, order_no varchar(32) NOT NULL COMMENT 订单编号, user_id int NOT NULL COMMENT 下单用户, total_amount decimal(10,2) DEFAULT 0.00 COMMENT 订单总金额, status tinyint DEFAULT 0 COMMENT 0待付款 1已付款 2配送中 3已完成 4已取消, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;order_no加了唯一索引防止重复下单生成相同订单号。total_amount用decimal而不是float这是金额字段的基本要求避免浮点精度丢失。utf8mb4字符集能存 emoji用户昵称里带表情也不会报错。3. 从导入数据库到小程序联调完整跑通流程3.1 环境准备与数据库导入动手之前先把环境对齐。后端需要 JDK 1.8 或以上、Maven 3.6、MySQL 5.7 或 8.0。小程序端需要微信开发者工具Vue 部分如果单独跑需要 Node.js 14。第一步是建库导数据。用 Navicat 或者命令行都行我一般用命令行快且不容易出错。# 登录 MySQL 并创建数据库 mysql -u root -p CREATE DATABASE takeout DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE takeout; # 导入源码包里的 sql 文件路径按你实际存放位置改 source /path/to/takeout.sql; # 确认表都建好了 SHOW TABLES;导入完成后执行SHOW TABLES应该能看到十几张表。如果报错说字符集不支持检查 MySQL 版本5.7 以下对utf8mb4支持不完整建议升级。导入后先别急着跑后端用SELECT * FROM user LIMIT 5看看有没有初始账号数据通常源码会带一个管理员账号密码是加密存储的。3.2 后端配置修改与启动数据库通了之后改后端配置文件。找到src/main/resources/application.yml把数据库连接信息换成你自己的。spring: datasource: url: jdbc:mysql://localhost:3306/takeout?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver # 文件上传路径商家上传菜品图片会存到这里 servlet: multipart: max-file-size: 10MBserverTimezoneAsia/Shanghai这个参数必须加否则插入订单时间会差 8 小时这个坑我见过太多次。max-file-size控制图片上传大小默认 1MB 传菜品图容易失败改成 10MB 比较稳妥。配置改完用 Maven 打包启动# 在项目根目录执行跳过测试加快速度 mvn clean package -DskipTests # 启动 jar 包 java -jar target/takeout-0.0.1-SNAPSHOT.jar看到控制台输出Started Application in x seconds就说明后端起来了。如果启动报Table takeout.xxx doesnt exist说明数据库导入不完整重新导一次。如果报端口占用改application.yml里的server.port。3.3 小程序端配置与接口联调小程序端用微信开发者工具打开源码里的miniprogram目录。第一件事是改请求地址找到utils/request.js或者config.js把baseUrl改成你后端跑起来的地址。// 小程序端请求封装baseUrl 指向本地后端 const baseUrl http://localhost:8080/api; function request(options) { return new Promise((resolve, reject) { wx.request({ url: baseUrl options.url, method: options.method || GET, data: options.data || {}, header: { Content-Type: application/json }, success: (res) { // 后端统一返回 code/msg/data这里做拦截 if (res.data.code 200) { resolve(res.data.data); } else { wx.showToast({ title: res.data.msg, icon: none }); reject(res.data.msg); } }, fail: reject }); }); }这里code 200的判断和后端Result类是对应的。联调时如果小程序一直提示网络错误先在开发者工具里勾选「不校验合法域名」因为本地localhost不在微信白名单里。真机调试时要把localhost换成电脑的局域网 IP手机和电脑连同一个 WiFi。联调顺序建议是先测登录接口再测美食列表最后测下单。下单接口涉及库存和优惠券最容易出问题放到最后调。4. 订单状态流转与优惠券核销业务逻辑里的硬骨头4.1 订单状态机与并发下单处理订单状态流转是外卖系统里最容易写乱的地方。这份源码把状态变更集中在OrderService里每次改状态前先查当前状态是否允许变更。常见做法是定义一个状态流转表比如待付款只能变成已付款或已取消已付款只能变成配送中配送中只能变成已完成。你在 Service 里加一个checkStatusTransition方法不满足条件直接抛异常。并发下单是另一个坑。两个用户同时抢最后一份菜品如果不在数据库层面加锁会出现超卖。源码里用的是乐观锁方案在美食表加一个version字段更新库存时带上版本号。// 扣减库存的乐观锁写法 Update(UPDATE food SET stock stock - #{num}, version version 1 WHERE id #{foodId} AND stock #{num} AND version #{version}) int reduceStock(Param(foodId) int foodId, Param(num) int num, Param(version) int version);如果返回的影响行数是 0说明库存不足或者版本号对不上Service 层要捕获这个情况并提示用户「手慢了菜品已售罄」。这个方案比synchronized性能好适合外卖这种读多写少的场景。4.2 优惠券的领取、绑定与核销优惠券逻辑分三步领取、下单时绑定、支付后核销。源码里优惠券表有个status字段0 未使用、1 已使用、2 已过期。用户领券时插入一条记录下单时查询该用户所有未使用的券按满减条件筛选出可用的让用户选一张。这里要注意优惠券的user_id必须和下单用户一致否则会出现 A 用户用了 B 用户券的漏洞。核销动作放在支付回调里。支付成功后把优惠券状态改成已使用同时记录使用的订单号。如果支付失败或者订单取消要把券退回去状态改回未使用。这个「退回」逻辑很多源码会漏掉你二次开发时记得补上。// 核销优惠券支付成功后调用 public void useCoupon(int couponId, String orderNo) { Coupon coupon couponMapper.selectById(couponId); // 校验券是否属于当前用户、是否未使用 if (coupon null || coupon.getStatus() ! 0) { throw new BusinessException(优惠券不可用); } coupon.setStatus(1); coupon.setUseOrderNo(orderNo); couponMapper.updateById(coupon); }BusinessException是自定义异常配合全局异常处理器返回统一错误信息。useOrderNo字段记录券用在哪一单方便后续对账和退款时回退。4.3 购物车与订单的数据一致性购物车在小程序端有本地缓存用户点「去结算」时才把数据提交到后端生成订单。这里有个一致性问题用户在小程序里改了购物车数量但本地缓存没同步到服务端结算时金额对不上。源码的处理方式是结算前先调一个「同步购物车」接口把本地数据推给后端后端以服务端数据为准计算金额。这样即使本地缓存被篡改金额也不会错。你测试时可以故意在小程序里把某道菜数量改成 999然后点结算看后端返回的金额是不是按实际库存和价格算的。如果直接用了本地传过来的金额那就是个安全漏洞需要改。5. 避坑与排查那些让我熬夜的报错5.1 小程序请求后端一直 404现象是小程序端所有接口都返回 404但浏览器直接访问后端地址是通的。原因通常是baseUrl配错了比如多写了一个/api或者少写了。解决方法是打开微信开发者工具的 Network 面板看实际请求的完整 URL和后端 Controller 上的RequestMapping路径逐段比对。另外注意小程序请求默认走 HTTPS本地调试要在开发者工具里关掉域名校验。5.2 数据库中文乱码现象是菜品名称在数据库里显示正常但小程序端拿到的是问号。原因是数据库连接 URL 没加characterEncodingutf8或者表创建时用了latin1字符集。解决方法是检查application.yml里的连接串确保有useUnicodetruecharacterEncodingutf8同时用SHOW CREATE TABLE food确认表的字符集是utf8mb4。5.3 订单金额出现 0.01 元误差现象是用户结算金额和后台统计金额差几分钱。原因是用了float或double存金额浮点运算有精度损失。解决方法是把所有金额字段改成decimal(10,2)Java 里用BigDecimal做加减乘除并且指定保留两位小数、四舍五入模式。5.4 商家上传菜品图片失败现象是商家端选完图片点保存后端报MaxUploadSizeExceededException。原因是 SpringBoot 默认上传限制是 1MB手机拍的菜品图轻松超过。解决方法是在application.yml里把spring.servlet.multipart.max-file-size和max-request-size都调到 10MB 或更大同时检查服务器磁盘空间。5.5 优惠券领取后不显示现象是用户点了领取提示成功但优惠券列表里没有。原因是领取接口写入了数据库但列表查询接口的user_id条件写错了比如用了商家 ID 去查。解决方法是打开后端日志看列表查询实际执行的 SQL 和参数确认user_id是不是当前登录用户。另外检查优惠券的status字段如果领取时默认写成了 1已使用列表按未使用筛选自然查不到。6. 二次开发进阶把外卖系统改成校园食堂订餐这份源码的骨架足够干净改造成校园食堂订餐系统只需要动三个地方。第一个是角色模型食堂场景下商家就是窗口一个食堂有多个窗口你需要在商家表加一个canteen_id字段把窗口归属到食堂下面。第二个是取餐方式外卖是配送到地址食堂是到窗口自取订单表要加一个pickup_time字段记录预约取餐时间前端下单页把地址选择换成时间选择。第三个是支付方式校园场景常用余额支付你可以在用户表加balance字段下单时先扣余额再走微信支付兜底。改造时建议先跑通一条最小链路用户选窗口、选菜品、预约时间、余额支付、生成取餐码。这条链路通了再补优惠券和统计报表。数据库改动用ALTER TABLE增量执行别直接删表重建否则测试数据全丢。验证改造是否成功我一般用三个检查点一是并发下单同一窗口同一时段看会不会超卖二是取餐码生成后重复扫码看会不会重复核销三是余额扣减和订单金额是否一致用SELECT对账。这三个点过了基本就能交付。从那以后我每次拿到一份新源码都强制先跑通「登录-列表-下单」这条最短路径再去看架构和扩展点。顺序反了很容易陷在配置里出不来。希望这份拆解能帮你少走点弯路源码包里的运行说明写得还算清楚配合上面的步骤应该能顺利跑起来。本文还有配套的精品资源点击获取
返回列表