1. 项目概述
作为一名长期从事校园信息化建设的开发者,我最近完成了一个基于Python和UniApp的微信小程序食堂点餐系统。这个项目源于学校食堂的实际需求——每到用餐高峰期,排队点餐的队伍总是让人望而生畏。通过这个小程序,学生和教职工可以直接在手机上完成点餐和支付,大大减少了排队时间。
系统采用前后端分离架构,前端使用UniApp框架开发微信小程序,后端基于Python的Flask框架构建RESTful API。数据库选用MySQL存储菜品信息、用户数据和订单记录。整个开发周期约3个月,目前已在校内两个食堂试点运行,平均点餐时间从原来的5-8分钟缩短至1分钟以内。
2. 技术选型与架构设计
2.1 前端技术栈
选择UniApp作为前端框架主要基于以下几点考虑:
- 跨平台能力:UniApp使用Vue.js语法,一套代码可编译到微信小程序、H5等多端。我们实测从微信小程序迁移到支付宝小程序只需调整少量API调用。
- 开发效率:相比原生小程序开发,UniApp的组件化开发模式使我们的前端开发速度提升了约40%。
- 社区支持:丰富的插件市场提供了现成的UI组件(如uView),特别适合快速开发餐饮类应用。
核心组件包括:
- 自定义菜品卡片组件
- 购物车浮动面板
- 订单状态进度条
- 微信支付SDK封装
2.2 后端技术栈
后端选用Flask而非Django的主要原因是:
- 轻量灵活:食堂点餐系统的业务逻辑相对简单,Flask的微内核设计更符合需求
- 扩展性强:通过Flask-RESTful扩展可以快速构建API,实测单个接口响应时间<200ms
- 部署便捷:配合Gunicorn+Nginx,单台2核4G服务器可支撑300+并发请求
关键后端模块:
python复制# 示例:订单创建API
@app.route('/api/order', methods=['POST'])
@jwt_required()
def create_order():
data = request.get_json()
# 验证库存
for item in data['items']:
dish = Dish.query.get(item['dish_id'])
if dish.stock < item['quantity']:
return {'message': f'{dish.name}库存不足'}, 400
# 创建订单
new_order = Order(
user_id=get_jwt_identity(),
total_amount=calculate_total(data['items']),
status='待支付'
)
db.session.add(new_order)
db.session.commit()
# 扣减库存
for item in data['items']:
dish = Dish.query.get(item['dish_id'])
dish.stock -= item['quantity']
OrderItem(
order_id=new_order.id,
dish_id=item['dish_id'],
quantity=item['quantity'],
price=dish.price
).save()
db.session.commit()
return {'order_id': new_order.id}, 201
2.3 数据库设计
MySQL表结构设计要点:
- 冗余设计:订单明细中存储菜品快照信息,避免菜品信息变更影响历史订单
- 索引优化:在user_id、created_at等高频查询字段建立组合索引
- 分表策略:订单表按月分表,防止单表数据过大
主要表结构:
sql复制CREATE TABLE `dishes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`price` decimal(10,2) NOT NULL,
`category_id` int(11) NOT NULL,
`image_url` varchar(255) DEFAULT NULL,
`stock` int(11) DEFAULT '0',
`is_active` tinyint(1) DEFAULT '1',
PRIMARY KEY (`id`),
KEY `idx_category` (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 核心功能实现
3.1 微信登录与认证
采用微信官方登录流程:
- 前端调用wx.login获取code
- 将code发送到后端换取openid
- 后端生成JWT token返回给前端
安全注意事项:
- 必须验证code有效性,防止伪造请求
- JWT token设置合理过期时间(我们设为7天)
- 敏感接口需验证token有效性
3.2 购物车实现
关键技术点:
- 本地存储:使用uniapp的uni.setStorageSync在客户端暂存购物车数据
- 合并策略:同一菜品多次添加时合并数量而非新增记录
- 实时计算:使用computed属性自动计算总金额
示例代码:
javascript复制// 购物车逻辑
export default {
data() {
return {
cartItems: []
}
},
computed: {
totalAmount() {
return this.cartItems.reduce((sum, item) => {
return sum + (item.price * item.quantity)
}, 0)
}
},
methods: {
addToCart(dish) {
const existItem = this.cartItems.find(i => i.id === dish.id)
if (existItem) {
existItem.quantity++
} else {
this.cartItems.push({
...dish,
quantity: 1
})
}
uni.setStorageSync('cart', this.cartItems)
}
}
}
3.3 微信支付集成
支付流程实现要点:
- 后端生成商户订单号(需保证唯一性)
- 调用微信支付统一下单接口获取prepay_id
- 返回支付参数给前端调起支付
- 处理异步支付结果通知
避坑经验:
- 订单号建议采用"时间戳+随机数"组合
- 必须验证支付结果通知的签名
- 设置合理的订单超时时间(我们设为30分钟)
4. 性能优化实践
4.1 前端优化措施
- 图片懒加载:菜品图片使用uniapp的lazy-load特性
- 数据分页:历史订单列表采用分页加载
- 缓存策略:菜品分类数据本地缓存24小时
- 组件复用:公共组件如星级评分全局注册
4.2 后端优化方案
- 数据库连接池:使用SQLAlchemy的连接池配置
- 查询优化:N+1查询问题通过joinedload解决
- 缓存应用:热门菜品数据Redis缓存
- 异步任务:支付结果通知处理使用Celery异步队列
5. 部署与运维
5.1 服务器配置
推荐配置:
- 前端:静态资源部署到CDN
- 后端:2核4G云服务器(实测可支撑2000+日订单)
- 数据库:MySQL 5.7+,建议单独服务器部署
5.2 监控方案
必备监控项:
- 接口响应时间(使用Prometheus监控)
- 数据库连接数监控
- 支付失败率告警
- 库存预警机制
6. 实际运行效果
上线三个月后的数据统计:
- 用户注册率:食堂就餐人员的78%
- 日均订单量:1200+
- 平均点餐时间:45秒
- 支付成功率:98.3%
- 食堂排队时间减少65%
7. 常见问题与解决方案
7.1 支付回调失败
现象:支付成功后订单状态未更新
排查:
- 检查微信支付配置的回调地址是否可外网访问
- 验证签名算法是否正确
- 查看Nginx日志是否有拦截POST请求
解决方案:
python复制# 确保路由允许POST方法
@app.route('/api/payment/notify', methods=['POST'])
def payment_notify():
# 验证签名
if not verify_signature(request.data):
return 'FAIL'
# 处理业务逻辑
update_order_status(request.data['out_trade_no'])
return 'SUCCESS'
7.2 高并发下库存超卖
现象:热门菜品出现超卖情况
解决方案:
- 使用数据库悲观锁
python复制# 查询时加锁
dish = Dish.query.with_for_update().get(dish_id)
if dish.stock >= quantity:
dish.stock -= quantity
db.session.commit()
- 引入Redis分布式锁
- 前端限制最大购买数量
8. 项目扩展方向
- 智能推荐:基于用户历史订单推荐菜品
- 预约取餐:分时段预约减少集中取餐压力
- 营养分析:展示菜品营养成分表
- 多食堂支持:扩展为校园食堂聚合平台
开发这个系统的过程中,最大的收获是理解了如何平衡技术先进性与实际业务需求。比如最初我们计划使用GraphQL API,但考虑到食堂工作人员的技术接受度,最终选择了更传统的RESTful API。在实际运营中,这种务实的选择往往比追求技术时髦更重要。