1. 项目背景与核心需求
私厨服务系统是近年来兴起的一种O2O餐饮服务模式,它连接了有烹饪技能的私厨和追求个性化餐饮体验的消费者。作为一名长期关注Node.js技术栈的全栈开发者,我发现这个领域存在几个关键痛点:
- 传统的外卖平台无法满足用户对个性化、定制化餐饮的需求
- 独立私厨缺乏稳定的线上获客渠道和技术支持
- 现有的解决方案大多基于PHP或Java,对中小型团队开发不够友好
这个毕业设计项目正是要解决这些问题。系统采用Node.js作为后端技术栈,主要基于以下几个考虑:
- 高并发处理能力:餐饮服务有明显的时段性高峰(如午餐、晚餐时间),Node.js的非阻塞I/O模型非常适合这种场景
- 快速迭代需求:毕业设计周期有限,需要选择开发效率高的技术栈
- 全栈JavaScript:前后端统一语言,降低学习成本
- 丰富的npm生态:可以快速集成支付、地图、消息推送等常见功能模块
提示:选择Node.js版本时,建议使用LTS版本(当前是18.x),避免使用最新的奇数版本,因为它们可能包含不稳定的特性。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 技术栈选型
整个系统采用MEVN架构(MongoDB + Express + Vue.js + Node.js),这是经过多次项目验证的可靠组合:
- 前端:Vue 3 + Vant UI(移动端组件库)
- 后端:Express 4.x + TypeScript
- 数据库:MongoDB Atlas(云数据库服务)
- 辅助工具:
- JWT认证
- Socket.IO实现实时通知
- Multer处理图片上传
- Mongoose进行数据建模
2.2 核心模块划分
系统主要包含以下功能模块:
| 模块名称 | 功能描述 | 技术实现要点 |
|---|---|---|
| 用户模块 | 注册/登录/个人信息管理 | JWT认证、bcrypt密码加密 |
| 私厨模块 | 厨师认证/菜单管理 | 文件上传、资质审核流程 |
| 订单模块 | 下单/支付/评价 | 微信支付集成、事务处理 |
| 消息模块 | 用户与厨师沟通 | WebSocket实时通信 |
| 推荐模块 | 个性化菜品推荐 | 基于用户行为的简单推荐算法 |
2.3 数据库设计
考虑到私厨服务的业务特点,我们设计了以下核心集合(Collections):
javascript复制// 用户模型
const UserSchema = new mongoose.Schema({
username: { type: String, unique: true },
password: String,
avatar: String,
role: { type: String, enum: ['user', 'chef', 'admin'] },
location: {
type: { type: String, default: 'Point' },
coordinates: [Number] // [经度, 纬度]
}
});
// 菜品模型
const DishSchema = new mongoose.Schema({
name: String,
price: Number,
images: [String],
chef: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
tags: [String],
description: String
});
注意:MongoDB从4.4版本开始支持多文档事务,这对订单处理等需要ACID特性的场景非常重要。
3. 关键功能实现
3.1 用户认证系统
采用JWT(JSON Web Token)实现无状态认证,这是目前Node.js项目的标准做法:
javascript复制// auth.controller.ts
const login = async (req: Request, res: Response) => {
const { username, password } = req.body;
const user = await User.findOne({ username });
if (!user) return res.status(404).send('用户不存在');
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) return res.status(401).send('密码错误');
const token = jwt.sign(
{ userId: user._id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
res.json({ token });
};
安全注意事项:
- 密码必须加盐哈希存储(使用bcrypt)
- JWT密钥要足够复杂且不提交到代码仓库
- 设置合理的token过期时间
- 敏感接口需要角色验证中间件
3.2 订单处理流程
订单模块是系统的核心,需要特别注意并发控制和事务处理:
javascript复制// order.service.ts
const createOrder = async (orderData) => {
const session = await mongoose.startSession();
session.startTransaction();
try {
// 1. 检查菜品库存
const dish = await Dish.findById(orderData.dishId).session(session);
if (dish.stock < orderData.quantity) {
throw new Error('库存不足');
}
// 2. 扣减库存
dish.stock -= orderData.quantity;
await dish.save({ session });
// 3. 创建订单
const order = new Order({
...orderData,
status: 'pending',
createdAt: new Date()
});
await order.save({ session });
// 4. 提交事务
await session.commitTransaction();
return order;
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
session.endSession();
}
};
3.3 实时通知系统
使用Socket.IO实现订单状态变化的实时推送:
javascript复制// socket.js
const io = require('socket.io')(server);
io.on('connection', (socket) => {
// 用户连接时绑定用户ID
socket.on('authenticate', (token) => {
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
socket.join(`user_${decoded.userId}`);
} catch (err) {
socket.disconnect();
}
});
// 订单状态更新时通知相关用户
Order.watch().on('change', (change) => {
if (change.operationType === 'update') {
const orderId = change.documentKey._id;
const userId = change.updateDescription.updatedFields.userId;
io.to(`user_${userId}`).emit('orderUpdate', {
orderId,
status: change.updateDescription.updatedFields.status
});
}
});
});
4. 开发环境搭建与常见问题
4.1 Node.js环境配置
这是大多数新手遇到的第一个坎。根据我的经验,Windows系统下最常见的问题是PowerShell执行策略限制:
bash复制# 以管理员身份运行PowerShell,然后执行:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
Mac/Linux用户推荐使用nvm管理Node版本:
bash复制curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
nvm install --lts
nvm use --lts
4.2 项目初始化与依赖安装
创建一个标准的Node.js项目结构:
code复制private-chef-system/
├── client/ # 前端代码
├── server/ # 后端代码
│ ├── src/
│ │ ├── controllers/
│ │ ├── models/
│ │ ├── routes/
│ │ └── app.ts
│ ├── package.json
│ └── tsconfig.json
├── .env # 环境变量
└── README.md
安装核心依赖:
bash复制cd server
npm init -y
npm install express mongoose jsonwebtoken bcryptjs socket.io cors dotenv
npm install -D typescript @types/node @types/express ts-node nodemon
4.3 常见错误与解决方案
-
MongoDB连接问题:
- 错误:
MongoNetworkError: failed to connect to server - 解决:检查MongoDB Atlas的白名单设置,确保当前IP被允许访问
- 错误:
-
跨域问题:
javascript复制// 在Express中启用CORS app.use(cors({ origin: ['http://localhost:8080'], credentials: true })); -
文件上传大小限制:
javascript复制// 调整默认的请求体大小限制 app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ limit: '10mb', extended: true }));
5. 项目部署与优化
5.1 生产环境部署
推荐使用PM2作为进程管理器:
bash复制npm install -g pm2
pm2 start dist/app.js --name "private-chef-api"
配置生态系统文件:
javascript复制// ecosystem.config.js
module.exports = {
apps: [{
name: 'private-chef-api',
script: 'dist/app.js',
instances: 'max',
autorestart: true,
watch: false,
env: {
NODE_ENV: 'production',
PORT: 3000,
MONGODB_URI: 'your_production_connection_string'
}
}]
};
5.2 性能优化建议
-
数据库索引优化:
javascript复制// 为常用查询字段添加索引 UserSchema.index({ username: 1 }, { unique: true }); DishSchema.index({ chef: 1, createdAt: -1 }); -
API响应缓存:
javascript复制const apicache = require('apicache'); const cache = apicache.middleware; // 缓存菜品列表接口5分钟 app.get('/api/dishes', cache('5 minutes'), dishController.listDishes); -
静态资源CDN:
将用户上传的菜品图片等静态资源托管到云存储服务(如阿里云OSS、AWS S3),减轻服务器负担。
5.3 监控与日志
使用Winston进行结构化日志记录:
javascript复制// logger.ts
import winston from 'winston';
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}
export default logger;
6. 毕业设计扩展建议
为了让项目更具竞争力,可以考虑以下扩展方向:
-
微信小程序集成:
- 使用Taro框架开发跨平台小程序
- 接入微信支付和地理位置API
-
推荐算法优化:
- 基于用户历史订单实现协同过滤推荐
- 考虑地理位置因素进行就近推荐
-
后台管理系统:
- 使用AdminJS快速搭建管理界面
- 实现数据统计和运营分析功能
-
压力测试:
- 使用Artillery进行负载测试
- 优化高并发场景下的性能表现
我在实际开发中发现,最大的挑战不是技术实现,而是业务逻辑的完备性。建议在开始编码前,先绘制完整的业务流程和状态转换图,这样可以避免后期大量的返工。
