每年到这个时间点就会有很多人开始头疼毕业设计选题。你要是问我现在做哪个方向最稳妥又不太容易翻车我大概率会推荐你试试网上订餐系统。原因很简单餐饮外卖这个场景大家每天都在用需求清楚、流程直观更重要的是——Java Spring Boot Vue这套组合打底无论从工作量还是从答辩亮点来看都能让你把毕业设计做得有模有样。这个题目说它是基于JavaSpring BootVue的网上订餐全流程信息化管控系统的设计与实现本质上就是一个餐饮外卖数字化运营的完整闭环从用户点餐、商家接单到骑手配送、订单结算全链条都要管起来。今天这篇东西我就把整个项目从需求拆解、技术选型、数据库建模到核心接口设计和踩坑实录全流程过一遍。不管你现在的项目是刚起步、代码写到一半卡住了还是准备把已有代码升级成更完整的版本这篇文章都值得你花十分钟看完再动手。1. 需求拆解与功能边界划分做毕设最大的坑是什么是一上来就抄一个秒杀项目或者拿个什么后台管理系统直接改。结果答辩老师问你订单状态是怎么流转的你答不上来。所以第一步不是写代码而是把需求想清楚搞清楚你要交付的角色到底有哪几个。1.1 三类核心角色与对应的业务流程网上订餐系统的核心是订单订单是整个系统的总线。围绕这条总线最常见的角色划分有三种用户端小程序或H5页面浏览菜品、加入购物车、提交订单、支付、查看订单状态、申请退款。商家端Web后台菜品管理上架、下架、库存、订单接单/出餐、营业数据统计。管理端超级后台商家入驻审核、用户管理、订单监管、平台内容管理如公告、横幅。有些项目还会拆出骑手端。如果你把骑手也做进来工作量会上去20%左右但可展示的架构深度也明显增加——订单状态流转会更完整待接单 → 已接单→ 配送中 → 已完成。对于毕设来说我建议把骑手功能作为加分项来处理基础版本可以先做用户端商家端管理端如果时间充裕再加骑手配送流程。1.2 全流程信息化管控到底管控什么这个题目里最核心的词不是订餐而是**全流程信息化管控**。很多同学做出来的东西只是个CRUD那叫信息系统但不叫管控。管控意味着订单的整个生命周期每一步都有状态、有时间戳、有操作记录。我给的参考状态流转链路是待支付购物车确认后生成 → 已支付用户付款成功 → 待接单推送到商家端 → 商家已接单 → 制作中 → 配送中骑手提货 → 已完成 → 待评价可选环节有状态就得有状态变更日志这就是订单快照表的由来。继续往上做还可以加超时未支付自动取消、商家拒绝接单、用户取消申请退款这些分支。这个状态机设计好了你的论文里至少能写两页的内容答辩的时候也能凭空多出很多可以说的东西。1.3 功能清单的一版建议配置我按基础必做 进阶选做做了个清单你可以直接抄作业模块基础功能必做进阶功能选做用户端注册登录、菜品分类浏览、购物车、下单支付、订单列表地址管理、历史订单评价、优惠券商家端菜品CRUD、订单接单/出餐、基础数据统计菜品分类拖拽排序、日/周销售趋势图管理端用户封禁、商家审核、订单监管列表数据可视化大屏、权限分配系统支撑JWT登录鉴权、统一异常处理、跨域配置Redis缓存热点菜品、RabbitMQ订单异步化列到第三行的时候你应该已经发现了这个系统麻雀虽小五脏俱全对于毕设而言工作量拿捏得刚刚好——不会轻得像课设也不至于做到一半做不动。2. 技术选型背后的逻辑标题里已经点名了后端必须走 Java Spring Boot 方向前端必须上 Vue。这套组合是目前国内中小型Web项目最主流的搭配用它做毕设有个很大的好处面试的时候如果聊到项目面试官大概率也熟悉这套技术栈你们沟通成本会低很多。2.1 为什么是Spring Boot而不是SSM五年前做毕设还是SSMSpring SpringMVC MyBatis的天下现在再做SSM就有种老师傅修手扶拖拉机的感觉了。Spring Boot在这个场景里有几个致命的优势配置极简化不需要那一坨XML配置一个启动类就能把整个项目跑起来对毕设党的心态非常友好。生态极其成熟Spring Data Redis、Spring Security、RabbitMQ客户端等都是starter一键集成遇到问题百度一下全是答案。自带Tomcat打包就一个JAR部署的时候不用单独下载Tomcat。对毕设演示来说一台电脑一个JAR一把梭。2.2 Vue 2还是Vue 3我的建议如果你现在还处于学习阶段网上找的教程大多是Vue 2 Element UI那我建议你跟着教程走。毕设求稳不要做技术选型的先烈。如果你从零开始写代码那就直接上Vue 3 Vite Pinia别再碰Vue CLI和Vuex了。Vue 3和Vue 2最直观的区别是组合式APIComposition API让代码复用更舒服逻辑相关的代码可以写在一起不用在data、methods、computed之间来回蹦。Vite冷启动速度比Webpack快好几倍改完代码浏览器秒刷新。Pinia比Vuex更简单不用写那么多mutation直接改state。前端UI组件库这里Element Plus算是Vue 3的最佳搭档表格、表单、弹窗、分页都用得上。如果你需要做移动端H5那就Vant Vue 3手机浏览器上渲染效果也不错。2.3 MyBatis Plus的意义本身技术栈里加一个 MyBatis Plus能让你少写很多繁琐的重复SQL。为什么因为纯MyBatis需要你手写大量XML映射文件只是一张单表的话非常消磨耐心。MyBatis Plus的价值在于单表CRUD不需要写SQL继承一个BaseMapper接口自带insert、delete、update、selectById。自带分页插件一句分页搞定PageHelper式的语法不用担心方言兼容。代码生成器AutoGenerator可以根据数据库表自动生成实体类、Mapper、Service、Controller极大缩短建脚手架的时间。不过有一点要提醒你MyBatis Plus生成的Mapper里是一整套默认功能的SQL复杂查询比如多表联查还是得自己写。你理解成基础操作给你包办了高端操作还是得自己来就行。3. 数据库设计点餐业务的核心建模数据库设计是整个项目的地基这里如果设计得不好后期写代码能让你痛苦到怀疑人生。我强烈建议你先用PowerDesigner或draw.io把ER图画出来哪怕画得很糙也要在动手写代码之前想清楚表之间的关系。3.1 核心表结构一版参考订单是全流程信息化管控的核心所以和订单相关的表要设计得足够完整。第一个表用户表user用户表本身没什么好说的字段就是账号、密码、昵称、头像、手机号、状态。需要注意两个细节密码要加密存储推荐BCrypt别用MD5——对我知道MD5快但毕设答辩上老师问一句密码怎么存的你说MD5分数就降了。BCrypt每次生成的HASH都不一样安全性高很多。加一个逻辑删除字段deleted不要物理删用户数据否则订单里关联的用户信息就会变成无头数据。第二个表菜品表dish菜品表关联商家ID字段有菜品名称、图片、描述、价格、分类ID、起售状态这个字段做下架用不是物理删。价格用数据库的DECIMAL类型存不用float否则一旦发生精度问题你就等着期末查算账出岔子。第三个表订单表orders这是全系统的核心表最少包含以下字段字段说明order_sn订单编号格式建议yyyyMMddHHmmss 随机位user_id下单用户shop_id所属商家total_amount订单总金额保留两位小数status订单状态0待支付/1已支付/2商家已接单/3配送中/4已完成/5已取消address收货地址快照payment_time支付时间finish_time完成时间remark用户备注地址字段这里特别说一句下订单的时候要把用户的收货地址拷贝到订单表里而不是直接写user_id去关联用户表里的地址。为什么因为用户的地址是可以改的你订单生成之后不能因为用户改了地址而影响这笔订单的历史快照。这种历史快照的思维就是信息化管控系统比普通管理系统的加分项。第四个表订单明细表order_detail这个表专门存订单下每个菜品的信息菜品ID、菜品名称、菜品图片、价格、数量。为什么已经关联了菜品表还要把菜名、价格冗余一份因为商铺的菜品可能改了名字、涨了价但已经成交的订单必须保留下单那一刻的商品信息。这就是快照思想的第二次应用。第五个表菜品分类表、购物车表、商家表、管理员表这些表相对简单关联关系也就是外键维度。购物车表可以不用加外键约束逻辑上关联就行实际写代码的时候通过Java层的逻辑维护一致性。外键约束加多了反而影响某些框架的分页操作性能。3.2 用一个多商户还是单商户的取舍网上订餐系统通常会做成平台型类似美团外卖也就是一个平台里有很多商家。但很多毕设案例都做成单商户类似老王饭店的点餐系统这也说得过去但上限就低了。我建议你直接做多商户版本因为在系统设计的时候加一个shop_id只是多一个字段的成本但是呢它能让你顺理成章地说出RBAC权限控制多租户隔离商家独立经营空间这些专业词答辩的时候非常有面子。3.3 MyBatis Plus根据实体类生成建表SQL的技巧有些同学反着来先写Java实体类再根据实体类生成SQL。这在MyBatis Plus里也支持只要引入mybatis-plus-generator依赖配置好数据库连接信息和表名前缀直接执行代码生成器一张表对应的实体类、Mapper、Service、Controller全出来了。模板引擎用到Freemarker或者Velocity都行。生成之前要在全局配置里设置实体类的包路径、开启Lombok、开启swagger注释方便后续生成接口文档。用代码生成器不是为了偷懒而是为了「统一规范」——你手写的实体类容易在命名规范上歪掉生成的代码风格完全统一对毕设来说非常加分。4. 前后端核心流程实现从下单到派单写毕设的难点不在某个接口不会写而在于一整个业务流程的串联。用户端点击一个按钮后端要处理一堆东西前端要跳转好几个页面这套东西理顺了项目就立住了。4.1 用户下单流程的实现要点下单这一个操作后端接口内部至少要做这几件事校验用户登录状态通过JWT拦截器解析用户ID从购物车取数据计算出订单总额校验商家营业状态打烊了就别让人下单生成订单主表和明细表这里要开事务保证两个表同时写入清空购物车如果支付流程是模拟的那支付回调后更新订单为已支付我给一个参考的Service层核心方法的伪代码结构Transactional(rollbackFor Exception.class) public OrderVO submitOrder(OrderSubmitDTO dto) { // 1. 校验用户与商家状态 User user userService.getById(dto.getUserId()); Shop shop shopService.getById(dto.getShopId()); Assert.notNull(user, 用户不存在); Assert.isTrue(shop.getStatus() 1, 商家已打烊); // 2. 从购物车汇总购物项 ListCartItem cartItems cartService.getCartItems(dto.getUserId()); Assert.notEmpty(cartItems, 购物车不能为空); // 3. 计算总价保留两位小数 BigDecimal totalAmount cartItems.stream() .map(item - item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))) .reduce(BigDecimal.ZERO, BigDecimal::add); // 4. 生成订单主表 明细表 Orders order buildOrder(dto, totalAmount); orderService.save(order); ListOrderDetail details buildDetails(order.getId(), cartItems); orderDetailService.saveBatch(details); // 5. 清空购物车 cartService.clearCart(dto.getUserId()); // 6. 返回订单号 return OrderVO.builder().orderId(order.getId()).orderSn(order.getOrderSn()).build(); }这里最容易被忽略的是事务注解一定要加。一旦订单主表写入成功但明细表写入失败事务回滚就不会出现一笔找不到明细的幽灵订单。4.2 前端路由与页面状态流转Vue前端这边路由设计也要跟订单状态对齐。我建议的路由是/toHome # 首页展示分类和菜品 /toCart # 购物车页 /createOrder # 确认订单页选地址、填写备注 /payOrder/:orderSn # 支付页面模拟支付扫码 /orderList # 订单列表页按不同状态tab切换 /orderDetail/:orderSn # 订单详情页订单列表页通常是前端做得最费劲的部分因为你要按照状态tab去切换列表待支付、进行中、已完成、已取消。我建议干脆把所有订单一次查出来前端按status字段做tab内过滤数据量在毕设演示阶段完全够用代码反而更简单。路由守卫别忘了加// main.js或router目录下的全局前置守卫 router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (!token to.meta.requiresAuth) { next(/login); } else { next(); } });4.3 商家接单与订单推送的思路如果你是纯Web轮询方案那就简单商家端每隔3秒调用一次订单接口查询状态为待接单的订单有新单就弹窗提醒播放提示音。听起来有点土但毕设完全够用了。真要优化体验就上WebSocket或者SSEServer-Sent Events——我建议用SSE实现起来比WebSocket简单得多服务端一个SseEmitter就能把新订单推送到商家端页面前端就用EventSource监听。Redis在这个项目里还有个很实际的应用用Redis存储待接单订单的队列。用户支付成功后把orderSn推入一个Redis队列商家端监听这个队列有新数据就刷新待接单列表。这样你论文里又能多一个Redis的高性能应用场景。5. 实操避坑毕设最容易踩到的8个技术坑代码写到一半出问题太正常了这里我把每年学生踩得最多的坑整理成一个速查表你可以直接收藏。真遇到问题了照着这个表排查就能节约三小时起步。症状原因解决方法前端请求接口报CORS跨域后端没开启跨域Spring Boot添加WebMvcConfigurer重写addCorsMappings登录后每次请求都401JWT过期或Redis中的token不一致统一校验拦截器全局异常处理过期则返回特定code分页查询查不出来MyBatis Plus分页插件没注册添加MybatisPlusInterceptor Bean注册PaginationInnerInterceptor订单金额查出来是0.30000000000004用了float/double金额全部用BigDecimal构造时用字符串入参数据库存emoji报错UTF-8字符集不支持4字节字符数据库连接串加characterEncodingutf8mb4上传图片显示不出来没配置静态资源映射在配置类里addResourceHandlers映射本地图片目录刷新页面404Vue路由是history模式后端开启forward到index.html或改用hash模式时间差8小时服务器时区UTC数据库连接串加serverTimezoneAsia/Shanghai这几个坑每一个我都亲自踩过一遍尤其是跨域和分页插件的问题几乎每年都会有人在群里问一遍。5.1 跨域问题实操配置Spring Boot后端如果是本地开发前端是Vite起的5173端口你直接在配置类里加一段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); } }这里有个小细节如果前端用了axios发请求且带了token自定义header那allowedHeaders必须配*allowCredentials必须与allowedOriginPatterns配合。如果只配了某个固定域名可以但前端调用跨端口请求时会报请求头不够丰富。5.2 时间字段处理的金标准前后端日期传输不要传时间戳数字进去不然前端格式化会疯掉。我的建议是统一用Jackson的全局配置把Long类型时间戳转成字符串返回或者统一格式化LocalDateTime。spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8Java实体里的时间字段用LocalDateTime不用Date。LocalDateTime更直观配合Jackson序列化也方便。5.3 电脑环境准备一页纸环境准备这一节很多人愣是卡了两三天我直接把有效步骤列在这按顺序执行就完事JDK装JDK 8或者JDK 11配好JAVA_HOME和PATH环境变量命令行输入java -version有输出就行。Maven下载zip解压就行不用安装包配置好阿里云镜像仓库settings.xml里加mirror不然拉依赖能慢到怀疑人生。Node.js装16以上版本npm install装vue项目依赖时记得顺手把淘宝镜像配一下npm config set registry。IDE后端用IntelliJ IDEA社区版够用前端可以用VS Code或者WebStorm。IDEA全家桶也可以打开两个项目窗口。后端项目启动命令一行都不用记IDEA右上角点绿色运行按钮就行。前端就npm run dev。6. 项目部署与答辩演示的加分项很多人的毕设代码写完了一到要演示的时候就崩。原因无非是本地环境问题、数据库没导入、端口冲突。我建议你在答辩前一天做一次干净的部署演练开一台没用过的虚拟机从零装JDK、MySQL、Node然后一步步启动项目。这一步操作下来能在答辩时帮你捡回很多分。6.1 打包部署的两种方案方案一推荐前后端分开打包部署后端IDEA里右侧Maven面板选择package生成一个xxx.jar文件命令行java -jar xxx.jar就能跑。前端Vue项目终端执行npm run build生成dist目录整个目录拷贝到Nginx的html目录下。Nginx里配一个反向代理把/api开头的请求转发到Spring Boot的8080端口。方案二省事前端打成静态资源放到后端的static目录把dist目录下的内容复制到后端src/main/resources/static下重新打包成一个JAR单文件部署演示的时候一条命令全起来弊端前后端代码耦合了后续改前端要重新打包。我个人推荐方案一因为面试聊这个项目的时候Nginx反向代理这个概念本身就是个加分项。6.2 答辩演示脚本的标准化流程演示别上来就登录进后台点来点去那样显得很乱。我建议按这样走第一幕从用户端首页开始演示浏览菜品 → 加入购物车 → 下单 → 支付全流程注意停留一下展示金额计算正确。第二幕切换到商家端演示接单和出餐操作等用户端页面状态变化后向评委说明这是通过WebSocket/轮询实现的实时联动。第三幕进入管理端展示数据统计列表或可视化面板说明平台对所有订单的总体监控能力。第四幕顺手展示一项亮点技术——比如超时自动取消订单若已经实现快速点开代码定位到定时任务那段讲一讲原理。每次演示前记得把数据库重新初始化一下用演示数据脚本来回滚保持场景一致性。6.3 值得在论文中单独展开的三个技术亮点如果你的论文章节需要撑篇幅我强烈推荐下面三个方向随便选一个展开到三四千字订单状态机的设计状态流转表、异常流、状态变更日志表、定时任务扫描超时订单。高并发场景下的库存扣减策略用库存预扣方案创建订单时不减库存支付成功才真正扣减超时回滚释放。写清楚唯一索引防订单重复的问题。权限与数据隔离RBAC模型如何落到用户、商家、管理员三种角色上如何实现商家只能看自己的订单的数据权限过滤。这三块每一块都有得写、有得画图、有得聊答辩老师但凡问为什么这么设计你都有话接。7. 关于这个项目后续扩展的一些想法项目做完之后代码别扔进回收站。网上订餐系统是一个特别耐打的业务底座再往里加东西很容易比如接一个微信小程序前端业务逻辑全复用只写页面答辩时直接说跨端方案。给商家端加数据大屏对接ECharts展示近七日的销售额曲线前端效果很震撼。把订单模块拆成独立微服务引入Feign调用面试聊微服务的时候就有项目支撑了。引入ES或全文检索做菜品的模糊搜索。百度搜索能力就差在模糊查询上你要是做了这个功能面试官必然会问。我个人在实际操作中的体会是毕设这个东西选一个人人都用过、逻辑链条完整、可扩展性强的业务模型比选一个听起来高大上的AI题目要稳妥得多。网上订餐系统就是这么个典型——业务贴近生活、技术栈主流、成长性好。从现在开始定题目花两周搭框架两周把核心下单流程跑通剩下时间修细节、写论文、做PPT顺利毕业的把握还是很大的。最后再分享一个小经验写项目之前先给自己留一个演示账号清单用户、商家、管理员各一个密码记好、状态保持如常。很多人在答辩前紧张现场还到处翻数据库找账号体验非常差。提前准备好演示时直接一气呵成那就稳了。
阅读完成 · 觉得有帮助?