Java后端+微信小程序外卖系统毕业设计全解析
2026/8/29 10:41:10 网站建设 项目流程

简介:前后端分离架构正在成为Web开发的主流实践,后端提供接口、前端负责交互,两者通过API联调完成业务闭环。Spring Boot作为Java生态中主流的快速开发框架,以“约定大于配置”的理念大幅降低了服务端搭建门槛;微信小程序则凭借轻量化和高触达能力,成为移动端应用的热门载体。二者结合,能够高效实现用户登录、菜单浏览、下单支付、订单状态流转等完整业务链路,非常适合用于餐饮外卖等场景的工程练习与毕业设计。一套完整的餐饮外卖系统,其数据库表结构、订单状态机、核心接口设计到小程序端交互实现,覆盖了全栈项目的关键环节。通过梳理这些内容,并整理常见部署问题与答辩思路,零基础读者可以快速理解并跑通项目。 拿到这种“源码+说明+数据库+演示视频”四件套的毕业设计项目,第一反应往往不是“我终于有东西交了”,而是“我该怎么把它跑起来、讲清楚、应付答辩”。这套餐饮外卖系统我前后拆过好几遍,算是典型的 Java 后端 + 微信小程序前端组合,今天直接把底层逻辑、核心表结构、接口设计和小程序端的实现细节全部摊开讲,顺便把我自己踩过的坑也一起放出来,争取让零基础的人也能看完就跑通。

先说结论:这套项目用一句话概括就是“Java 做外卖业务的后端大脑,微信小程序做用户手里的点餐前台,MySQL 存所有业务数据”。它面向的是学生、毕业设计者、刚入职想练手的新人,尤其是对“小程序 + 后端接口联调”这套流程还没有完整认知的人。整个项目麻雀虽小五脏俱全,从用户登录、浏览菜单、加购物车、下单支付(通常是模拟支付)、骑手接单、订单状态流转,到用户历史订单查询,一条完整的外卖闭环全都覆盖。看懂它,你不仅能把毕设交差,还能在答辩时把“我为什么这么设计”讲出底气。

1. 项目定位与整体设计思路

1.1 从外卖场景拆解系统需求

外卖系统表面上看起来功能不多,但一旦认真拆解,涉及的模块远比想象中复杂。从用户的视角出发,外卖 App 要做的事至少包括:注册登录、浏览商家、查看菜单、加入购物车、提交订单、支付订单、查看订单状态、确认收货、历史订单查询。从商家或平台视角出发,还需要处理菜品管理、订单接单、订单状态更新、销售数据统计等后台功能。

这套毕业设计项目把用户端和后台管理端都包含进来了,只不过用户端做成了微信小程序,管理端则是用传统的 Web 页面(通常是基于 Bootstrap 或 Vue 的简单后台)实现。这样的设计有一个很实际的好处:在答辩演示时,你可以用手机演示“用户用小程序点外卖”,再切换到电脑浏览器演示“管理员在后台处理订单”,两个角色串起来就是一个完整的外卖业务闭环,演示效果非常直观。

另外一个关键点是:这套系统在业务设计上刻意做了一定程度的“简化”,比如支付环节通常使用模拟支付、不接真实第三方支付通道;配送环节不接真实地图定位,而是用一个配送状态字段来模拟“骑手接单、配送中、已送达”等阶段。这种简化不是偷懒,而是毕业设计的常见取舍——把核心业务链路做完整,把非核心环节用合理的方式替代,重点在于展示业务逻辑的闭环能力和技术选型的合理性。

1.2 技术栈选型:为什么是 Java + 微信小程序

在这个项目里,后端采用 Java 技术栈,前端用户端采用微信小程序原生开发,管理后台则使用传统的 Web 页面。这套组合在毕业设计里出场率非常高,不是没有原因的。

Java 后端的选择空间非常大,绝大多数毕业设计都会选择 Spring Boot 作为基础框架。Spring Boot 的好处是“约定大于配置”,大幅降低了项目搭建的门槛,一个简单的 Spring Boot 工程只需要在 pom.xml 中引入相关依赖,就能快速提供 RESTful API 接口。同时 Spring Boot 对 MyBatis 或 JPA 都有非常成熟的整合方案,操作 MySQL 数据库很方便。Maven 做依赖管理也比以前手动导 jar 包省心太多。

选择微信小程序作为用户端,一是因为微信用户基数大,小程序的传播和打开成本低,不用额外安装 App;二是因为小程序开发本身的语法(WXML、WXSS、JS)与前端基础相似,学习曲线不算陡峭;三是毕业设计用小程序展示,在演示环节比传统网页更直观、更有说服力。

后端使用 Java 的原因也很现实:Java 在高校教学中的普及率极高,绝大多数计算机相关专业的学生在校期间都系统学过 Java,选择 Java 做后端意味着你不需要从零开始学一门新的服务端语言,而且 Java 生态对数据库操作、接口开发、部署运维等方面的方案都非常成熟,遇到问题也容易查到解决方案。

提示:如果你还想让项目看起来更“高级”一点,可以额外引入 Redis 做缓存、RabbitMQ 做订单消息队列。但核心的 Spring Boot + MyBatis + MySQL 组合已经足够支撑毕业设计的全部功能。在此之上做拓展是加分项,但没有也不会影响项目完整性。

1.3 交付物清单:源码、说明、数据库、演示视频分别怎么用

这套项目的压缩包里有四样东西:源码、说明文档、数据库脚本、演示视频。很多学生拿到手第一步就去看源码,这种顺序其实是错的。

我建议的顺序是:先看演示视频,再看说明文档,然后导入数据库,最后打开源码。演示视频能让你在 5 分钟内知道这个系统长什么样、有哪些功能、页面之间怎么跳转;说明文档则把项目结构、技术栈、部署步骤写得很清楚,相当于一份最简操作手册;接下来把数据库脚本导入 MySQL,保证底层的表结构就绪,最后再打开源码,启动后端服务并运行小程序,这时候你面前的就是一个能跑通全流程的外卖系统了。

说明文档通常是写论文和答辩 PPT 的重要参考。它一般包含需求分析、功能模块图、数据库设计、核心代码说明等章节,这些内容可以直接沿用到你的毕业论文里。但不要原文照抄,一是查重过不了,二是一旦答辩老师深问细节,你答不上来反而更难看。正确做法是把文档作为框架参考,自己理解的细节再重新表述。

2. 数据库设计与核心表结构

2.1 六大核心数据表:从用户到订单的完整链路

外卖系统的数据库设计是整个项目的基础,数据表之间的关系直接影响业务逻辑的实现。这套项目的数据库脚本通常包含以下核心数据表:

  • 用户表(user):存储微信用户的 openid、昵称、头像、手机号、地址等信息。openid 是微信小程序用户的唯一标识,通常用它来关联用户身份,而不是让用户手动输入用户名密码注册。
  • 商家/店铺表(shop):存储店铺名称、头像、起送价、配送费、营业状态等信息。虽然大部分毕设只做一个商家,但表结构仍然设计成可扩展的多商家模式,这也是一个答辩加分点。
  • 菜品分类表(category):将菜品按“热销、主食、饮品、小吃”等分类,关联到店铺。
  • 菜品表(dish):菜品名称、图片、价格、月售量、描述、上架状态、所属分类、所属店铺。
  • 购物车表(cart):记录用户加入购物车的菜品、数量、单价、店铺标识。
  • 订单表(orders):订单号、用户 ID、店铺 ID、下单菜品快照(以 JSON 或关联菜品表的方式存储)、订单总金额、配送地址、订单状态、下单时间、支付时间、送达时间等。
  • 订单明细表(order_detail):订单与菜品是多对多关系,通过明细表记录每个订单中有哪些菜品、数量、当时的价格快照。订单主表存订单整体信息,订单明细表存订单内每一道菜的信息,两张表配合使用。
  • 地址表(address):用户的收货地址列表,包含联系人、电话、详细地址、默认地址标识。

在这个结构里,最核心的关系是“用户—订单—菜品”三角关系。用户下订单,订单关联多个菜品,订单明细表作为中间表记录数量与价格。数据库设计的关键原则是“订单不直接引用菜品表的价格”,而是把下单瞬间的菜品价格冗余到订单明细表里。这样做的好处是:就算以后菜品改价了,历史订单里的支付金额和菜品快照也不会被影响。

2.2 订单状态机:外卖业务中最容易出问题的环节

订单状态是整个外卖系统里最核心的业务字段。这套项目里,订单状态通常用整型数字表示:

  • 0:待支付,用户下单但未完成支付
  • 1:待接单,已支付成功,等待商家接单
  • 2:待配送(已接单),商家已接单但还没分配给骑手
  • 3:配送中,骑手正在配送
  • 4:已完成(已送达),用户确认收货或系统自动确认
  • 5:已取消,用户取消或商家拒单

这个状态机允许状态往下流转,但不允许任意跳转。比如待支付状态只能变成已取消或待接单,不能直接变成已完成。实现时最粗暴的方式是在 Service 层用 if 判断当前状态与目标状态是否允许切换。比如执行“商家接单”操作时,先判断当前订单状态是否为“待接单”,如果不是就直接抛异常,这样能避免脏数据出现。

有一个容易被忽略的细节:订单超时未支付自动取消。很多毕设版本没有实现这个功能,只能手动更新状态。如果有精力,可以用 Java 的定时任务(Spring Schedule)每过一段时间扫描状态为“待支付”且创建时间超过 30 分钟的订单,自动把状态置为“已取消”并回滚库存。这个功能加进去,项目完整性一下子就上来了。

2.3 数据库初始化脚本与常见坑

这套项目的 db 目录下通常会有一个init.sqlfood.sql文件,里面包含建库建表和初始数据(比如店铺信息、菜品分类、菜品数据、一个测试账号)。导入方式很简单:用 Navicat 或命令行执行source /path/to/xxx.sql即可。

我在导入时踩过两个坑。第一个是 MySQL 版本不一致导致 SQL 语法报错,比如 8.0 的一些写法(如utf8mb4_0900_ai_ci排序规则)在 5.7 上不兼容。解决方法是用文本编辑器打开 SQL 文件,把排序规则统一改成utf8mb4_general_ci。第二个坑是 JDK 和 MySQL 驱动版本不匹配,比如 MySQL 8.0 以上需要使用com.mysql.cj.jdbc.Driver,老项目里写的是com.mysql.jdbc.Driver,启动后端会报找不到驱动类的错误。把application.ymldb.properties里的驱动类改对就好了。

3. 后端接口设计与核心业务实现

3.1 Spring Boot 项目结构:分层是答辩加分项

这套项目的后端通常采用经典的分层架构:Controller(控制层)、Service(业务层)、Mapper(数据持久层)、Entity(实体类)。每一层的职责非常明确:

  • Controller 只负责接收 HTTP 请求、调用 Service、返回 JSON 结果,不写任何业务逻辑。
  • Service 层承载核心业务逻辑,比如下单要校验菜品是否存在、库存是否充足、金额是否计算正确。
  • Mapper 层用 MyBatis 负责数据库的增删改查,接口方法与 XML 中的 SQL 一一对应。
  • Entity 实体类与数据表结构一一映射,ORM 映射字段时注意数据库下划线命名与 Java 驼峰命名的自动转换。

对答辩来说,去背这些层的作用是不够的。更建议的做法是,拿出项目中的一个核心流程(例如“用户点餐下单”)完整的走一遍:用户在小程序点击“提交订单”,小程序调用后端的/order/create接口;Controller 在接收到请求后先通过 Token 解析出用户身份,然后调用 OrderService.createOrder();在 Service 层里,第一步根据菜品 ID 列表查出全部菜品及最新价格,第二步计算总价并生成订单号,第三步写入订单主表和订单明细表,第四步清空该用户的购物车数据;如果任何一步出错,事务回滚,整个操作就像没有发生过一样。

这一套下来,既讲清楚了你做了什么事,又体现出了你明白“分层是为了什么”。

3.2 下单流程的核心接口实现

我直接说下单接口的处理逻辑,这是整个后端最核心的接口,没有之一。

@PostMapping("/order/create") public Result createOrder(@RequestBody OrderCreateDTO dto, @RequestHeader("token") String token) { // 1. 解析 token 获取用户 ID Integer userId = userService.getUserIdByToken(token); // 2. 查询购物车中该用户勾选的菜品列表 List<CartItem> cartItems = cartMapper.selectCheckedItems(userId); if (cartItems.isEmpty()) { return Result.error("购物车为空,无法下单"); } // 3. 生成订单主表记录 Orders order = new Orders(); order.setOrderNo(generateOrderNo()); order.setUserId(userId); order.setShopId(cartItems.get(0).getShopId()); order.setTotalAmount(calculateTotal(cartItems)); order.setStatus(0); // 待支付 order.setCreateTime(new Date()); orderMapper.insert(order); // 4. 遍历购物车,写入订单明细表 for (CartItem item : cartItems) { OrderDetail detail = new OrderDetail(); detail.setOrderId(order.getId()); detail.setDishId(item.getDishId()); detail.setDishName(item.getDishName()); detail.setDishImage(item.getDishImage()); detail.setPrice(item.getPrice()); detail.setQuantity(item.getQuantity()); orderDetailMapper.insert(detail); } // 5. 清空该用户的购物车 cartMapper.cleanCart(userId); return Result.success(order); }

这里有两个必须强调的细节。第一,订单明细表里保存的dish_namedish_image是冗余字段,下单时就已经把菜名和图片复制过来了。这样设计的好处是:以后菜品改名或删除,已生成的订单仍然能正常显示历史菜品信息,不会出现“订单里的菜被删了,历史订单显示空白”的尴尬情况。第二,整个下单过程必须加@Transactional事务注解,确保“生成订单主表 + 生成订单明细 + 清空购物车”要么全部成功,要么全部失败。不加事务的话,如果写入明细时中断,主表订单会变成无内容的“幽灵订单”。

订单号生成也是一个值得在答辩时讲的细节。不要用数据库自增 ID 直接当订单号返回给前端,因为这样会把平台的当天订单量暴露给用户,而且容易被遍历爬取。更合适的做法是生成一个唯一业务订单号,比如yyyyMMddHHmmss + 用户ID后四位 + 随机数,既保证可读性,又不容易撞号。

3.3 接口安全与跨域:小程序调用后端的三道坎

小程序调后端接口和浏览器调接口有几个明显区别,这在实际联调时是最容易出问题的地方。第一个坎是跨域问题。微信小程序里wx.request的域名必须在微信公众平台配置白名单,开发模式下可以在开发者工具里勾选“不校验合法域名”,但手机真机预览时,仍然需要后端处理好 CORS(跨域资源共享)配置。

Spring Boot 里最简单的跨域处理方式是写一个配置类:

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }

第二个坎是用户身份识别。小程序端没有传统的 Cookie 会话机制,通常的做法是登录时调用wx.login()获取 code,然后把 code 发给后端,后端再调用微信接口换取 openid,并生成一个自定义 token 返回给小程序端。小程序端把这个 token 存在本地 storage 里,后续每次请求都放在请求头中携带。

第三个坎是接口返回 JSON 格式的统一。建议提前封装一个统一的 Result 对象,包含codemessagedata三个字段。前端小程序封装一个request.js工具函数,统一处理请求头、错误提示和 Token 失效跳转,这样页面代码里只需要关心成功后的数据逻辑。

4. 微信小程序端界面与交互实现

4.1 小程序整体页面结构与 tabBar 设计

这套项目的小程序端通常包含 4 个底部导航栏页面(tabBar):

  • 首页:展示店铺信息和推荐菜品,通常有轮播图、店铺卡片、菜品分类入口。
  • 点餐/菜单:左侧是菜品分类,右侧是菜品列表,支持点击加购。
  • 订单:展示用户的历史订单列表,点击进入订单详情,不同状态显示对应操作按钮(去支付、确认收货、再来一单等)。
  • 我的:展示用户信息、收货地址管理、设置等入口。

小程序的app.json中通过tabBar字段配置底部导航,pages数组里配置所有页面路径。对于没有加入 tabBar 的子页面,比如订单详情页、地址编辑页、支付结果页,直接通过wx.navigateTo跳转即可。

tabBar 的 icon 通常需要准备 81px * 81px 的 PNG 图标。如果没有设计资源,可以临时用文字替代,或者从免费的 icon 网站下载。tabBar 的图标不能用网络图片,必须放在本地目录下,这也是很多人第一次配置 tabBar 时容易踩的坑。

4.2 点餐加购与购物车:滑动加购的交互细节

点餐页面是外卖小程序的核心交互场景,最常见的交互方式是:左侧显示分类列表,右侧用 scroll-view 显示该分类下的菜品,每个菜品右侧显示“+”(加号按钮)。点击加号时菜品数量 +1,同时页面底部的购物车栏会同步更新总价和总数量。

这个交互的实现方式比较简单。每个菜品数据中用一个count字段表示当前已加购数量,点击加号时把该字段 +1,同时更新一个全局的购物车数组。页面底部购物车栏监听购物车数组的变化,用setData刷新总价和总数量。

这里有一个体验细节值得注意:页面底部购物车栏应该是吸底固定的,通常用position: fixed; bottom: 0;实现。当购物车中有商品时,栏上会显示“去结算”按钮和总金额;没有商品时,按钮置灰并显示“购物车是空的”。这个小细节很影响用户感受,答辩演示时也容易操作,建议优先做好。

另一个值得做的小功能是“清空购物车”和“商品减一”。在购物车展开面板里,每样商品要支持减号操作,数量减到 0 时自动移除。这套逻辑虽然简单,但涉及数组的遍历和赋值,建议把购物车的增删逻辑统一封装到一个公共 JS 文件或自定义组件里,避免多个页面重复写代码。

4.3 订单列表与状态展示:把后端数据对上号

订单模块在小程序端是另一个核心页面。订单列表的数据来源是后端/order/list接口,返回该用户所有订单的摘要信息。列表中需要展示订单编号、店铺名称、菜品图片(通常取第一个菜品的图片)、菜品数量、总价、订单状态、下单时间。

订单状态展示的建议是:不要直接用“0、1、2、3”这样的数字显示给用户,而是在前端做一个状态映射,比如:

const orderStatusMap = { 0: '待支付', 1: '待接单', 2: '待配送', 3: '配送中', 4: '已完成', 5: '已取消' };

订单列表的排序建议按创建时间倒序,最新的订单排在最前面。已取消或已完成的订单可以置灰显示,待支付的订单高亮显示并放一个醒目的“去支付”按钮。点击订单列表项可以跳转到订单详情页,详情页除了展示订单全部信息外,还需要根据订单状态显示不同的操作按钮:

  • 待支付:显示“去支付”“取消订单”
  • 待接单/待配送/配送中:显示“催单”或暂不显示操作
  • 已完成:显示“再来一单”

“再来一单”功能其实做起来很简单,就是把上一单的菜品清单拿到购物车数组里,然后跳转到点餐页,用户可以再点一次“去结算”。这个功能虽然不大,但会让演示时考官觉得系统思路到位。

5. 从部署到答辩:完整运行流程与高频问题排查

5.1 本地运行环境配置全过程

要把整套项目跑起来,需要依次完成以下准备:

  1. 安装 JDK 1.8(部分版本可能需要 JDK 11),配置JAVA_HOME环境变量,并在命令行输入java -version验证。
  2. 安装 Maven,配置MAVEN_HOME,并确认settings.xml中使用的阿里云镜像源。
  3. 安装 MySQL 5.7 或 8.0,导入数据库脚本,创建一个专门的数据库账号(通常是 root / 123456 或项目文档中指定的账号)。
  4. 用 IDEA 打开后端源码,等待 Maven 自动下载依赖。首次加载依赖可能需要几分钟,如果网络不好,建议先配置好 Maven 国内镜像源再打开项目。
  5. 修改application.yml里的数据库连接信息,确保账号密码、数据库名、端口号与你本地 MySQL 一致。
  6. 启动后端项目,看到 “Started Application in x.x seconds” 的日志即表示启动成功。可以先用浏览器访问http://localhost:8080/或 Swagger 接口文档地址验证接口是否正常。
  7. 用微信开发者工具打开小程序前端源码,在app.js或某个配置文件中把接口请求的 baseURL 改成http://localhost:8080。注意微信开发者工具需要在“详情 -> 本地设置”里勾选“不校验合法域名”,否则请求会被拦截。
  8. 小程序编译运行,此时应该可以完成从登录到点餐下单的完整流程。

5.2 我实测中遇到的高频问题与解决方案

我把以前调试这类项目时遇到的高频问题整理成一份速查表,遇到问题可以直接对照排查。

问题现象可能原因解决方案
后端启动报错Access denied for user 'root'@'localhost'数据库账号密码错误检查application.yml中的账号密码是否与本地 MySQL 一致
后端启动报错Unknown database 'xxx'数据库未创建先执行CREATE DATABASE xxx,再导入 SQL 脚本
小程序请求接口报ERR_CERT_COMMON_NAME_INVALID请求了 HTTPS 接口但证书不合法开发环境把 baseURL 改成 http,并勾选“不校验合法域名”
小程序请求接口报request:fail后端未启动、baseURL 不对、或 CORS 未配置依次检查后端是否启动、baseURL 是否加了端口号、CORS 是否允许
后端连接数据库报Public Key Retrieval is not allowedMySQL 8.0 驱动连接参数缺失在 JDBC URL 后追加?allowPublicKeyRetrieval=true&useSSL=false
中文乱码数据库连接未指定 UTF-8URL 后追加characterEncoding=utf-8&serverTimezone=Asia/Shanghai
真机预览时图片不显示图片路径是 localhost用内网 IP 或图片服务器地址替换 localhost
订单状态一直不更新前端请求成功但状态未刷新检查状态字段的映射关系,确认是否用了数字而不是字符串

5.3 给答辩的几点建议:如何把毕业设计讲出亮点

很多学生把项目跑通就以为万事大吉,结果答辩时被老师一问就卡壳。这里整理几个高频问题和对应的回答思路。

“这个系统有什么创新点?”不要只说“我用了 Spring Boot”,要结合实际细节。比如“针对外卖订单高并发场景,我在下单模块使用了数据库事务和唯一订单号生成策略,保证了数据一致性”或者“为了优化用户点餐体验,菜品加购逻辑采用本地缓存 + 后端同步的策略,降低了接口请求频率”。

“订单状态是怎么流转的?”直接讲状态机:待支付 -> 待接单 -> 待配送 -> 配送中 -> 已完成。然后说明每个流转动作触发的时候后端做了哪些校验,比如“用户取消订单只能取消待支付或待接单状态,配送中订单不能随意取消”。

“数据库设计时有哪些考虑?”讲三方面:一是订单明细表冗余了菜品名称和图片,保证历史订单的可追溯性;二是订单状态用 int 而不是 varchar,节省存储空间且便于状态机判断;三是用户表以微信 openid 作为唯一标识,省去了用户名密码注册流程,降低了登录门槛。

答辩的核心不是背代码,而是把“你为什么这么设计”讲出自己的思考过程。就算是参考了别人的项目,只要你能把核心流程、表关系、状态流转讲清楚,老师基本不会为难你。

从我个人的经验来看,这类毕设项目的价值不在“代码本身有多复杂”,而在于你借这个机会把“需求分析 -> 数据库设计 -> 接口开发 -> 前端联调 -> 部署演示”的完整链路走了一遍。这套外卖系统最大的优点是业务场景贴近生活,模块划分清晰,非常适合用来建立对全栈项目的第一印象。如果你正在准备答辩,建议把下单流程、订单状态流转和数据库表关系这三块吃透,这三个问题答好了,整个答辩基本就稳了。后面如果还有时间,不妨从“评价/评分”、后端接入 Redis 缓存、或增加骑手角色这几种方向做一次扩展尝试,这些方向选一个做深,项目的含金量会再上一个台阶。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询