在餐饮行业数字化转型浪潮中,网上点餐系统已成为连接商家与消费者的重要纽带。作为一名经历过多个餐饮系统开发的老手,我深知传统纸质菜单的痛点:高峰期服务员应接不暇、订单错漏频发、经营数据难以沉淀。这个基于SpringBoot+Vue+MySQL的解决方案,正是针对这些行业痛点设计的实战型项目。
系统采用前后端分离架构,后端使用SpringBoot 2.7提供RESTful API,前端通过Vue 3组合式API构建交互界面,MySQL 8.0作为数据存储引擎。这种技术组合在保证系统性能的同时,极大提升了开发效率——实测从零搭建基础框架仅需2小时,这得益于SpringBoot的自动配置和Vue的模块化设计。
选择SpringBoot而非传统SSM框架,主要基于三点考量:
前端选用Vue.js+ElementUI的组合,实测比React+AntD方案减少约30%的代码量。特别是在动态表单生成方面,Vue的v-for指令配合ElementUI的el-form组件,可以极简实现菜品规格选择功能。
采用JWT+RBAC的混合认证模式:
java复制// JWT生成核心代码示例
public String generateToken(Long userId, String username, String role) {
return Jwts.builder()
.setHeaderParam("typ", "JWT")
.setSubject(username)
.claim("userId", userId)
.claim("role", role)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE_TIME))
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
}
关键点:将用户角色信息直接编码到Token中,避免每次鉴权查库。设置30分钟过期时间,配合Refresh Token实现无感续期。
用户表采用密码哈希存储而非明文:
sql复制CREATE TABLE `user` (
`user_id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(50) UNIQUE NOT NULL,
`password_hash` VARCHAR(100) NOT NULL COMMENT 'BCrypt加密',
`salt` VARCHAR(50) NOT NULL,
`phone` VARCHAR(20) CHECK (phone REGEXP '^1[3-9]\\d{9}$')
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
避坑指南:
采用"主表+明细表"的分拆设计:
sql复制-- 订单主表
CREATE TABLE `order` (
`order_id` VARCHAR(32) PRIMARY KEY COMMENT '时间戳+随机数',
`user_id` BIGINT NOT NULL,
`total_amount` DECIMAL(12,2) UNSIGNED NOT NULL,
`status` ENUM('pending','paid','delivered','completed','cancelled') DEFAULT 'pending',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- 订单明细表
CREATE TABLE `order_detail` (
`detail_id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`order_id` VARCHAR(32) NOT NULL,
`dish_id` BIGINT NOT NULL,
`quantity` INT UNSIGNED DEFAULT 1,
`current_price` DECIMAL(10,2) UNSIGNED NOT NULL COMMENT '下单时价格快照',
FOREIGN KEY (`order_id`) REFERENCES `order`(`order_id`)
) ENGINE=InnoDB;
经验之谈:使用ENUM类型限定订单状态,比VARCHAR更规范。价格字段保存快照,避免菜品调价影响历史订单。
采用Redis Hash存储临时购物车数据:
java复制// 添加菜品到购物车
public void addToCart(Long userId, Long dishId, Integer quantity) {
String key = "cart:" + userId;
// 使用Lua脚本保证原子性
String script = "if redis.call('hexists', KEYS[1], ARGV[1]) == 1 then " +
"local newQty = tonumber(redis.call('hget', KEYS[1], ARGV[1])) + tonumber(ARGV[2]) " +
"return redis.call('hset', KEYS[1], ARGV[1], newQty) " +
"else return redis.call('hset', KEYS[1], ARGV[1], ARGV[2]) end";
redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Collections.singletonList(key),
dishId.toString(), quantity.toString()
);
}
性能优化点:
支付状态机设计:
mermaid复制stateDiagram-v2
[*] --> PENDING : 创建订单
PENDING --> PAID : 支付成功
PENDING --> CANCELLED : 用户取消
PAID --> DELIVERED : 商家接单
DELIVERED --> COMPLETED : 用户确认
DELIVERED --> CANCELLED : 超时未取
(注:实际实现时应使用代码状态机而非mermaid图)
使用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_DATABASE: food_order
volumes:
- mysql_data:/var/lib/mysql
ports:
- "3306:3306"
backend:
build: ./backend
depends_on:
- mysql
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/food_order
ports:
- "8080:8080"
volumes:
mysql_data:
配置Nginx反向代理解决跨域:
nginx复制server {
listen 80;
server_name yourdomain.com;
location /api {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
}
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
}
使用MySQL乐观锁解决:
java复制@Transactional
public Order createOrder(Long userId, List<CartItem> items) {
// 检查库存
items.forEach(item -> {
Dish dish = dishMapper.selectById(item.getDishId());
if (dish.getStock() < item.getQuantity()) {
throw new BusinessException("库存不足");
}
});
// 扣减库存(带版本号校验)
items.forEach(item -> {
int affected = dishMapper.reduceStockWithVersion(
item.getDishId(),
item.getQuantity(),
item.getVersion() // 获取购物车中的版本号
);
if (affected == 0) {
throw new ConcurrentUpdateException("库存变更冲突");
}
});
// 创建订单...
}
常见原因及解决方案:
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
connection-timeout: 30000
idle-timeout: 600000
这个项目经过三个月的迭代开发,已在本地餐饮店实际运行,日均处理订单200+。最大的收获是认识到:可靠的系统不是一蹴而就的,需要持续监控和调优。建议新手开发者重点关注订单状态的闭环管理和库存的一致性保证,这两个环节最容易出问题。