一到毕业季,论坛和群里最常见的求助就是“有没有现成的毕设项目可以抄”。我这两年帮人审过的毕业设计里,奶茶点餐小程序几乎是最稳的一个方向——业务模型清楚、技术栈主流、工作量可控、演示效果又直观。基于 springboot + vue + 微信小程序 来做一套奶茶点餐系统,源码、数据库、文档都能完整交付,对于计算机专业的学生来说,既能拿来应付课程设计,也能直接升级成毕业论文的主体。这篇我就把这个项目的完整设计思路、数据库表结构、核心接口、前端页面,以及那些文档里不会写的坑,从头到尾过一遍。
这个项目真正解决的是“点餐流程数字化”的问题:顾客在小程序里浏览菜单、加购物车、下单支付,商家在 vue 后台管理商品、处理订单、看销售数据。整个业务闭环很干净,没有多余的概念,非常适合用来展示你掌握全栈开发的水平。学完你能带走一套能跑的前后端分离项目,也能从中学到 JWT 登录、事务处理、购物车结算、小程序联调这些高频知识点。
1. 先从业务出发:一杯奶茶背后的系统设计
1.1 三个角色一条链路
拿到一个毕设题目,第一反应不是建表,而是先搞清楚谁在用这个系统。奶茶点餐场景里无非三种人:顾客、店员/商家、管理员。顾客打开小程序,看到的是轮播图、分类菜单、商品列表、商品详情、购物车和订单记录;店员进入后台,要能上架下架商品、修改价格、处理新订单;管理员则关心整体数据,比如营业额、销量排行这些。
顺着这个逻辑往下拆,系统的核心链路就是“浏览商品 → 加入购物车 → 提交订单 → 模拟支付 → 商家接单 → 完成订单”。这条链路能跑通,项目的主心骨就有了。很多人做毕设容易犯一个毛病,就是上来就写代码,结果做到一半发现模块之间对不上。建议先把这条链路画在纸上,标清楚每一步的数据变化,再动手建工程。
决定用 springboot + vue + 小程序这套组合,还有一个很现实的原因:网上资料多、问答多,你踩到坑基本都能搜到解法。真要选一个冷门框架,界面做得再漂亮,后期卡住没人帮你看,那就非常痛苦了。
1.2 三个端的技术版本怎么定
选版本这件事,看着琐碎,实际上决定了你后面少踩多少个坑。
后端用 springboot,建议选 2.7.x。这个版本的资料最全,各种教程里写的javax.servlet和springfox都能直接用。如果你图新鲜上了 springboot 3.x,那很多老代码就变了,javax要改成jakarta,Swagger 依赖也要换,对毕设来说完全没必要冒这个险。ORM 层直接上 MyBatis-Plus,单表 CRUD 不用写 SQL,分页查订单、条件查商品都很方便。
数据库用 MySQL 5.7 或者 8.0 都行,只要注意连接串的编码参数写对,在本地开发环境里基本不会出问题。
vue 后台这块,我建议用 vue 2 + Element UI。不是说 vue 3 不好,而是 vue 2 的生态对新手最友好,Element UI 的表格、表单、弹窗组件可以帮你一晚上把管理界面搭出来。如果你是前端老手,用 vue 3 + Element Plus 也没问题,但要注意父子组件传参和路由配置这些细节,版本差异会带来不少隐性坑。
小程序端直接用微信开发者工具写原生语法就够了。不用为了“一套代码多端运行”去上 uni-app,毕设场景下原生小程序最稳定,调试也最直接。
1.3 交付物怎么组织
答辩和交作业的时候,老师要的不只是一堆源码。建议工程目录按下面这样整理,干净清楚:
milktea-system/ ├── backend/ # springboot 后端工程 ├── admin-web/ # vue 管理后台 ├── miniapp/ # 微信小程序 ├── sql/ # 数据库脚本 ├── docs/ # 论文、答辩PPT、演示视频 └── README.md # 项目说明和部署步骤后端工程内部再按controller / service / mapper / entity / common分包,小程序页面按pages/index、pages/cart、pages/order、pages/user组织。这样做的价值在于:论文里的系统设计章节可以直接对着目录结构写,评阅老师看着也舒服。
2. 数据库设计:趁早把表建对,省下一半的返工时间
2.1 核心表字段怎么定
数据库是整个项目的底盘。奶茶点餐系统不需要搞一堆复杂的表,核心就六张:用户表、分类表、商品表、购物车表、订单表、订单明细表。
| 表名 | 关键字段 | 说明 |
|---|---|---|
| user | id, openid, nickname, avatar, balance, create_time | 小程序用户,openid 是唯一标识 |
| category | id, name, sort | 商品分类,比如招牌奶茶、鲜果茶、纯茶 |
| product | id, category_id, name, description, image, price, stock, sales, status | status 控制上下架,sales 做销量统计 |
| cart | id, user_id, product_id, quantity, checked | checked 表示购物车中勾选状态 |
| orders | id, order_no, user_id, total_amount, status, address, remark, create_time | 主订单表,status 记录订单状态 |
| order_item | id, order_id, product_id, product_name, product_image, price, quantity | 订单明细,冗余商品快照 |
订单明细表里冗余了商品名称和图片,这个是有意为之。真实场景里奶茶店改价、下架甚至删除商品都很常见,如果订单明细只存 product_id,回头查历史订单时商品信息可能会变样甚至查不到。把这个思路写进论文里,属于很加分的设计细节。
字段类型也要注意:价格用DECIMAL(10, 2),不用DOUBLE,因为浮点数算价格会出现精度偏差,虽然演示时看不出来,但答辩老师一问就露馅。库存和销量用INT,状态值用TINYINT就行。
2.2 订单状态机要成为全项目的共识
订单表里的 status 字段,是整个系统最容易写乱的地方。我见过很多人的代码里到处散落魔法数字,1 表示这个、2 表示那个,改来改去自己都分不清。建议从一开始就定义好一套状态机:
- 0 待支付
- 1 已支付待制作
- 2 制作中
- 3 待取餐
- 4 已完成
- 5 已取消
订单流转是“待支付 → 已支付待制作 → 制作中 → 待取餐 → 已完成”,用户主动取消和超时未支付都会落到已取消。开发时建议写一个常量类统一管理这些值,后端判断逻辑、小程序状态展示、后台按钮操作全都引用同一个常量,这样就不怕改一处漏一处。
2.3 初始化和演示数据
建表别用 JPA 自动建表,直接把 SQL 脚本写好提交到sql/目录下。这样新环境一键导入就能跑,老师检查时也直观。
顺带说一句,要初始化足够的演示数据。奶茶图片别用一张灰色占位图,网上找一些实际产品图放上去,轮播图和分类图标也都配好,演示效果完全不一样。页面上有真实感,你讲起来也有底气。为了后期做销售统计图表,可以在初始化脚本里插入近 15 天的模拟订单数据,时间字段分布在最近半个月,营业额曲线就能出来。
2.4 购物车用表存还是用本地缓存存
购物车这个小模块,我和不少人讨论过。简单方案是用户把购物车数据存在小程序的 Storage 里,不落表;复杂方案是每个用户一张购物车表。毕设项目我建议用表存,虽然多写几个接口,但能让后台多出一个数据表、多几个 CRUD 操作,论文和代码量都更扎实。
购物车表要以user_id + product_id作为逻辑唯一键。用户点“加入购物车”时,如果该商品已经在购物车里,就直接把数量加一,而不是插入一条新记录。
3. 后端接口开发:把核心链路一次跑通
3.1 工程初始化和统一返回结构
后端项目用 Spring Initializer 生成,依赖选Spring Web、MyBatis-Plus、MySQL Driver、Lombok、Validation这几个就够了。配置里把端口设为8080,数据库连接串写成下面这样:
server.port=8080 spring.datasource.url=jdbc:mysql://localhost:3306/milktea?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=你的密码所有接口的返回格式统一包装成一个Result类,包含code、message、data三个字段。这样前端处理逻辑就统一了,不用每个接口单独判断类型。
@Data public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> success(T data) { Result<T> result = new Result<>(); result.setCode(200); result.setMessage("success"); result.setData(data); return result; } public static <T> Result<T> error(String message) { Result<T> result = new Result<>(); result.setCode(500); result.setMessage(message); return result; } }3.2 用户登录与鉴权
小程序端登录和后台管理员登录要分开处理。小程序用户走微信登录:前端调用wx.login拿到临时code,后端拿这个 code 请求微信接口换取openid。如果 user 表里没有这个 openid,就自动创建一条新用户记录,然后签发一个 JWT 给小程序端,后续请求都带上这个 token。
管理员的登录则直接做账号密码校验,密码存 BCrypt 加密后的密文,登录成功后也签发 JWT。后端加一个拦截器统一校验 token,白名单放行登录接口、商品查询接口和图片资源访问,其余接口全部要求有效 token,不然返回 401。这个设计在论文里写“基于 JWT 的无状态认证机制”,就是一个很标准的亮点。
3.3 下单接口:事务和库存扣减一个都不能少
下单是后端最重要的接口,也是答辩时最喜欢被追问的地方。流程是:根据购物车里勾选的商品拼接订单,校验库存,计算总价,扣库存,生成订单主表和明细表,最后清空购物车。
库存扣减这一块要说清楚为什么不能只靠前端判断。用户提交订单前,前端可以把购物车商品、价格、库存都校验一遍,但后端必须再校验一次,因为前端传的数据可以伪造,而且并发场景下两个用户同时买同一杯奶茶,前端都显示有库存,后端如果不去控制,库存就可能被扣成负数。
建议在事务里用SELECT ... FOR UPDATE锁住商品行,再判断库存够不够,够就扣减。加上@Transactional让整个操作要么全部成功要么全部回滚。
@Transactional public OrderVO createOrder(OrderCreateRequest request) { // 1. 根据购物车ID列表查询商品列表 // 2. SELECT ... FOR UPDATE 锁定商品行 // 3. 校验库存并计算总价 // 4. 创建订单主表和明细表 // 5. 扣减库存,累加销量 // 6. 清空购物车 }订单号生成也有讲究。直接用数据库自增 ID 当订单号太没有说服力,答辩时容易被问“电商系统为什么不直接用自增ID”。建议用时间戳加随机数,比如yyyyMMddHHmmss + 4位随机数,或者直接用雪花算法。把这个问题写进论文的“关键技术”里,也算一个小亮点。
3.4 模拟支付怎么设计
毕设阶段没法真正接入微信支付,因为商户号、证书、回调地址这些前提条件拿不到。但你可以做一个“模拟支付”,用户点击支付按钮时,前端弹出一个支付确认框(金额、奶茶名字),点确认就直接把订单状态改成“已支付待制作”,同时记录支付时间。
如果想显得更专业,可以加一个支付回调的模拟接口:支付成功后,系统内部生成一条支付流水记录到payment_log表。这样论文里能写“完整走通了支付流水闭环,后续可无缝替换为真实微信支付”,老师听着也觉得你思考过。
3.5 顺手做的加分模块
核心链路跑通之后,有几个增值模块很值得写:首页数据统计、销售排行、Redis 缓存。管理员后台需要 ECharts 展示近 7 天营业额曲线、今日订单数、热销商品 TOP5,对应的后端接口用聚合查询按天分组就能算出来。如果项目里引入了 Redis,可以把分类列表和热销商品缓存起来,接口响应变快,论文里又能多写一章“基于 Redis 的性能优化实践”。
4. 前端与管理后台:让页面真正连上接口
4.1 vue 管理后台的页面结构
管理后台的页面不用太多,但每页都要有用。登录页写完,紧接着就是数据看板、商品管理、分类管理、订单管理、用户管理这五块。
数据看板放统计卡片和两张图表,下单趋势用折线图,分类销售占比用饼图。商品管理页就是一个表格加新增编辑弹窗,Element UI 的el-table和el-dialog组合起来写很快。比较容易被忽略的是图片上传,建议后端提供一个单独的上传接口,保存文件到本地某个目录,回传 URL。表单里用el-upload组件,预览用<el-image>。
订单管理页要支持按状态筛选和状态流转操作。比如待接单的订单显示“接单”按钮,制作中的订单显示“完成制作”按钮,已完成的不显示按钮。这个交互做完,整个后台的业务逻辑就完整了。
4.2 小程序端的页面与交互
小程序端页面按业务链路来:首页、分类页、商品详情页、购物车页、确认订单页、订单列表页、个人中心页。首页顶部放搜索框,下面轮播图,再往下是分类 Tab 和商品卡片列表,整体布局参考主流奶茶点单小程序的样子就行。
首页请求后端商品列表接口时,按分类 ID 过滤。为了让页面更流畅,小程序端可以做一个简单下拉刷新和触底加载更多,订单列表用分页加载,一次拿 10 条,触底时加载下一页。
购物车页面要支持勾选、修改数量、删除、全选和合计价计算。这里要注意,数量加减的按钮别做得太小,真机演示时点起来费劲,体验会打折扣。
4.3 前后端联调和跨域设置
前端工程里用 axios 封装请求,baseURL用一个环境变量管理,本地开发时是小程序开发者工具里配置的地址。小程序端在“详情 → 本地设置”里勾选“不校验合法域名”,就能访问http://localhost:8080了。真机预览时,localhost 是手机自己,得把后端接口改成电脑的局域网 IP。
后端要写一个 CORS 配置类,放行所有跨域请求,避免后台管理页访问接口时被浏览器拦截:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }5. 常见问题与避坑指南
5.1 启动和运行阶段的经典报错
很多同学代码写完了,结果卡在没法跑起来。我整理一份高频问题清单,照着排查基本能解决:
| 错误现象 | 根本原因 | 解决办法 |
|---|---|---|
springboot 启动报javax.servlet不存在 | 用了 springboot 3.x,包名已改为jakarta | 换成 2.7.x 版本,或者统一替换 import |
数据库中文变??? | 连接串没加编码参数,或建表不是 utf8mb4 | 连接串加characterEncoding=utf8,表用utf8mb4 |
vue 启动报Error: digital envelope routines::unsupported | Node 17+ 与 vue 2 的 webpack 4 不兼容 | 安装 Node 16 LTS,或者设置NODE_OPTIONS=--openssl-legacy-provider |
| npm install 报 404 / 永远装不完 | 网络源不稳定 | 把 registry 切到淘宝镜像源 |
| 小程序真机访问不了后端接口 | 手机连的不是同一个局域网,或防火墙拦住 | 后端绑定0.0.0.0,电脑关防火墙,手机和电脑连同一 WiFi |
| 8080 端口被占用 | 其他程序占用了端口 | 改配置端口,或杀掉占用进程 |
| 上传的图片加载不出来 | 图片路径是本地绝对路径,前后端不在同一台机器 | 后台图片用可访问的 URL 返回,小程序里也要可访问 |
5.2 答辩时怎么讲清楚这个项目
答辩本质上是在 5-10 分钟里让老师相信你完整参与了这个系统。不建议照着 PPT 念技术名词,建议准备一条主线:“用户点单 → 订单生成 → 商家处理”这条业务链路,走到每个关键节点时引出你做的技术点。
比如讲到用户登录,可以说 JWT 是怎么签发、怎么校验的;讲到下单,可以说事务和库存锁的细节;讲到管理后台,可以现场演示上架一个商品,然后切到小程序刷新看到商品出现。这种两端的联动演示,比讲十页原理都有效。
另外准备两个“触发问题”的答案,比如“如果同时有很多人下单,库存怎么保证不超卖”“订单状态为什么用数字而不是字符串”。把这两个问题的来龙去脉想明白,基本挡住了最容易被追问的环节。
5.3 后续还可以往哪些方向扩展
如果还有时间,想让它从“能交差”变成“有点东西”,可以从这些方向挑一个做:加会员积分系统,下单送积分、积分抵扣金额;加优惠券模块,后台发放、用户领取,数据库里多两张表;加订单导出功能,用 EasyExcel 把订单明细导出成 Excel;加多门店支持,订单表里加门店 ID,后台按门店筛选。
这些扩展不需要改核心架构,只加表和接口,但写在论文的“系统扩展性”章节里,会显得你思考得比较完整。
5.4 关于源码获取和学习的建议
网上找这套系统的源码很容易,但拿到源码不等于学会。源码能给你节省搭框架的时间,更重要的是让你看到别人怎么设计表、怎么写事务、怎么组织接口。建议拿到手之后做三件事:第一,把数据库脚本手动执行一遍,搞清楚每个表的作用;第二,从“商品列表 → 下单 → 支付成功”把请求链路走通,看后端日志理解每一步;第三,挑一个模块自己重写一遍,比如重新写个小程序的购物车页面,代码量不大但收获最大。
整体的体会是,这个项目真正磨人的不是知识点本身,而是把三个端串起来的过程。前端调不通接口、后端忘了配跨域、小程序不校验合法域名,这些坑每一步都可能卡你半天。所以千万不要拿到源码就开始写论文,一定先把项目跑起来、理解通了,再动笔。后面写系统设计、写需求分析,素材全在项目里,一天就能串出一篇像样的初稿。