简介:这是一套面向计算机专业本科生的微信点餐系统毕业设计/课程设计完整源码,适用于小程序开发入门到进阶实践,解决从菜单展示、用户下单、订单管理到后台数据交互的一站式学习需求。资源共1285个文件,涵盖138个Vue页面组件(含首页、点餐、订单、用户中心等核心模块)、178个JS逻辑脚本、123个Java后端服务类(Controller/Service/DAO层齐全)、13.84MB压缩包内还包含MySQL 5.7建表SQL、Navicat数据库备份、Tomcat部署配置及uniapp与原生双框架适配代码。已有54人学习下载,配套说明文档详述环境搭建、前后端联调步骤与常见报错解决方案;内容预览可见多套.bak备份文件及install/run/build三阶段批处理脚本,体现工程化规范与可复用性设计,适合直接运行、二次开发或拆解学习全栈开发流程。
1. 这不是「套模板」的小程序,而是一套能真实跑通点餐闭环的微信小程序毕业设计源码
很多计算机专业学生拿到「微信点餐系统」毕设题目时,第一反应是去 GitHub 搜“weapp restaurant”,结果下载一堆只有前端页面、后端空壳、数据库字段缺失、连登录都报 500 的压缩包——最后熬夜改接口、补 SQL、硬啃微信支付文档,答辩前还在修 CORS 错误。而这份标题为【小程序毕业设计】微信点餐系统源码(完整前后端+mysql+说明文档).zip 的资源,核心价值在于它提供了一条从本地启动到功能验证的最小可行路径:前端基于原生微信小程序框架(非 uni-app 封装层),后端采用 Spring Boot 2.7.x(兼容 JDK 8/11),MySQL 5.7 兼容建表脚本,且所有接口路径、token 验证逻辑、订单状态机流转均按微信小程序实际调用链路对齐。它不追求高并发架构,但覆盖了用户扫码进店→浏览菜单→加购下单→管理员后台核销→MySQL 订单表与商品库存联动更新的全链路。适合需要在 2 周内完成部署、调试、录屏演示的本科毕设场景,也适合作为理解「小程序如何与传统 Java 后端安全交互」的实操切口。
2. 搭建环境:从解压到首次启动,绕过 90% 的新手卡点
这套源码的可复现性,高度依赖环境配置的确定性。常见失败不是代码问题,而是 JDK、MySQL、IDEA 版本组合引发的隐性冲突。以下步骤严格按毕业设计实操场景设计,跳过 Docker、云服务器等非必要环节,全部在 Windows/macOS 本地完成。
2.1 MySQL 5.7 快速就位(避免 MySQL 8.0 默认 strict mode 导致建表失败)
该源码的sql/restaurant_init.sql脚本使用了datetime类型默认值(如create_time datetime DEFAULT CURRENT_TIMESTAMP),这在 MySQL 5.7 是合法的,但在 MySQL 8.0.19+ 的严格模式下会报错。因此必须使用 MySQL 5.7(推荐 5.7.32 或 5.7.40 免安装版,官网已归档,搜索“mysql 5.7.40 zip”可得)。
提示:不要用 MySQL Installer 安装最新版,也不要尝试修改
sql_mode强行兼容。毕业设计阶段稳定性优先,5.7.40 是经大量毕设项目验证的黄金版本。
解压后执行初始化:
# 进入 MySQL bin 目录(例如 D:\mysql-5.7.40-winx64\bin) mysqld --initialize-insecure --user=mysql mysqld --install net start mysql然后用mysql -u root -p登录(初始密码为空),执行:
CREATE DATABASE restaurant_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE restaurant_db; SOURCE D:/your/path/sql/restaurant_init.sql; -- 注意路径用正斜杠或双反斜杠关键检查点:执行后应有t_user,t_food,t_order,t_order_item四张表,其中t_order.status字段为tinyint(2),取值范围 0(待支付)、1(已支付)、2(已核销)、3(已取消)——这是后续前端状态渲染和后端核销逻辑的依据。
2.2 后端 Spring Boot 项目导入与关键配置修正
使用 IntelliJ IDEA(2022.3 或以上)导入backend/目录为 Maven 项目。不要直接点击 Run,先修正三处配置:
2.2.1 修改application.yml中的数据库连接参数
spring: datasource: url: jdbc:mysql://localhost:3306/restaurant_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: # 若你设置了密码,请填入;否则留空 driver-class-name: com.mysql.cj.jdbc.Driver注意:serverTimezone=Asia/Shanghai是必须项,否则datetime字段插入时区错误导致时间乱码;useUnicode=true&characterEncoding=utf8确保中文菜名不乱码。
2.2.2 关闭微信支付自动初始化(避免因未配置密钥导致启动失败)
源码中WechatPayConfig.java会尝试加载wechatpay-apiclient并初始化 SDK。毕业设计若无需真实支付,注释掉@PostConstruct方法中initClient()调用,或在application.yml中添加:
wechat: pay: enabled: false并在 Controller 中将@PreAuthorize("hasRole('USER')")注解临时改为@PreAuthorize("permitAll"),跳过 JWT 校验快速验证接口。
2.2.3 设置 JVM 参数防止内存溢出
在 IDEA 的 Run Configuration → VM Options 中添加:
-Dfile.encoding=UTF-8 -Xms512m -Xmx1024mSpring Boot 2.7 默认使用 Tomcat 9.0.x,此内存配置足够支撑 50 并发以内的点餐操作。
启动成功标志:控制台输出Started RestaurantApplication in X.XXX seconds,且http://localhost:8080/swagger-ui.html可打开 Swagger 文档(含/api/user/login,/api/food/list,/api/order/create等核心接口)。
2.3 微信小程序前端:真机调试前的三项必改
前端位于frontend/目录,使用微信开发者工具(稳定版 1.07.2303090)打开。立即修改以下文件,否则无法请求本地后端:
2.3.1 修改project.config.json中的appid
将"appid": "wx1234567890abcdef"替换为你自己申请的测试号 AppID(微信公众平台 → 开发管理 → 开发者工具 → 获取 appid)。无 AppID 会导致wx.login()失败,后续所有接口 401。
2.3.2 修改utils/request.js中的 base URL
// 原始可能为:const BASE_URL = 'https://api.example.com' const BASE_URL = 'http://localhost:8080/api'; // 开发阶段必须指向本地后端同时确保微信开发者工具勾选「不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书」——这是本地调试的必要开关,不影响上线。
2.3.3 配置app.js中的登录态缓存逻辑
源码中login()方法调用wx.request后,将返回的token存入wx.setStorageSync('token', res.data.token)。需确认res.data.token结构与后端一致(通常为 JWT 字符串)。若后端返回字段为data而非token,需同步修改前端解析逻辑:
// utils/request.js 中的 login 方法 success: (res) => { if (res.data.code === 200) { wx.setStorageSync('token', res.data.data); // 注意此处 key 为 data.data } }完成上述修改后,点击「编译」,首页应显示餐厅 Logo 和菜品列表;点击「去结算」能跳转订单页;提交订单后,后端t_order表应新增一条记录,status=0—— 此时本地闭环已初步跑通。
3. 核心功能落地:从菜单展示到订单核销的四步数据流
该系统的价值不在界面美观,而在其清晰的数据流向设计。以下以「顾客下单」为例,拆解前后端协作的关键节点,所有代码均来自源码包,仅作路径和参数说明。
3.1 前端发起加购请求:/api/cart/add接口的正确调用姿势
小程序中点击「+」按钮时,触发cart.js中的addToCart方法:
// pages/cart/cart.js addToCart(e) { const foodId = e.currentTarget.dataset.id; wx.request({ url: `${app.globalData.baseUrl}/cart/add`, method: 'POST', header: { 'Authorization': 'Bearer ' + wx.getStorageSync('token'), 'Content-Type': 'application/json' }, data: { foodId: foodId, quantity: 1 }, success: (res) => { if (res.data.code === 200) { wx.showToast({ title: '已加入购物车' }); } } }); }注意:
Authorization头必须为Bearer <token>格式,且 token 来自wx.getStorageSync('token')。若后端使用 Spring Security,默认配置要求此格式,否则返回 401。
后端CartController.java接收请求:
@PostMapping("/add") public Result add(@RequestBody CartAddDTO dto) { cartService.add(dto.getFoodId(), dto.getQuantity()); return Result.success(); }关键点:CartAddDTO使用@RequestBody接收 JSON,cartService.add()内部会校验foodId是否存在于t_food表,并检查库存(stock > 0),若不足则抛出BusinessException,前端收到{code: 500, msg: "库存不足"}。
3.2 提交订单:/api/order/create如何保证幂等与库存扣减
订单创建是系统最易出错环节。源码采用「先锁库存再写订单」策略,避免超卖:
// OrderServiceImpl.java @Transactional public void createOrder(OrderCreateDTO dto) { // 1. 查询购物车中所有商品(关联 t_food) List<CartVO> cartItems = cartMapper.selectByUserId(userId); // 2. 对每个商品加行级锁(SELECT ... FOR UPDATE) for (CartVO item : cartItems) { Food food = foodMapper.selectByIdForUpdate(item.getFoodId()); // 自定义 mapper 方法 if (food.getStock() < item.getQuantity()) { throw new BusinessException("商品" + food.getName() + "库存不足"); } } // 3. 扣减库存并插入订单 for (CartVO item : cartItems) { foodMapper.decreaseStock(item.getFoodId(), item.getQuantity()); orderItemMapper.insert(new OrderItem(...)); } // 4. 清空购物车 cartMapper.deleteByUserId(userId); }提示:
selectByIdForUpdate是关键,它在 MySQL 中生成SELECT ... FOR UPDATE语句,对t_food行加锁。若两个用户同时下单同一商品,第二个请求会阻塞直到第一个事务提交,从而保证库存一致性。此方案比 Redis 分布式锁更轻量,适合单库场景。
3.3 管理员核销:/api/order/verify/{orderId}的状态机控制
核销接口位于OrderController.java:
@PutMapping("/verify/{orderId}") public Result verify(@PathVariable Long orderId) { orderService.verify(orderId); return Result.success(); }orderService.verify()内部逻辑:
public void verify(Long orderId) { Order order = orderMapper.selectById(orderId); if (!Objects.equals(order.getStatus(), 1)) { // 必须是已支付状态 throw new BusinessException("订单状态异常,无法核销"); } order.setStatus(2); // 更新为已核销 orderMapper.updateById(order); }前端管理员页面调用时,需传递orderId路径参数,并确保请求头携带管理员 token(role=ADMIN)。状态机强制约束:仅status=1(已支付)可转为status=2(已核销),防止重复核销或跳过支付直接核销。
3.4 数据库表结构与外键约束的实际作用
查看sql/restaurant_init.sql,重点关注三处设计:
| 表名 | 关键字段 | 作用 | 毕设验证点 |
|---|---|---|---|
t_food | stock int not null default 0 | 实时库存,扣减依据 | 修改某菜品 stock 为 0,前端加购应提示“库存不足” |
t_order | status tinyint(2) not null default 0 | 订单状态机起点 | 查询SELECT * FROM t_order WHERE status=2应返回核销订单 |
t_order_item | order_id bigint, food_id bigint | 订单与商品多对多关系 | 删除t_order记录时,t_order_item应级联删除(源码中ON DELETE CASCADE已启用) |
执行SHOW CREATE TABLE t_order_item;可验证外键是否生效。若未生效,需确认 MySQL 引擎为 InnoDB(MyISAM 不支持外键)。
4. 常见故障排查:五类高频报错的定位与修复指令
毕设调试阶段,90% 的问题集中在网络、认证、SQL、前端路径四类。以下按现象给出精准定位命令和修复方案,避免盲目百度。
4.1 「request:fail net::ERR_CONNECTION_REFUSED」——后端根本没起来
现象:小程序控制台报此错,Swagger 页面打不开。
定位命令:
# 检查 8080 端口是否被占用 netstat -ano | findstr :8080 # Windows lsof -i :8080 # macOS/Linux # 查看 Java 进程是否运行 jps -l | findstr "RestaurantApplication" # Windows jps -l | grep "RestaurantApplication" # macOS/Linux修复:若端口被占,修改application.yml中server.port: 8081;若进程未启动,检查 IDEA 控制台是否有Caused by: java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver—— 此时需确认pom.xml中<dependency>的mysql-connector-java版本为8.0.28(兼容 MySQL 5.7),而非8.0.33(部分版本驱动类名变更)。
4.2 「401 Unauthorized」——Token 传递或解析失败
现象:登录成功,但后续接口全 401。
定位步骤:
- 小程序控制台
console.log(wx.getStorageSync('token')),确认非空字符串; - 后端
JwtAuthenticationFilter.java中断点,检查request.getHeader("Authorization")是否为Bearer xxx; - 若为
null,检查utils/request.js中header是否拼写错误(如authoriztion); - 若为
Bearer xxx但解析失败,在JwtUtil.java的parseToken方法中打印token值,确认是否含非法字符(如换行符)。
修复:JwtUtil中Jwts.parser().setSigningKey(secret).parseClaimsJws(token)若抛SignatureException,说明secret与前端生成时不一致,需统一application.yml中jwt.secret: your-secret-key-here。
4.3 「Column count doesn't match value count at row 1」——SQL 插入字段数不匹配
现象:提交订单时后端报此错,t_order表无新增记录。
定位命令:
-- 查看 t_order 表结构,对比 INSERT 语句字段数 DESC t_order; -- 检查源码中 OrderMapper.xml 的 insert 语句,例如: -- <insert id="insert">INSERT INTO t_order (user_id, total_price, status) VALUES (#{userId}, #{totalPrice}, #{status})</insert> -- 确认 VALUES 中字段数(3个)与表实际列数(含 id, create_time 等)是否一致修复:t_order表含id bigint PK auto_increment,create_time datetime DEFAULT CURRENT_TIMESTAMP,故INSERT语句不能显式插入id和create_time,应写为:
<insert id="insert"> INSERT INTO t_order (user_id, total_price, status) VALUES (#{userId}, #{totalPrice}, #{status}) </insert>4.4 「Cannot resolve symbol 'xxx'」——IDEA Maven 依赖未加载
现象:pom.xml有红色波浪线,import com.xxx.entity.Food;报错。
修复指令:
- 右键
pom.xml→Maven→Reload project; - 若仍失败,执行
mvn clean compile -X查看详细错误; - 常见原因是镜像源配置错误,在
~/.m2/settings.xml中确认<mirror>指向阿里云:
<mirror> <id>aliyunmaven</id> <mirrorOf>*</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>4.5 「Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin」——JDK 版本不匹配
现象:mvn compile报错Source option 11 is not supported。
定位命令:
java -version mvn -v修复:确保JAVA_HOME指向 JDK 11(Spring Boot 2.7 要求),并在 IDEA → Settings → Project → Project SDK 中选择同一 JDK;同时在pom.xml中显式声明:
<properties> <java.version>11</java.version> </properties>5. 毕设演示技巧:三个让答辩老师眼前一亮的实操细节
答辩不是代码朗诵,而是展现你对系统脉络的理解。以下三个细节无需额外开发,仅靠现有源码调整即可体现工程素养。
5.1 动态设置小程序顶部标题,强化场景感
微信小程序默认标题为app.json中window.navigationBarTitleText。但点餐系统在不同页面应有不同标题(如「首页」「购物车」「订单详情」)。源码中pages/index/index.js已预留onLoad方法:
onLoad: function () { wx.setNavigationBarTitle({ title: '美味餐厅' }); }实操:在pages/order/detail.js的onLoad中添加:
onLoad: function (options) { const orderId = options.orderId; wx.setNavigationBarTitle({ title: `订单详情 #${orderId}` }); }演示时,点击订单列表进入详情页,标题实时变化——这比静态标题更能体现「用户视角」。
5.2 利用 MySQL Workbench 可视化展示订单状态流转
不要只说「订单有四种状态」,用工具直观呈现:
- 下载 MySQL Workbench(官网免费);
- 连接本地
restaurant_db; - 执行
SELECT id, status, create_time FROM t_order ORDER BY create_time DESC LIMIT 10;; - 在结果集右上角点击「图表」图标,选择
status为 X 轴,COUNT(*)为 Y 轴,生成柱状图; - 现场下单、支付、核销,刷新图表,展示
status从 0→1→2 的变化。
提示:答辩时截图保存此图表,作为「数据驱动决策」的佐证,比口头描述更有力。
5.3 修改刚进入的加载页面,提升首屏体验
源码app.js中onLaunch方法调用wx.showLoading,但未隐藏。在pages/index/index.js的onLoad结尾添加:
onLoad: function () { wx.setNavigationBarTitle({ title: '美味餐厅' }); // 添加两秒模拟加载,结束后隐藏 setTimeout(() => { wx.hideLoading(); }, 2000); }同时在app.json中window节点添加:
"navigationStyle": "custom"再在pages/index/index.wxml顶部添加自定义导航栏:
<view class="nav-bar"> <text class="nav-title">美味餐厅</text> </view>这样,小程序启动时显示「加载中…」,2 秒后进入首页并显示定制导航栏——体现对用户体验细节的关注,远超单纯功能实现。
本文还有配套的精品资源,点击获取