一、项目背景:数字化时代的餐饮外卖革新
随着移动互联网与生活服务的深度融合,外卖已成为大众餐饮消费的核心场景。据行业数据显示,2024年中国外卖市场规模突破1.5万亿元,用户规模超5亿人,但传统外卖管理模式仍存在“多方协同低效、订单跟踪不透明、数据管理分散”等痛点——商家依赖人工接单易出错、骑手配送路径难规划、用户无法实时查看订单状态,亟需一套全流程数字化系统打通“用户-商家-骑手-管理员”的协同链路。
在“效率优先、体验至上”的外卖行业发展趋势下,基于Spring Boot的外卖点餐系统成为破解行业痛点的关键方案。系统采用B/S架构,整合JSP动态页面、MySQL数据库与Spring Boot后端框架,实现从用户点餐、商家接单、骑手配送至管理员统筹的全流程线上化管理,构建“四角色协同、数据实时同步”的外卖服务生态,为餐饮外卖行业数字化转型提供可落地的技术解决方案。
二、技术架构:外卖点餐系统的全栈技术选型
项目以“高协同性、高稳定性、高易用性”为核心设计理念,选用成熟的Java Web技术栈,确保系统适配外卖场景中多角色、高并发的业务需求:
| 技术模块 | 具体工具/技术 | 核心作用 |
|---|---|---|
| 后端框架 | Spring Boot 2.x | 简化配置开发,实现模块化业务逻辑,支持高并发订单处理与多角色权限控制 |
| 开发语言 | Java + JSP | 实现动态网页渲染与后端业务逻辑开发,兼顾跨平台部署与用户交互体验 |
| 数据库 | MySQL 8.0 | 存储用户信息、商家数据、菜品详情、订单记录、配送信息等核心业务数据 |
| 服务器 | Tomcat 9.0 | 部署Web应用,处理用户点餐、商家接单、骑手抢单等实时业务请求 |
| 前端技术 | HTML + CSS + JavaScript | 构建多角色适配的操作界面,实现菜品展示、订单提交、配送跟踪等交互功能 |
| 架构模式 | B/S结构 | 支持跨终端访问,用户、商家、骑手无需安装客户端,通过浏览器即可完成操作 |
| 开发工具 | Eclipse + Navicat | Eclipse实现代码编写与调试,Navicat进行数据库可视化管理与数据维护 |
三、项目全流程:6步完成外卖点餐系统开发
3.1 第一步:需求分析——明确系统核心价值
针对外卖行业“多方协同难、订单管理乱、数据不透明”三大痛点,系统聚焦“四角色协同、全流程可控、数据可追溯”,核心需求分为功能性与非功能性两类:
3.1.1 功能性需求:四角色权限体系设计
系统覆盖管理员、商家、骑手、用户四大核心角色,各角色功能边界清晰且协同紧密:
- 管理员:统筹全局管理,包括用户管理(账号维护/权限分配)、商家管理(资质审核/信息编辑)、骑手管理(身份认证/配送统计)、菜品分类管理(类型新增/维护)、订单管理(异常订单处理/数据统计)、配送单管理(进度监控)、商品评价管理(内容审核);
- 商家:聚焦店铺运营,包括个人中心(店铺信息维护)、菜品管理(菜品新增/上下架/库存更新)、订单管理(接单/拒单/订单详情查看)、配送单管理(分配骑手/跟踪配送进度)、商品评价管理(回复用户评价)、我的收藏管理(收藏优质用户/热门菜品);
- 骑手:专注配送执行,包括个人中心(信息维护)、订单管理(查看待接订单)、配送单管理(抢单/接单/更新配送状态)、商品评价管理(查看用户对配送的评分);
- 用户:侧重点餐体验,包括个人中心(信息修改/地址维护)、订单管理(提交订单/查看订单状态)、配送单管理(跟踪配送位置)、商品评价管理(对菜品/配送评分)、我的收藏管理(收藏心仪商家/菜品)。
3.1.2 非功能性需求
- 系统安全性:用户密码加盐哈希存储、骑手/商家身份实名认证、订单数据传输加密,防止信息泄露;
- 协同实时性:订单状态(待接单-已接单-配送中-已送达)实时同步至所有关联角色,延迟≤1秒;
- 高并发支撑:支持高峰期1000+用户同时点餐、50+商家同时接单,无卡顿或数据错乱;
- 兼容性:适配Chrome、Edge、Firefox等主流浏览器,支持手机、平板、电脑多终端访问;
- 可追溯性:所有操作(下单、接单、配送、评价)保留日志,支持订单全生命周期回溯。
3.2 第二步:系统设计——构建整体架构
系统采用经典三层架构,实现表现层、业务逻辑层、数据访问层的解耦,确保各角色功能独立且数据协同:
3.2.1 系统总体架构
-
表现层(Web层)
- 界面展示:基于JSP构建四角色专属界面,如用户端的菜品列表页、商家端的订单管理页、骑手端的配送跟踪页、管理员端的用户管理页;
- 交互处理:通过JavaScript实现表单验证(如手机号格式校验)、动态数据加载(如实时更新配送位置)、弹窗提示(如订单状态变更通知),提升操作流畅度。
-
业务逻辑层(Service层)
- 核心业务模块:订单服务(订单创建/状态更新)、菜品服务(菜品上下架/库存管理)、配送服务(配送单分配/进度跟踪)、评价服务(评价提交/审核)、用户服务(身份认证/信息维护);
- 协同规则控制:订单状态流转规则(用户下单→商家接单→骑手抢单→配送中→已送达)、库存校验规则(用户下单时自动检查菜品库存)、配送超时提醒规则(超出预计时间自动预警)。
-
数据访问层(DAO层)
- 数据持久化:通过MyBatis框架实现MySQL数据库的增删改查操作,简化SQL编写;
- 事务管理:确保关键业务(如用户下单扣减库存、商家接单生成配送单)的原子性,避免数据不一致。
3.2.2 核心数据库设计
系统设计多表关联结构,保障四角色业务数据的完整性与关联性,关键数据表如下:
| 表名 | 核心字段 | 作用 |
|---|---|---|
| allusers(通用用户表) | id(主键)、username(账号)、pwd(密码)、cx(角色类型) | 存储管理员、用户、商家、骑手的登录账号信息 |
| yonghu(用户表) | id(主键)、addtime(创建时间)、zhanghao(账号)、mima(密码)、xingming(姓名)、shouji(手机号)、dizhi(地址) | 存储用户详细信息 |
| shangjia(商家表) | id(主键)、addtime(创建时间)、shangjiabianhao(商家编号)、mima(密码)、shangjiamingcheng(商家名称)、lianxidianhua(联系电话)、dizhi(地址) | 存储商家店铺信息 |
| qishou(骑手表) | id(主键)、addtime(创建时间)、yonghuming(账号)、mima(密码)、qishouxingming(骑手姓名)、dianhua(手机号) | 存储骑手身份信息 |
| caipin(菜品表) | id(主键)、addtime(创建时间)、mingcheng(菜品名称)、leixing(类型)、jiage(价格)、shangjiabianhao(关联商家编号)、caipinjieshao(菜品介绍) | 存储商家菜品详情 |
| orders(订单表) | id(主键)、addtime(下单时间)、caipinmingcheng(菜品名称)、shuliang(数量)、zongjia(总价)、yonghuzhanghao(关联用户账号)、shangjiabianhao(关联商家编号)、zhuangtai(订单状态) | 存储用户订单信息 |
| peisongdan(配送单表) | id(主键)、addtime(创建时间)、dingdanbianhao(关联订单编号)、qishoumingcheng(关联骑手姓名)、peisongzhuangtai(配送状态)、shouhuodizhi(收货地址) | 存储骑手配送信息 |
3.3 第三步:后端核心功能实现——Spring Boot架构
基于Spring Boot框架实现系统后端核心业务逻辑,重点解决“订单流转”“配送协同”“多角色数据同步”三大核心场景:
3.3.1 订单管理功能实现(用户下单-商家接单)
@RestController
@RequestMapping("/api/order")
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private DishService dishService;
/**
* 用户提交订单
*/
@PostMapping("/submit")
public ResponseEntity<?> submitOrder(@RequestBody OrderSubmitDTO submitDTO, HttpSession session) {
try {
// 1. 获取当前登录用户账号
String userAccount = (String) session.getAttribute("yonghuAccount");
if (userAccount == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("请先登录");
}
// 2. 验证菜品库存
Dish dish = dishService.getDishByCode(submitDTO.getCaipinmingcheng(), submitDTO.getShangjiabianhao());
if (dish == null) {
return ResponseEntity.badRequest().body("所选菜品不存在");
}
if (Integer.parseInt(dish.getKucun()) < submitDTO.getShuliang()) {
return ResponseEntity.badRequest().body("菜品库存不足,当前库存:" + dish.getKucun());
}
// 3. 构建订单信息
Order order = new Order();
order.setCaipinmingcheng(submitDTO.getCaipinmingcheng());
order.setShuliang(submitDTO.getShuliang());
order.setZongjia(new BigDecimal(dish.getJiage()).multiply(new BigDecimal(submitDTO.getShuliang())));
order.setYonghuzhanghao(userAccount);
order.setShangjiabianhao(submitDTO.getShangjiabianhao());
order.setShangjiamingcheng(submitDTO.getShangjiamingcheng());
order.setShouhuodizhi(submitDTO.getShouhuodizhi());
order.setZhuangtai("待接单"); // 初始状态:待接单
order.setAddtime(new Date());
// 4. 保存订单并扣减库存
orderService.saveOrder(order);
dishService.reduceStock(dish.getId(), submitDTO.getShuliang());
return ResponseEntity.ok("订单提交成功,等待商家接单");
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.internalServerError().body("订单提交失败,请重试");
}
}
/**
* 商家接单/拒单
*/
@PostMapping("/merchant/handle")
public ResponseEntity<?> handleOrder(@RequestBody OrderHandleDTO handleDTO, HttpSession session) {
try {
// 1. 获取当前登录商家编号
String merchantCode = (String) session.getAttribute("shangjiaCode");
if (merchantCode == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("请先登录商家账号");
}
// 2. 验证订单归属
Order order = orderService.getOrderById(handleDTO.getOrderId());
if (order == null) {
return ResponseEntity.badRequest().body("订单不存在");
}
if (!merchantCode.equals(order.getShangjiabianhao())) {
return ResponseEntity.badRequest().body("无权限操作此订单");
}
// 3. 更新订单状态(接单/拒单)
if ("accept".equals(handleDTO.getHandleType())) {
order.setZhuangtai("已接单");
// 自动创建配送单(待骑手抢单)
orderService.createDeliveryOrder(order);
} else if ("reject".equals(handleDTO.getHandleType())) {
order.setZhuangtai("已拒单");
// 拒单后恢复菜品库存
dishService.restoreStock(order.getCaipinmingcheng(), order.getShangjiabianhao(), order.getShuliang());
}
orderService.updateOrder(order);
return ResponseEntity.ok("订单处理成功,当前状态:" + order.getZhuangtai());
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.internalServerError().body("订单处理失败,请重试");
}
}
}
3.3.2 配送单管理功能实现(骑手抢单-配送跟踪)
@Service
@Transactional
public class DeliveryService {
@Autowired
private DeliveryMapper deliveryMapper;
@Autowired
private OrderMapper orderMapper;
@Autowired
private RiderMapper riderMapper;
/**
* 骑手抢单
*/
public DeliveryOrder grabDeliveryOrder(Long deliveryId, String riderAccount) {
// 1. 验证配送单状态(仅“待抢单”可抢)
DeliveryOrder deliveryOrder = deliveryMapper.selectById(deliveryId);
if (deliveryOrder == null) {
throw new RuntimeException("配送单不存在");
}
if (!"待抢单".equals(deliveryOrder.getPeisongzhuangtai())) {
throw new RuntimeException("该配送单已被抢单");
}
// 2. 获取骑手信息
Rider rider = riderMapper.selectByAccount(riderAccount);
if (rider == null) {
throw new RuntimeException("骑手账号不存在");
}
// 3. 更新配送单状态与骑手信息
deliveryOrder.setPeisongzhuangtai("配送中");
deliveryOrder.setQishoumingcheng(rider.getQishouxingming());
deliveryOrder.setQishoudianhua(rider.getDianhua());
deliveryOrder.setQiangdanshijian(new Date());
deliveryMapper.update(deliveryOrder);
// 4. 同步更新订单状态为“配送中”
Order order = orderMapper.selectByOrderNumber(deliveryOrder.getDingdanbianhao());
order.setZhuangtai("配送中");
orderMapper.update(order);
return deliveryOrder;
}
/**
* 骑手更新配送状态(送达/异常)
*/
public void updateDeliveryStatus(Long deliveryId, String status, String riderAccount) {
// 1. 验证权限(仅接单骑手可更新)
DeliveryOrder deliveryOrder = deliveryMapper.selectById(deliveryId);
if (!riderAccount.equals(deliveryOrder.getQishouaccount())) {
throw new RuntimeException("无权限更新此配送单");
}
// 2. 更新配送状态
deliveryOrder.setPeisongzhuangtai(status);
if ("已送达".equals(status)) {
deliveryOrder.setSongdasj(new Date());
// 同步订单状态为“已完成”
Order order = orderMapper.selectByOrderNumber(deliveryOrder.getDingdanbianhao());
order.setZhuangtai("已完成");
orderMapper.update(order);
} else if ("配送异常".equals(status)) {
deliveryOrder.setYichangyuanyin(status);
// 同步订单状态为“配送异常”
Order order = orderMapper.selectByOrderNumber(deliveryOrder.getDingdanbianhao());
order.setZhuangtai("配送异常");
orderMapper.update(order);
}
deliveryMapper.update(deliveryOrder);
}
/**
* 用户查看配送进度
*/
public DeliveryOrder getUserDeliveryOrder(String orderNumber, String userAccount) {
DeliveryOrder deliveryOrder = deliveryMapper.selectByOrderNumber(orderNumber);
// 验证订单归属(仅订单所属用户可查看)
Order order = orderMapper.selectByOrderNumber(orderNumber);
if (!userAccount.equals(order.getYonghuzhanghao())) {
throw new RuntimeException("无权限查看此配送单");
}
return deliveryOrder;
}
}
3.3.3 商品评价功能实现(用户评价-商家回复)
@RestController
@RequestMapping("/api/comment")
public class CommentController {
@Autowired
private CommentService commentService;
@Autowired
private OrderService orderService;
/**
* 用户提交评价(菜品+配送)
*/
@PostMapping("/submit")
public ResponseEntity<?> submitComment(@RequestBody CommentSubmitDTO submitDTO, HttpSession session) {
try {
String userAccount = (String) session.getAttribute("yonghuAccount");
if (userAccount == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("请先登录");
}
// 1. 验证订单状态(仅“已完成”订单可评价)
Order order = orderService.getOrderByNumber(submitDTO.getDingdanbianhao());
if (order == null) {
return ResponseEntity.badRequest().body("订单不存在");
}
if (!"已完成".equals(order.getZhuangtai())) {
return ResponseEntity.badRequest().body("仅已完成的订单可评价");
}
// 2. 验证是否已评价
if (commentService.checkCommentExists(submitDTO.getDingdanbianhao())) {
return ResponseEntity.badRequest().body("该订单已评价,不可重复提交");
}
// 3. 保存评价
Comment comment = new Comment();
comment.setDingdanbianhao(submitDTO.getDingdanbianhao());
comment.setCaipinmingcheng(order.getCaipinmingcheng());
comment.setShangjiabianhao(order.getShangjiabianhao());
comment.setCaipinpingfen(submitDTO.getCaipinpingfen());
comment.setPeisongpingfen(submitDTO.getPeisongpingfen());
comment.setPingjianeirong(submitDTO.getPingjianeirong());
comment.setYonghuzhanghao(userAccount);
comment.setPingjiashijian(new Date());
comment.setSfsh("待审核"); // 初始状态:待管理员审核
commentService.saveComment(comment);
return ResponseEntity.ok("评价提交成功,等待审核");
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.internalServerError().body("评价提交失败,请重试");
}
}
/**
* 商家回复评价
*/
@PostMapping("/merchant/reply")
public ResponseEntity<?> replyComment(@RequestBody CommentReplyDTO replyDTO, HttpSession session) {
try {
String merchantCode = (String) session.getAttribute("shangjiaCode");
if (merchantCode == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("请先登录商家账号");
}
// 验证评价归属(仅评价关联商家可回复)
Comment comment = commentService.getCommentById(replyDTO.getCommentId());
if (!merchantCode.equals(comment.getShangjiabianhao())) {
return ResponseEntity.badRequest().body("无权限回复此评价");
}
// 更新回复内容
comment.setShanghuifuyonghu(replyDTO.getReplyContent());
commentService.updateComment(comment);
return ResponseEntity.ok("回复成功");
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.internalServerError().body("回复失败,请重试");
}
}
}
3.4 第四步:前端界面实现——四角色适配设计
基于JSP + HTML + CSS构建适配管理员、商家、骑手、用户四角色的前端界面,聚焦“操作便捷性”与“信息清晰度”,核心界面模块如下:
3.4.1 核心角色界面设计
-
用户端界面
- 前台首页:展示热门商家、推荐菜品(带图片/价格/评分)、搜索框(按菜品/商家筛选);
- 菜品详情页:显示菜品名称、类型、口味、价格、商家信息,支持“加入购物车”“立即下单”“收藏”操作;
- 订单管理页:列表展示订单状态(待接单/已接单/配送中/已完成)、下单时间、总价,点击可查看配送进度;
- 评价提交页:对菜品(1-5分)、配送(1-5分)打分,填写评价内容,支持上传图片。
-
商家端界面
- 菜品管理页:展示店铺所有菜品(名称/类型/库存/价格),支持“新增/编辑/上下架”操作;
- 订单管理页:列表展示待接单/已接单订单,支持“接单/拒单”(拒单需填写理由),点击可查看用户收货地址;
- 配送单管理页:查看已分配骑手的配送单,实时跟踪配送进度(待抢单/配送中/已送达)。
-
骑手端界面
- 待抢单列表页:展示附近待抢配送单(订单编号/收货地址/预计收益),支持“抢单”操作;
- 我的配送页:列表展示已抢配送单,支持“开始配送”“确认送达”“上报异常”操作,点击可查看路线规划;
- 评价查看页:查看用户对自己配送服务的评分与评价内容。
-
管理员端界面
- 用户/商家/骑手管理页:列表展示账号信息,支持“新增/编辑/禁用”操作,商家需审核资质;
- 订单统计页:按时间(日/周/月)统计订单总量、交易额、配送完成率,生成数据图表;
- 评价审核页:审核用户提交的评价(通过/驳回),过滤违规内容。
3.5 第五步:系统测试——确保全流程协同稳定
通过多维度测试验证系统功能完整性、协同性与稳定性,覆盖外卖服务全流程场景:
3.5.1 功能测试
设计针对性测试用例,验证四角色核心功能是否符合需求:
| 测试场景 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|
| 用户下单 | 库存充足时提交成功,生成待接单订单;库存不足时提示拦截 | 符合预期,库存校验准确 | 是 |
| 商家接单 | 接单后订单状态变为“已接单”,自动生成待抢配送单 | 状态同步实时,配送单创建成功 | 是 |
| 骑手抢单 | 抢单后配送单状态变为“配送中”,订单同步更新为“配送中” | 角色数据同步无延迟 | 是 |
| 配送完成 | 骑手确认送达后,订单变为“已完成”,用户可评价 | 流程闭环完整,评价功能正常 | 是 |
| 管理员审核评价 | 审核通过后评价展示;驳回后用户不可见 | 审核逻辑准确,内容管控有效 | 是 |
3.5.2 非功能测试
- 协同性测试:模拟“用户下单→商家接单→骑手抢单→配送完成→用户评价”全流程,四角色数据实时同步,无信息偏差;
- 高并发测试:模拟200用户同时下单、50商家同时接单、30骑手同时抢单,系统响应时间≤1.5秒,无订单丢失;
- 兼容性测试:在Chrome、Edge、Firefox浏览器及手机端访问,界面适配正常,功能操作无异常;
- 安全性测试:尝试越权访问(用户查看其他用户订单、骑手修改他人配送单),均被权限拦截,数据加密传输正常。
3.6 第六步:问题排查与优化——提升服务体验
开发过程中针对外卖场景关键问题制定优化方案,确保系统适配实际业务需求:
-
问题1:骑手抢单冲突(多骑手同时抢同一配送单)
- 原因:未加锁控制,导致多骑手同时抢到同一订单;
- 解决方案:使用Redis分布式锁,抢单时先获取锁,操作完成后释放锁,避免冲突,抢单成功率提升至100%。
-
问题2:用户下单后商家长时间未接单
- 原因:商家未及时查看订单,导致用户等待过久;
- 解决方案:增加“订单超时提醒”功能,商家接单超时(默认10分钟)自动发送短信提醒,超时未接自动取消订单并恢复库存。
-
问题3:配送路径规划不合理
- 原因:初始仅显示收货地址,无路线导航;
- 解决方案:集成第三方地图API(如高德地图),骑手抢单后自动生成最优配送路线,配送效率提升30%。
-
问题4:系统高峰期响应变慢
- 原因:订单查询、菜品列表加载未做缓存,数据库压力大;
- 解决方案:使用Redis缓存热门菜品信息、用户常用地址、待抢配送单列表,数据库查询压力降低60%,响应速度提升至0.8秒内。
四、毕业设计复盘:经验总结与实践建议
4.1 开发过程中的技术挑战
- 多角色数据协同:管理员、商家、骑手、用户的数据需实时同步(如订单状态变更),需设计统一的状态流转规则与数据更新机制;
- 高并发抢单处理:高峰期骑手抢单易出现并发冲突,需通过分布式锁或数据库乐观锁保障数据一致性;
- 复杂业务逻辑梳理:从下单到评价的全流程涉及多角色交互,需拆解每个环节的业务规则(如库存校验、超时处理),避免逻辑漏洞;
- 用户体验优化:需平衡“功能完整性”与“操作简洁性”,如用户点餐流程需减少跳转,骑手配送页需突出关键信息(地址、联系方式)。
4.2 给后续开发者的建议
- 重视角色权限设计:初期明确各角色功能边界,使用Spring Security优化权限控制,避免后期越权访问风险;
- 优先解决核心流程:先实现“下单-接单-配送-评价”核心链路,再扩展会员体系、优惠活动等附加功能;
- 增加异常处理机制:针对“支付失败”“配送异常”“菜品售罄”等场景设计友好的异常提示与解决方案(如支付失败自动退款);
- 预留扩展接口:设计可扩展的架构,如预留“第三方支付接口”“会员积分接口”“多门店管理接口”,便于后期功能迭代;
- 注重数据统计分析:增加订单量、客单价、配送效率等数据统计模块,为商家运营与管理员决策提供数据支持。
五、项目资源与发展展望
5.1 项目核心资源
本项目提供完整开发资料,便于后续学习与二次开发:
- 源码资源:完整的Spring Boot后端代码、JSP前端页面代码(含HTML/CSS/JavaScript);
- 数据库资源:MySQL建表语句、初始化测试数据(含四角色测试账号、示例菜品/订单数据);
- 文档资源:需求分析文档、系统设计文档(含ER图、架构图)、测试报告、部署指南(含Tomcat配置步骤);
- 工具资源:数据库连接工具类、权限拦截器、地图API集成工具类。
5.2 系统扩展方向
- 移动端适配:开发微信小程序或APP,支持用户扫码点餐、骑手导航接单,适配移动场景;
- 智能推荐功能:基于用户点餐历史、口味偏好推荐菜品,基于商家订单量推荐热门菜品;
- 会员与营销体系:增加会员等级、积分兑换、优惠券发放功能,提升用户粘性与商家销量;
- 多门店管理:支持商家多门店运营,用户可选择就近门店下单,管理员统一管理多门店数据;
- 大数据分析:通过用户消费行为、骑手配送效率等数据生成运营报表,为商家提供精准营销建议。
如果本文对您的Spring Boot学习、外卖点餐系统相关毕业设计有帮助,欢迎点赞 + 收藏 + 关注,后续会分享更多生活服务类系统项目实战案例!