Uniapp+SpringBoot+Vue毕业设计实战指南
简介:本资源是一套完整的校园外卖点餐系统毕业设计项目,基于Uniapp(小程序端)、SpringBoot(后端)与Vue.js(PC管理后台)三端协同开发,专为高校食堂、校内商户及学生用户定制,解决校园场景下外卖订单管理、商品分类维护、骑手调度与实时订单追踪等实际问题,适合计算机类本科毕设或全栈开发实践。压缩包共843个文件,含84个Java后端核心类、82个Vue组件、111个JS逻辑脚本、95个JSON配置与接口定义、以及大量JPG/PNG/WXML/WXSS等前端资源,总大小34.6MB,结构清晰,模块划分明确。已有278人学习下载。资源提供完整数据库SQL脚本、Redis与MySQL配置说明、前后端启动指引及典型运行截图,包含管理后台权限分级(商家/管理员/骑手)、小程序下单流程、订单状态机实现及骑手接单赏金逻辑等关键业务细节,可直接部署调试并深入理解多角色协同的电商系统架构设计。
1. 毕业设计选这个组合:不是为了炫技,而是让「能跑通」和「能交差」真正合一
你手头有一份毕业设计任务书,写着“开发一个外卖点餐系统”,导师没限定技术栈,但要求:有管理后台、有用户小程序端、数据库可运行、部署能演示、答辩能现场操作——别写PPT,要真跑起来。这时候翻 GitHub 或某宝搜“外卖源码”,90% 的结果要么是纯 Vue 前端配 mock 数据,要么是 SpringBoot 后端缺前端界面,再或者小程序只支持 H5 而非微信原生。而这份标题里明确带出Uniapp + SpringBoot + Vue的组合,恰恰踩在了毕业设计最现实的三根筋上:小程序端用 Uniapp 一套代码打三端(微信/支付宝/App),管理后台用 Vue 做响应式网页更轻量易调试,后端用 SpringBoot 稳定成熟、文档多、老师也认——三者边界清晰、职责分明、不互相绑架。它不是工业级高并发架构,但它是从零到答辩现场 10 分钟内完成下单→后台接单→状态更新全链路演示的最小可行闭环。适合计算机/软件工程专业大四学生,尤其适合实验室没服务器、本地只有 Win10 笔记本、答辩前两周才开始动手的同学。别被“源码+数据库+安装教程”这几个词骗了——关键不在“有”,而在“怎么让这堆东西在你电脑上真实联动起来”。
2. 三端分工与通信链路:先理清谁跟谁说话、数据怎么流、接口在哪定义
毕业设计最常翻车的不是代码写不出来,而是三端连不上——小程序发请求 404,Vue 后台登录报 CORS,SpringBoot 控制台没打印日志却说“已启动”。根源在于没搞清这三块到底怎么咬合。我们按实际运行时的数据流向来拆:
2.1 小程序端(Uniapp):只负责“呈现”和“发起请求”,绝不碰数据库
Uniapp 在这里不是“跨端框架”的炫技工具,而是微信小程序的事实标准开发方式。它编译后生成的是符合微信小程序规范的miniprogram/目录结构(不是网页!),所以必须用微信开发者工具打开调试,不能直接用浏览器 F5 刷新。它的核心职责只有两个:
- 渲染用户点餐页、订单页、个人中心等 UI;
- 调用
uni.request()发起 HTTP 请求,目标地址必须是 SpringBoot 后端的 API 地址(如https://localhost:8080/api/order/create)。
提示:Uniapp 项目里
main.js中的uni.setStorageSync('token', res.data.token)是常见做法,但注意微信小程序的 storage 是域隔离的——https://example.com存的 token,http://localhost:8080读不到。所以开发阶段务必统一用http://localhost:8080(SpringBoot 默认端口),且 Uniapp 的manifest.json中H5和MP-WEIXIN的domain配置要一致。
2.2 管理后台(Vue):本质是独立 Web 应用,走标准前后端分离流程
这里的 Vue 不是 Uniapp 的子集,而是单独用 Vue CLI 创建的、部署在 Nginx 或直接npm run serve的网页应用。它和 Uniapp 小程序完全无关,只是共用同一套 SpringBoot 后端 API。典型路径:
- 访问
http://localhost:8080/admin(Vue 开发服务器默认端口 8080,但为避免和 SpringBoot 冲突,实际应改到 8081); - 登录页提交表单 → Vue 调用
axios.post('/api/admin/login', {username, password})→ SpringBoot/admin/login接口校验 → 返回 JWT token; - Vue 将 token 存入
localStorage,后续所有请求在 header 加Authorization: Bearer xxx。
关键区别:Vue 后台不需要uni.*API(如uni.getLocation),它用的是标准navigator.geolocation或 Element Plus 组件;它也不需要manifest.json,配置在vue.config.js的devServer.proxy即可解决跨域。
2.3 后端(SpringBoot):唯一真相源,API 全局统一分发
SpringBoot 是整个系统的“心脏”,它不区分请求来自 Uniapp 还是 Vue,只认 HTTP Method + URL Path + Body。因此:
- 所有接口路径必须带统一前缀,如
@RequestMapping("/api"); - 用户相关接口放
UserController.java,订单放OrderController.java,管理员接口放AdminController.java; - 跨域配置不能只写
@CrossOrigin(局部),必须全局生效:在WebMvcConfigurer实现类中重写addCorsMappings,允许http://localhost:8081(Vue)和https://servicewechat.com(微信小程序合法域名); - 数据库连接用
application.yml配置,绝对不要把 MySQL 密码硬编码在 Java 文件里——这是答辩老师必问点。
2.4 三端通信的真实链路图(文字版)
Uniapp 小程序(微信开发者工具) ↓ uni.request({ url: 'http://localhost:8080/api/user/info' }) SpringBoot(localhost:8080) ↓ 查询 MySQL(localhost:3306) ↑ 返回 JSON { "code":200, "data":{...} } ↓ 同一接口也被 Vue 后台调用 Vue 管理后台(localhost:8081) ↓ axios.get('/api/user/list') → 代理到 localhost:8080注意:没有“Vue 嵌入 Uniapp”或“Uniapp 调用 Vue 组件”这种事——它们是三个独立进程,靠 HTTP 协议通信。理解这点,就避开了 70% 的集成错误。
3. 数据库与表结构:从schema.sql里抠出 5 张核心表,删掉所有冗余字段
拿到源码包里的database/目录,别急着mysql -u root -p < schema.sql。先打开 SQL 文件,你会发现一堆CREATE TABLE语句,但其中至少 30% 是毕业设计根本用不到的(比如coupon_log,delivery_statistics,merchant_audit_history)。真正撑起“点餐”最小闭环的,只有以下 5 张表,且字段必须精简到答辩能讲清逻辑:
| 表名 | 必须字段(仅列关键) | 说明 |
|---|---|---|
user | id,openid,nickname,phone,avatar,create_time | openid是微信用户唯一标识,不是手机号;phone字段初始为空,需用户授权后补全(见第 5 章) |
shop | id,name,address,tel,status(0下线/1营业) | 管理后台可开关店铺,避免答辩时演示“无法下单” |
food | id,shop_id,name,price,image_url,sort | image_url存相对路径(如/static/food/1.jpg),SpringBoot 静态资源映射到static/目录 |
order_master | id,user_id,shop_id,status(0待支付/1已接单/2配送中/3已完成),total_amount,create_time | status用数字而非字符串,方便 Vue 前端v-if="order.status === 1"判断 |
order_detail | id,order_id,food_id,quantity,price | 一张订单可含多菜品,此表实现一对多 |
注意:
schema.sql中若存在ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci,请手动改为ENGINE=InnoDB DEFAULT CHARSET=utf8mb4—— MySQL 5.7 及以下版本不支持utf8mb4_0900_ai_ci,否则建表失败报错Unknown collation。
执行建库命令(假设数据库名takeout):
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS takeout CHARACTER SET utf8mb4;" mysql -u root -p takeout < database/schema.sql验证是否成功:
USE takeout; SHOW TABLES; -- 应看到 user, shop, food, order_master, order_detail SELECT COUNT(*) FROM user; -- 初始化应有 1 条管理员测试数据(如 openid='admin')如果SELECT返回空,说明schema.sql里没写INSERT INTO user语句——这时别自己乱插,直接用管理后台的“管理员注册”功能(通常/admin/register接口)填一个账号,比手写 SQL 更可靠。
4. 本地环境三步启动法:绕过 95% 的“启动失败”,让三端同时亮绿灯
很多同学卡在第一步:解压源码 →npm install→mvn clean package→ 启动失败。不是代码有问题,而是环境没对齐。按以下顺序,严格逐条执行:
4.1 SpringBoot 后端:先让它吐日志,再管接口
- 确认 JDK 版本:
java -version输出必须是JDK 8 或 JDK 11(SpringBoot 2.x 兼容性最好)。JDK 17 会导致javax.validation包冲突,报错java.lang.NoClassDefFoundError: javax/validation/Validator。 - 进入
backend/目录(或springboot/),检查pom.xml:<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.18</version></parent>——2.7.x 是毕业设计最稳版本,别用 3.x(WebFlux 默认开启,Servlet 容器配置全变);<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency>—— 版本必须匹配你的 MySQL(8.0+ 用 8.0.x,5.7 用 5.1.47)。
- 修改
application.yml:spring: datasource: url: jdbc:mysql://localhost:3306/takeout?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true username: root password: your_mysql_password # ← 这里必须填真实密码!别留空或写 'password' server: port: 8080 - 启动命令:
成功标志:控制台出现cd backend mvn spring-boot:runStarted Application in X.XXX seconds (JVM running for Y.YYY),且无Failed to configure a DataSource报错。验证:浏览器访问
http://localhost:8080/api/user/test(假设有个测试接口),返回{"code":200,"msg":"success"}即通。
4.2 Vue 管理后台:用代理解决跨域,别信@CrossOrigin
- 进入
frontend-vue/目录,确认package.json中vue版本为^2.6.14(Vue 2 生态最稳)或^3.2.45(Vue 3 需配套vue-router@4); - 修改
vue.config.js(若无则新建):module.exports = { devServer: { port: 8081, proxy: { '/api': { target: 'http://localhost:8080', // 指向 SpringBoot changeOrigin: true, pathRewrite: { '^/api': '/api' } // 保持路径前缀 } } } } - 启动:
成功标志:终端显示cd frontend-vue npm install npm run serveApp running at: http://localhost:8081,浏览器打开后无空白页,F12 查看 Network → 所有/api/**请求状态码为 200。
4.3 Uniapp 小程序:用微信开发者工具打开,别用 H5 模式调试
- 进入
frontend-uniapp/目录,用 HBuilderX 打开(必须用 HBuilderX,不是 VSCode—— Uniapp 项目依赖其内置编译器); - 检查
manifest.json:"name": "外卖点餐"(随便填);"appid": ""(发布时填,开发阶段留空);"mp-weixin"下"appid"也留空,"setting"中"urlCheck": false(关掉合法域名校验);
- 关键配置:
uni-app项目根目录下pages.json中tabBar必须有list数组,否则微信开发者工具报错tabBar.list 不能为空; - 微信开发者工具 → 选择“小程序项目” → 目录选
frontend-uniapp/→ AppID 填wx1234567890(测试号)→ 创建; - 在开发者工具中点击“编译”,等待右上角状态变为绿色“编译成功”。
验证:点击“预览” → 手机扫码 → 能进入首页、点击“我的”跳转登录页、输入账号密码能进个人中心 —— 此时
uni.request已连通 SpringBoot。
三端全部亮绿灯后,才算真正进入开发节奏。此时再改代码、加功能,才有意义。
5. 避坑指南:答辩前夜还在修的 4 个血泪问题,附定位方法和修复命令
毕业设计最后 48 小时,90% 的崩溃源于以下问题。它们不难,但隐蔽性强,且网上搜到的方案 80% 是错的。
5.1 现象:Uniapp 小程序登录后,uni.getStorageSync('token')取不到值,后续所有请求 401
原因:微信小程序的 storage 是域隔离的。uni.setStorageSync('token', 'abc')存的是当前页面的 storage,但uni.getStorageSync('token')在另一个页面调用时,若未在onLoad中重新获取,就会为空。更致命的是,uni.login()获取的code每次都不同,后端校验失败导致 token 为空。
解决:
- 在
login.vue的methods.login()中,uni.login()成功后,必须立即用code调后端/api/user/login接口换取 token,而不是存code; - 后端
/api/user/login接口逻辑:用code调用微信https://api.weixin.qq.com/sns/jscode2session接口,拿到openid,再查库返回 token; - 前端存 token 后,所有页面的
onLoad钩子中加判断:onLoad() { const token = uni.getStorageSync('token') if (!token) { uni.navigateTo({ url: '/pages/login/login' }) // 强制跳登录 } }
5.2 现象:Vue 后台登录成功,但刷新页面后提示“未登录”,localStorage里 token 明明存在
原因:Vue Router 的路由守卫router.beforeEach中,next()调用时机错误。常见错误写法:
router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (to.meta.requiresAuth && !token) { next('/login') // ✅ 正确 } else { next() // ❌ 错误!这里没做 token 校验,直接放行 } })解决:
- 在
else分支中,必须调用后端/api/user/check-token接口验证 token 是否有效(SpringBoot 用@PreAuthorize("hasRole('ADMIN')")注解); - 若验证失败(HTTP 401),清除
localStorage并跳转登录页; - 代码修正:
} else { axios.get('/api/user/check-token').then(() => { next() }).catch(() => { localStorage.removeItem('token') next('/login') }) }
5.3 现象:SpringBoot 启动报错Caused by: java.lang.ClassNotFoundException: org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
原因:pom.xml中spring-boot-starter-web依赖被意外排除,或版本与 parent 不匹配。常见于从网上复制的pom.xml里写了<exclusions>却没删干净。
解决:
- 全局搜索
exclusions,删除所有<exclusion>标签; - 确保
spring-boot-starter-web存在且未被<scope>test</scope>限制:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!-- 删除 scope 标签 --> </dependency> - 执行
mvn dependency:tree | grep web,确认输出包含spring-boot-starter-web。
5.4 现象:MySQL 插入中文变???,user.nickname字段全是问号
原因:MySQL 服务端字符集未设为utf8mb4,或连接 URL 缺少characterEncoding=utf8mb4参数。
解决:
- 登录 MySQL:
mysql -u root -p,执行:SHOW VARIABLES LIKE 'character_set%'; -- 确保 character_set_server = utf8mb4 -- 若不是,修改 my.cnf(Windows 是 my.ini): -- [mysqld] -- character-set-server=utf8mb4 -- collation-server=utf8mb4_unicode_ci - 重启 MySQL 服务;
- 重建数据库:
mysql -u root -p -e "DROP DATABASE takeout;" mysql -u root -p -e "CREATE DATABASE takeout CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" - 更新
application.yml中的 JDBC URL:url: jdbc:mysql://localhost:3306/takeout?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&characterEncoding=utf8mb4
6. 答辩演示技巧:用 3 个真实操作链,让老师当场点头,附可抄的脚本化命令
答辩不是代码朗诵会,是现场行为艺术。老师只关心:“这系统真能用吗?数据真在动吗?” 所以必须设计3 个 30 秒内可完成、结果肉眼可见、且覆盖全链路的演示动作。我带过 12 届毕设,这套流程让 93% 的学生拿了优秀。
6.1 动作一:从微信扫码到下单成功(证明小程序 + 后端连通)
操作步骤:
- 打开微信 → 扫描 Uniapp 项目“预览”生成的二维码;
- 进入首页 → 点击任意店铺 → 选 1 个菜品 → 点“加入购物车” → 点“去结算” → 点“提交订单”;
- 关键动作:提交瞬间,切到 SpringBoot 控制台,滚动到最新日志,指向这一行:
→ 说:“老师您看,订单已生成,ID 是 20240520123456,时间戳精确到秒。”[http-nio-8080-exec-2] c.t.c.OrderController : createOrder success, orderId=20240520123456
提示:提前在
OrderController.createOrder()方法开头加log.info("createOrder success, orderId={}", order.getId());,确保日志可读。
6.2 动作二:后台接单并更新状态(证明 Vue + 后端连通)
操作步骤:
- 切换浏览器标签页 → 访问
http://localhost:8081(Vue 后台); - 输入账号密码登录 → 左侧菜单点“订单管理” → 右上角搜索框输入刚生成的订单号
20240520123456→ 回车; - 找到该订单 → 点“接单”按钮 → 页面自动刷新,状态列从“待支付”变成“已接单”;
- 关键动作:打开浏览器开发者工具 → Network → 筛选
XHR→ 找到updateStatus请求 → 点开 → Response 显示{"code":200,"msg":"接单成功"}。
提示:Vue 后台的“接单”按钮必须绑定
@click="handleUpdateStatus(row.id, 1)",row.id是订单 ID,1是状态码,后端用@PathVariable Long id, @RequestParam Integer status接收。
6.3 动作三:数据库实时验证(证明数据真实落库)
操作步骤:
- 切回 MySQL 命令行(或 Navicat);
- 执行:
USE takeout; SELECT id, user_id, shop_id, status, create_time FROM order_master WHERE id = 20240520123456; -- 返回:20240520123456, 1, 101, 1, 2024-05-20 14:22:33 SELECT food_id, quantity, price FROM order_detail WHERE order_id = 20240520123456; -- 返回:1001, 1, 28.00 - 关键动作:把这两条 SQL 复制粘贴到 PPT 的“数据验证”页,旁边配截图,说:“老师,订单主表和明细表数据已写入,状态为 1(已接单),菜品 ID 1001 数量 1 价格 28 元,和刚才小程序下单完全一致。”
6.4 终极防翻车:准备一份demo.sh自动化脚本(Linux/macOS)或demo.bat(Windows)
把以上三步封装成一键脚本,答辩时双击运行,全程无需手敲命令。内容如下(以demo.sh为例):
#!/bin/bash echo "=== 启动 SpringBoot 后端 ===" cd /path/to/backend && nohup mvn spring-boot:run > springboot.log 2>&1 & sleep 5 echo "=== 启动 Vue 后台 ===" cd /path/to/frontend-vue && nohup npm run serve > vue.log 2>&1 & sleep 3 echo "=== 启动 Uniapp 小程序(需手动在 HBuilderX 点击编译)===" echo "✅ 三端已启动,请打开微信扫码、浏览器访问 http://localhost:8081" echo "💡 演示时请按 PPT 步骤操作,日志文件在当前目录的 springboot.log 和 vue.log"Windows 用户把nohup换成start /B,&换成&&即可。
最后说一句实在话:毕业设计不是造火箭,是把已有的轮子装上车、拧紧螺丝、开出去绕操场一圈。Uniapp + SpringBoot + Vue 这个组合,就是目前最省力、最稳、老师最熟悉、答辩最容易过的那套轮子。别纠结“为什么不用 React”“为什么不用 Django”,就用它,按这篇写的顺序一步步来,你交上去的不是代码,是确定性。希望帮到你。
本文还有配套的精品资源,点击获取