基于Vue3和Node.js的宠物用品购物系统设计与实现
一、项目描述
随着互联网技术的快速发展和宠物经济的持续升温,宠物用品电商平台已成为宠物主人购买宠物用品的主要渠道。设计并实现了一个基于Vue3和Node.js的全栈宠物用品购物系统,该系统采用前后端分离架构,包含用户购物系统和后台管理系统两个子系统。
系统前端采用Vue 3框架,结合TypeScript、Pinia状态管理、Vue Router路由管理和Element UI Plus组件库,实现了响应式的用户界面和流畅的交互体验。后端采用Node.js和Express框架,使用MongoDB作为数据库,通过JWT实现用户身份认证,构建了RESTful风格的API接口。系统实现了用户注册登录、商品浏览搜索、购物车管理、订单处理、社交互动、后台管理等核心功能。
1. 项目截图





















2. 技术栈
前端
- Vue 3 + TypeScript
- Vue Router 4 (路由管理)
- Pinia (状态管理)
- Element UI Plus (UI组件库)
- Axios (HTTP请求)
后端
- Node.js + Express (服务器框架)
- MongoDB + Mongoose (数据库)
- JWT (身份验证)
- Multer (文件上传)
- Bcryptjs (密码加密)
二、项目启动
前置要求
- Node.js >= 16
- pnpm >= 8
- MongoDB >= 5.0
1.安装依赖
bash
# 安装根目录依赖
pnpm install
2. 启动 MongoDB
确保 MongoDB 服务已启动并运行在 localhost:27017
3. 导入测试数据
arduino
pnpm run import
这将自动导入:
- ✅ 4个测试用户(1个管理员 + 3个普通用户)
- ✅ 完整的商品分类体系
- ✅ 10个示例商品
- ✅ 用户地址数据
- ✅ 订单数据
- ✅ 社交帖子数据
4. 启动开发服务器
arduino
pnpm run dev
启动后访问:
- 👤 用户系统:http://localhost:5173
- 🎛️ 管理系统:http://localhost:5174
- 🔗 后端API:http://localhost:3000
三、项目总体设计
1. 系统架构设计
1.1 架构模式选择
本系统采用前后端分离的架构模式,具有以下优势:
1. 职责分离
- 前端专注于用户界面和交互体验
- 后端专注于业务逻辑和数据处理
- 前后端可以独立开发、测试、部署
2. 技术独立
- 前端可以选择最适合的框架和技术
- 后端可以选择最适合的语言和框架
- 技术栈升级互不影响
3. 团队协作
- 前端团队和后端团队可以并行开发
- 通过API接口约定进行协作
- 提高开发效率
4. 可扩展性
- 前端和后端可以独立扩展
- 支持多端应用(Web、移动端、小程序)
- 便于向微服务架构演进
1.2 系统架构图
scss
┌─────────────────────────────────────────────────────────┐
│ 客户端层 │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 用户系统 │ │ 管理系统 │ │
│ │ (Vue 3) │ │ (Vue 3) │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
│
│ HTTP/HTTPS
│ RESTful API
▼
┌─────────────────────────────────────────────────────────┐
│ 服务端层 │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Express 应用服务器 │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 路由层 │ │ 中间件层 │ │ 控制器层 │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
│ Mongoose ODM
▼
┌─────────────────────────────────────────────────────────┐
│ 数据层 │
│ ┌──────────────────────────────────────────────────┐ │
│ │ MongoDB 数据库 │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 用户集合 │ │ 商品集合 │ │ 订单集合 │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
1.3技术架构
前端架构
scss
用户系统 / 管理系统
├── Vue 3 (核心框架)
├── TypeScript (类型系统)
├── Pinia (状态管理)
├── Vue Router (路由管理)
├── Element UI Plus (UI组件库)
├── Axios (HTTP客户端)
└── Vite (构建工具)
后端架构
scss
API服务器
├── Node.js (运行环境)
├── Express (Web框架)
├── MongoDB (数据库)
├── Mongoose (ODM)
├── JWT (身份认证)
├── Bcrypt (密码加密)
└── Multer (文件上传)
2. 系统功能模块设计
用户购物系统功能模块
markdown
用户购物系统
├── 用户管理模块
│ ├── 用户注册
│ ├── 用户登录
│ ├── 个人信息管理
│ └── 收货地址管理
├── 商品展示模块
│ ├── 首页展示
│ ├── 商品列表
│ ├── 商品详情
│ └── 商品搜索
├── 购物功能模块
│ ├── 购物车管理
│ ├── 订单创建
│ ├── 订单查询
│ └── 订单评价
└── 社交功能模块
├── 动态发布
├── 动态浏览
├── 点赞评论
└── 用户关注
后台管理系统功能模块
markdown
后台管理系统
├── 系统概览模块
│ ├── 数据统计
│ ├── 销售图表
│ └── 订单统计
├── 商品管理模块
│ ├── 商品列表
│ ├── 商品编辑
│ ├── 分类管理
│ └── 库存管理
├── 订单管理模块
│ ├── 订单列表
│ ├── 订单详情
│ ├── 发货处理
│ └── 退款处理
├── 用户管理模块
│ ├── 用户列表
│ ├── 用户详情
│ └── 用户状态管理
└── 数据统计模块
├── 销售统计
├── 商品排行
└── 用户分析
3. 数据库设计
系统主要包含以下实体:
- 用户(User) :存储用户基本信息和统计数据
- 商品(Product) :存储商品信息、价格、库存等
- 订单(Order) :存储订单详情、支付信息、物流状态
- 动态(Post) :存储用户发布的社交动态
- 评论(Comment) :存储动态评论信息
- 地址(Address) :存储用户收货地址
实体关系:
- 一个用户可以有多个订单(1:N)
- 一个订单包含多个商品(N:M)
- 一个用户可以发布多个动态(1:N)
- 一个动态可以有多个评论(1:N)
- 一个用户可以有多个收货地址(1:N)
四、用户认证模块设计
1. 功能流程图
用户注册流程:
用户填写信息 → 前端验证 → 发送注册请求 → 后端验证 → 密码加密 →
存入数据库 → 生成 Token → 返回用户信息和 Token → 前端存储 Token →
自动登录 → 跳转首页
用户登录流程:
用户输入账号密码 → 前端验证 → 发送登录请求 → 后端查询用户 →
验证密码 → 生成 Token → 返回用户信息和 Token → 前端存储 Token →
跳转首页
核心技术点:
- 密码加密(bcrypt)
bcrypt 是一种专门为密码存储设计的哈希算法,具有以下特点:
- 加盐(Salt) :自动生成随机盐值,防止彩虹表攻击
- 慢速哈希:计算速度慢,增加暴力破解难度
- 自适应:可调整计算复杂度,应对硬件性能提升
js
// 密码加密实现
import bcrypt from 'bcryptjs';
// 注册时加密密码
const hashPassword = async (password) => {
// 生成盐值,10 是成本因子(cost factor)
// 成本因子越高,计算越慢,安全性越高
const salt = await bcrypt.genSalt(10);
// 使用盐值加密密码
const hashedPassword = await bcrypt.hash(password, salt);
return hashedPassword;
};
// 登录时验证密码
const verifyPassword = async (inputPassword, storedPassword) => {
// bcrypt.compare 会自动提取盐值进行比较
const isMatch = await bcrypt.compare(inputPassword, storedPassword);
return isMatch;
};
为什么不使用 MD5 或 SHA?
- MD5 和 SHA 是快速哈希算法,容易被暴力破解
- 没有内置盐值机制,需要手动实现
- bcrypt 专为密码设计,更安全
2. JWT 身份认证
JWT(JSON Web Token)是一种无状态的身份认证方案,特别适合前后端分离架构。
JWT 结构:
json
JWT = Header.Payload.Signature
Header(头部):
{
"alg": "HS256", // 签名算法
"typ": "JWT" // Token 类型
}
Payload(载荷):
{
"userId": "64f8a1b2c3d4e5f6a7b8c9d0",
"username": "testuser",
"role": "user",
"iat": 1704067200, // 签发时间
"exp": 1704672000 // 过期时间
}
Signature(签名):
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
JWT 工作流程:
markdown
1. 用户登录成功
↓
2. 服务器生成 JWT Token
- 将用户信息编码到 Payload
- 使用密钥签名,防止篡改
↓
3. 返回 Token 给客户端
↓
4. 客户端存储 Token(localStorage 或 sessionStorage)
↓
5. 后续请求携带 Token
- 在 HTTP Header 中添加:Authorization: Bearer <token>
↓
6. 服务器验证 Token
- 验证签名是否有效
- 检查是否过期
- 提取用户信息
↓
7. 处理业务逻辑
JWT 实现代码:
js
import jwt from 'jsonwebtoken';
// 密钥(生产环境应使用环境变量)
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';
// 生成 Token
const generateToken = (user) => {
const payload = {
userId: user._id,
username: user.username,
role: user.role
};
// 签发 Token,设置 7 天过期
const token = jwt.sign(payload, JWT_SECRET, {
expiresIn: '7d'
});
return token;
};
// 验证 Token 中间件
const authenticateToken = async (req, res, next) => {
try {
// 从请求头获取 Token
const authHeader = req.headers.authorization;
const token = authHeader && authHeader.split(' ')[1]; // Bearer <token>
if (!token) {
return res.status(401).json({
success: false,
message: '访问令牌缺失'
});
}
// 验证 Token
const decoded = jwt.verify(token, JWT_SECRET);
// 查询用户是否存在且状态正常
const user = await User.findById(decoded.userId);
if (!user || user.status !== 'active') {
return res.status(401).json({
success: false,
message: '用户不存在或已被禁用'
});
}
// 将用户信息附加到请求对象
req.user = {
userId: decoded.userId,
username: decoded.username,
role: decoded.role
};
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({
success: false,
message: '令牌已过期,请重新登录'
});
}
return res.status(401).json({
success: false,
message: '无效的访问令牌'
});
}
};
JWT vs Session 对比:
| 特性 | JWT | Session |
|---|---|---|
| 存储位置 | 客户端 | 服务器 |
| 扩展性 | 好(无状态) | 差(需要共享 Session) |
| 性能 | 好(无需查询) | 一般(需要查询 Session) |
| 安全性 | 一般(Token 泄露风险) | 好(服务器控制) |
| 适用场景 | 前后端分离、微服务 | 传统 Web 应用 |
JWT 安全注意事项:
- 不要在 Payload 中存储敏感信息(密码、信用卡号等)
- 使用 HTTPS 传输,防止 Token 被窃取
- 设置合理的过期时间
- 实现 Token 刷新机制
- 考虑使用 Refresh Token 提升安全性