1. 项目背景与需求分析
在餐饮行业数字化转型的浪潮下,传统纸质菜单点餐方式暴露出诸多痛点:菜品更新不及时、人工记录易出错、高峰期服务效率低下、经营数据难以统计分析等。作为一名经历过多次餐饮系统开发的工程师,我深刻理解一套可靠的店内点餐系统对餐厅运营的重要性。
本次设计的SpringBoot餐厅点餐系统主要解决以下核心问题:
- 信息实时同步:解决纸质菜单菜品售罄后仍需人工告知的尴尬
- 服务效率提升:通过移动端点餐减少服务员往返时间
- 经营数据可视化:自动生成销量统计、热门菜品等经营报表
- 多角色协同:满足顾客、服务员、后厨、管理者的不同需求
实际开发中发现:中小型餐厅更关注系统的易用性和稳定性,而非复杂功能。因此我们采用SpringBoot+MyBatis的轻量级组合,避免过度设计。
2. 技术选型与架构设计
2.1 技术栈决策依据
后端框架选择:
- SpringBoot 2.7.x:内嵌Tomcat简化部署,starter依赖自动配置
- MyBatis-Plus 3.5.x:减少90%的常规SQL编写
- Hutool 5.8.x:处理Java基础工具类
数据库选择:
- MySQL 8.0:满足ACID要求,社区资源丰富
- Redis 6.x:缓存热门菜品数据和购物车信息
前端技术:
- Thymeleaf:服务端渲染管理后台
- 微信小程序:顾客端主要入口(考虑用户使用习惯)
2.2 系统架构图解
系统采用经典三层架构,但针对餐饮业务特点做了优化:
code复制[微信小程序] ←HTTP→ [SpringBoot] ←JDBC→ [MySQL]
↑
| WebSocket
↓
[厨房打印机]
关键设计考量:
- 订单状态推送:使用WebSocket实现后厨实时接单
- 缓存策略:菜品信息Redis缓存+本地Caffeine二级缓存
- 分布式锁:解决超卖问题(Redisson实现)
3. 核心功能实现细节
3.1 多角色权限设计
采用RBAC模型进行权限控制,但根据餐饮场景做了简化:
java复制// 权限注解示例
@PreAuthorize("hasRole('WAITER') or hasRole('ADMIN')")
@PostMapping("/order/confirm")
public R confirmOrder(@RequestBody OrderVO vo) {
// 服务员确认订单逻辑
}
权限划分:
- 顾客:浏览菜单、下单、支付
- 服务员:接单、催单、结账
- 管理员:全功能管理
3.2 菜品管理模块
数据库设计特别注意了扩展性:
sql复制CREATE TABLE `dish` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '菜品名称',
`category_id` int NOT NULL COMMENT '分类ID',
`price` decimal(10,2) NOT NULL COMMENT '售价',
`cost` decimal(10,2) DEFAULT NULL COMMENT '成本价',
`status` tinyint DEFAULT '1' COMMENT '1上架 0下架',
`sort` int DEFAULT '0' COMMENT '排序权重',
`description` text COMMENT '菜品描述',
`spicy_level` tinyint DEFAULT '0' COMMENT '辣度0-5',
`is_featured` bit(1) DEFAULT b'0' COMMENT '是否推荐',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
开发技巧:
- 使用MyBatis-Plus的
@TableField处理自动填充 - 图片上传采用七牛云OSS+本地备份双存储
- 实现Elasticsearch菜品搜索(可选)
3.3 订单业务流程
典型订单状态机设计:
code复制待支付 → 已支付 → 制作中 → 已上菜 → 已完成
↓
取消订单(15分钟内可取消)
关键代码片段:
java复制// 订单超时取消设计
@Scheduled(fixedRate = 60000) // 每分钟检查
public void checkOrderTimeout() {
List<Order> unpaidOrders = orderMapper.selectUnpaidOrders(15);
unpaidOrders.forEach(order -> {
order.setStatus(OrderStatus.CANCELLED);
orderMapper.updateById(order);
// 释放库存
redisTemplate.opsForValue().increment(
"dish_stock:" + order.getDishId(),
order.getQuantity());
});
}
4. 典型问题解决方案
4.1 高并发下单控制
采用分布式锁解决超卖问题:
java复制public boolean placeOrder(Long dishId, Integer quantity) {
String lockKey = "lock:dish:" + dishId;
RLock lock = redissonClient.getLock(lockKey);
try {
if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {
// 检查库存
Integer stock = dishService.getStock(dishId);
if (stock >= quantity) {
// 扣减库存
dishService.reduceStock(dishId, quantity);
return true;
}
}
} finally {
lock.unlock();
}
return false;
}
4.2 移动端适配问题
微信小程序开发注意事项:
- 使用
wx.login获取openid作为用户唯一标识 - 支付接口必须使用微信支付
- 图片上传需先获取临时路径
4.3 性能优化实践
- Nginx配置:
nginx复制location /static/ {
expires 30d;
add_header Cache-Control "public";
}
- JVM参数调优:
bash复制java -jar -Xms512m -Xmx1024m -XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 restaurant.jar
5. 部署与运维建议
5.1 生产环境部署
推荐使用Docker Compose编排:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql-data:/var/lib/mysql
redis:
image: redis:6-alpine
ports:
- "6379:6379"
app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- redis
5.2 监控方案
基础监控三板斧:
- SpringBoot Actuator暴露健康检查
- Prometheus + Grafana监控JVM指标
- ELK收集业务日志
6. 项目演进方向
根据实际运营反馈,建议后续迭代:
- 增加会员积分系统
- 开发菜品销量预测功能
- 实现智能推荐(协同过滤算法)
- 接入第三方配送平台API
在开发过程中,最大的体会是:餐饮系统必须考虑极端场景下的稳定性。比如我们在压力测试时发现,当并发订单量突增时,数据库连接池容易成为瓶颈。最终通过调整HikariCP配置和增加Redis缓存层解决了这个问题:
properties复制# application-prod.properties
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.connection-timeout=30000