主题
博客系统
在本章节中,我们将使用 Express 创建一个简单的博客系统。我们将覆盖从数据库设计、路由创建、文章发布、用户注册与登录、评论功能等多方面的内容。通过实践这一项目,您将对 Express 开发有更深入的了解,并学会如何处理实际项目中的常见功能需求。
1. 项目概述
本博客系统将包含以下基本功能:
- 用户身份验证:允许用户注册、登录和退出。
- 文章管理:支持用户发布、编辑、删除和查看文章。
- 评论功能:允许用户对文章进行评论。
- 前后端分离:前端可以通过 API 获取数据并展示。
2. 数据库设计
我们将使用 MongoDB 来存储数据,并通过 Mongoose 来操作数据库。博客系统的主要数据模型如下:
2.1 用户模型
用户模型包含以下字段:
username
: 用户名,唯一。email
: 用户邮箱,唯一。password
: 用户密码,哈希存储。
js
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
userSchema.methods.hashPassword = async function(password) {
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(password, salt);
};
userSchema.methods.comparePassword = async function(password) {
return bcrypt.compare(password, this.password);
};
const User = mongoose.model('User', userSchema);
module.exports = User;
2.2 文章模型
文章模型包含以下字段:
title
: 文章标题。content
: 文章内容。author
: 文章作者,引用用户模型。createdAt
: 创建时间。
js
const mongoose = require('mongoose');
const postSchema = new mongoose.Schema({
title: { type: String, required: true },
content: { type: String, required: true },
author: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
createdAt: { type: Date, default: Date.now },
});
const Post = mongoose.model('Post', postSchema);
module.exports = Post;
2.3 评论模型
评论模型包含以下字段:
post
: 关联文章。author
: 评论作者。content
: 评论内容。createdAt
: 创建时间。
js
const mongoose = require('mongoose');
const commentSchema = new mongoose.Schema({
post: { type: mongoose.Schema.Types.ObjectId, ref: 'Post', required: true },
author: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
content: { type: String, required: true },
createdAt: { type: Date, default: Date.now },
});
const Comment = mongoose.model('Comment', commentSchema);
module.exports = Comment;
3. 用户身份验证
我们将使用 JWT 来进行用户身份验证。当用户登录时,系统将生成一个 JWT 令牌,客户端将这个令牌保存在本地并用于后续请求的身份验证。
3.1 用户注册
用户注册时,需要提供用户名、邮箱和密码。密码将被哈希后存储在数据库中。
js
const express = require('express');
const bcrypt = require('bcrypt');
const User = require('../models/User');
const jwt = require('jsonwebtoken');
const router = express.Router();
router.post('/register', async (req, res) => {
const { username, email, password } = req.body;
try {
const user = new User({ username, email });
await user.hashPassword(password);
await user.save();
res.status(201).json({ message: 'User registered successfully' });
} catch (err) {
res.status(400).json({ message: 'Error registering user', error: err });
}
});
module.exports = router;
3.2 用户登录
用户登录时,我们将验证其邮箱和密码,若验证成功,生成 JWT 令牌并返回给客户端。
js
router.post('/login', async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.findOne({ email });
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
const isMatch = await user.comparePassword(password);
if (!isMatch) {
return res.status(400).json({ message: 'Invalid password' });
}
const token = jwt.sign({ userId: user._id }, 'secretkey', { expiresIn: '1h' });
res.json({ token });
} catch (err) {
res.status(500).json({ message: 'Error logging in', error: err });
}
});
3.3 验证 JWT 令牌
在需要身份验证的 API 路由中,使用 JWT 令牌进行身份验证。
js
const jwt = require('jsonwebtoken');
const authenticate = (req, res, next) => {
const token = req.header('Authorization');
if (!token) {
return res.status(401).json({ message: 'No token provided' });
}
try {
const decoded = jwt.verify(token, 'secretkey');
req.userId = decoded.userId;
next();
} catch (err) {
res.status(401).json({ message: 'Invalid token' });
}
};
module.exports = authenticate;
4. 文章功能
4.1 创建文章
用户可以创建文章,输入标题和内容后保存到数据库。
js
const Post = require('../models/Post');
router.post('/posts', authenticate, async (req, res) => {
const { title, content } = req.body;
try {
const post = new Post({
title,
content,
author: req.userId,
});
await post.save();
res.status(201).json({ message: 'Post created successfully', post });
} catch (err) {
res.status(500).json({ message: 'Error creating post', error: err });
}
});
4.2 获取所有文章
用户可以查看所有文章的列表。
js
router.get('/posts', async (req, res) => {
try {
const posts = await Post.find().populate('author', 'username').exec();
res.json(posts);
} catch (err) {
res.status(500).json({ message: 'Error fetching posts', error: err });
}
});
4.3 编辑文章
用户可以编辑自己发布的文章。
js
router.put('/posts/:id', authenticate, async (req, res) => {
const { title, content } = req.body;
try {
const post = await Post.findById(req.params.id);
if (!post) {
return res.status(404).json({ message: 'Post not found' });
}
if (post.author.toString() !== req.userId) {
return res.status(403).json({ message: 'Unauthorized' });
}
post.title = title || post.title;
post.content = content || post.content;
await post.save();
res.json({ message: 'Post updated successfully', post });
} catch (err) {
res.status(500).json({ message: 'Error updating post', error: err });
}
});
5. 评论功能
5.1 创建评论
用户可以对文章进行评论,评论将与文章关联。
js
const Comment = require('../models/Comment');
router.post('/posts/:postId/comments', authenticate, async (req, res) => {
const { content } = req.body;
try {
const post = await Post.findById(req.params.postId);
if (!post) {
return res.status(404).json({ message: 'Post not found' });
}
const comment = new Comment({
post: post._id,
author: req.userId,
content,
});
await comment.save();
res.status(201).json({ message: 'Comment added successfully', comment });
} catch (err) {
res.status(500).json({ message: 'Error adding comment', error: err });
}
});
5.2 获取评论
获取某篇文章下的所有评论。
js
router.get('/posts/:postId/comments', async (req, res) => {
try {
const comments = await Comment.find({ post: req.params.postId }).populate('author', 'username').exec();
res.json(comments);
} catch (err) {
res.status(500).json({ message: 'Error fetching comments', error: err });
}
});
6. 总结
通过本章节的
实现,您已经掌握了如何使用 Express 构建一个简单的博客系统。您学会了如何处理用户身份验证、文章发布、评论功能等常见需求,并了解了如何设计数据库模型和实现基本的 CRUD 操作。在此基础上,您可以扩展更多功能,如文章分类、搜索、分页等,进一步完善您的博客系统。