博客系统是Web开发中最经典的项目类型之一,它涵盖了内容管理、用户交互、数据存储等多个方面,是学习全栈开发的绝佳实践项目。
东巴文(db-w.cn) 认为:博客系统不仅是一个技术项目,更是一个内容平台。好的博客系统应该让作者专注于创作,让读者享受阅读。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>项目规划 - 东巴文</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
}
h1 {
color: #667eea;
margin-bottom: 20px;
}
h2 {
color: #764ba2;
margin: 30px 0 15px;
border-left: 4px solid #764ba2;
padding-left: 15px;
}
.goal-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
margin: 15px 0;
border-radius: 10px;
}
.goal-card h3 {
margin-bottom: 10px;
}
.info-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
.info-table th,
.info-table td {
padding: 12px;
text-align: left;
border: 1px solid #ddd;
}
.info-table th {
background: #667eea;
color: white;
}
</style>
</head>
<body>
<div class="container">
<h1>项目规划</h1>
<h2>项目目标</h2>
<div class="goal-card">
<h3>🎯 核心目标</h3>
<ul>
<li>实现文章的发布、编辑、删除功能</li>
<li>支持文章分类和标签管理</li>
<li>实现用户评论和互动功能</li>
<li>提供良好的阅读体验</li>
</ul>
</div>
<div class="goal-card">
<h3>🎯 次要目标</h3>
<ul>
<li>支持Markdown编辑</li>
<li>实现文章搜索功能</li>
<li>支持代码高亮显示</li>
<li>提供RSS订阅功能</li>
</ul>
</div>
<h2>技术选型</h2>
<table class="info-table">
<thead>
<tr>
<th>技术层</th>
<th>技术选择</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>前端</td>
<td>HTML5 + CSS3 + JavaScript</td>
<td>原生技术,易于理解和学习</td>
</tr>
<tr>
<td>后端</td>
<td>Node.js + Express</td>
<td>轻量级,适合中小型项目</td>
</tr>
<tr>
<td>数据库</td>
<td>MongoDB / SQLite</td>
<td>灵活的文档数据库或轻量级关系数据库</td>
</tr>
<tr>
<td>部署</td>
<td>云服务器 / Vercel</td>
<td>灵活的部署选项</td>
</tr>
</tbody>
</table>
<h2>项目范围</h2>
<ul>
<li><strong>用户角色:</strong> 管理员、作者、读者</li>
<li><strong>核心功能:</strong> 文章管理、用户管理、评论系统</li>
<li><strong>开发周期:</strong> 4-6周</li>
<li><strong>团队规模:</strong> 1-3人</li>
</ul>
<div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
<strong>东巴文提示:</strong>博客系统可以从简单开始,逐步增加功能。先实现核心的文章发布和展示功能,再考虑评论、搜索等高级功能。
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>需求分析 - 东巴文</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
}
h1 {
color: #667eea;
margin-bottom: 20px;
}
h2 {
color: #764ba2;
margin: 30px 0 15px;
border-left: 4px solid #764ba2;
padding-left: 15px;
}
.feature-list {
background: #f8f9fa;
padding: 20px;
border: 2px solid #ddd;
margin: 15px 0;
border-radius: 10px;
}
.feature-list h3 {
color: #667eea;
margin-bottom: 10px;
}
.feature-item {
background: white;
padding: 15px;
margin: 10px 0;
border-left: 4px solid #667eea;
}
.info-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
.info-table th,
.info-table td {
padding: 12px;
text-align: left;
border: 1px solid #ddd;
}
.info-table th {
background: #667eea;
color: white;
}
</style>
</head>
<body>
<div class="container">
<h1>需求分析</h1>
<h2>功能需求</h2>
<div class="feature-list">
<h3>📝 文章管理</h3>
<div class="feature-item">
<strong>功能:</strong>
<ul>
<li>创建、编辑、删除文章</li>
<li>文章分类和标签</li>
<li>文章封面图片</li>
<li>文章状态(草稿、发布)</li>
<li>文章浏览统计</li>
</ul>
</div>
</div>
<div class="feature-list">
<h3>👤 用户管理</h3>
<div class="feature-item">
<strong>功能:</strong>
<ul>
<li>用户注册和登录</li>
<li>用户资料管理</li>
<li>用户角色和权限</li>
<li>头像上传</li>
<li>密码找回</li>
</ul>
</div>
</div>
<div class="feature-list">
<h3>💬 评论系统</h3>
<div class="feature-item">
<strong>功能:</strong>
<ul>
<li>发表评论和回复</li>
<li>评论审核</li>
<li>评论点赞</li>
<li>评论举报</li>
<li>评论通知</li>
</ul>
</div>
</div>
<div class="feature-list">
<h3>🔍 搜索功能</h3>
<div class="feature-item">
<strong>功能:</strong>
<ul>
<li>全文搜索</li>
<li>按分类筛选</li>
<li>按标签筛选</li>
<li>按时间排序</li>
<li>搜索建议</li>
</ul>
</div>
</div>
<h2>非功能需求</h2>
<table class="info-table">
<thead>
<tr>
<th>需求类型</th>
<th>具体要求</th>
<th>优先级</th>
</tr>
</thead>
<tbody>
<tr>
<td>性能</td>
<td>页面加载时间 < 3秒</td>
<td>高</td>
</tr>
<tr>
<td>安全</td>
<td>防止XSS、CSRF攻击</td>
<td>高</td>
</tr>
<tr>
<td>可用性</td>
<td>响应式设计,支持移动端</td>
<td>高</td>
</tr>
<tr>
<td>可维护性</td>
<td>代码结构清晰,注释完善</td>
<td>中</td>
</tr>
<tr>
<td>可扩展性</td>
<td>支持插件和主题扩展</td>
<td>低</td>
</tr>
</tbody>
</table>
<div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
<strong>东巴文提示:</strong>需求分析要区分核心功能和扩展功能。优先实现核心功能,确保系统可用,再逐步添加高级功能。
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据库设计 - 东巴文</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
}
h1 {
color: #667eea;
margin-bottom: 20px;
}
h2 {
color: #764ba2;
margin: 30px 0 15px;
border-left: 4px solid #764ba2;
padding-left: 15px;
}
.db-schema {
background: #f8f9fa;
padding: 20px;
border: 2px solid #ddd;
margin: 15px 0;
border-radius: 10px;
}
.db-schema h3 {
color: #667eea;
margin-bottom: 10px;
}
.code-block {
background: #2d2d2d;
color: #f8f8f2;
padding: 15px;
border-radius: 5px;
overflow-x: auto;
margin: 10px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>数据库设计</h1>
<h2>数据模型</h2>
<div class="db-schema">
<h3>用户表(Users)</h3>
<div class="code-block">
<pre>
{
"_id": ObjectId,
"username": String, // 用户名
"email": String, // 邮箱
"password": String, // 密码(加密)
"avatar": String, // 头像URL
"role": String, // 角色(admin, author, reader)
"bio": String, // 个人简介
"created_at": Date, // 创建时间
"updated_at": Date // 更新时间
}
</pre>
</div>
</div>
<div class="db-schema">
<h3>文章表(Articles)</h3>
<div class="code-block">
<pre>
{
"_id": ObjectId,
"title": String, // 标题
"slug": String, // URL友好标题
"content": String, // 内容(Markdown)
"excerpt": String, // 摘要
"cover_image": String, // 封面图片
"author_id": ObjectId, // 作者ID
"category_id": ObjectId, // 分类ID
"tags": [String], // 标签数组
"status": String, // 状态(draft, published)
"view_count": Number, // 浏览次数
"like_count": Number, // 点赞次数
"comment_count": Number, // 评论次数
"created_at": Date, // 创建时间
"updated_at": Date, // 更新时间
"published_at": Date // 发布时间
}
</pre>
</div>
</div>
<div class="db-schema">
<h3>分类表(Categories)</h3>
<div class="code-block">
<pre>
{
"_id": ObjectId,
"name": String, // 分类名称
"slug": String, // URL友好名称
"description": String, // 分类描述
"parent_id": ObjectId, // 父分类ID(可选)
"created_at": Date, // 创建时间
"updated_at": Date // 更新时间
}
</pre>
</div>
</div>
<div class="db-schema">
<h3>评论表(Comments)</h3>
<div class="code-block">
<pre>
{
"_id": ObjectId,
"article_id": ObjectId, // 文章ID
"user_id": ObjectId, // 用户ID
"parent_id": ObjectId, // 父评论ID(可选)
"content": String, // 评论内容
"status": String, // 状态(pending, approved, rejected)
"like_count": Number, // 点赞次数
"created_at": Date, // 创建时间
"updated_at": Date // 更新时间
}
</pre>
</div>
</div>
<h2>索引设计</h2>
<ul>
<li><strong>用户表:</strong> username(唯一), email(唯一)</li>
<li><strong>文章表:</strong> slug(唯一), author_id, category_id, status, created_at</li>
<li><strong>评论表:</strong> article_id, user_id, status</li>
</ul>
<div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
<strong>东巴文提示:</strong>数据库设计要考虑查询效率和数据一致性。合理使用索引可以大幅提升查询性能,但过多的索引会影响写入性能。
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后端API设计 - 东巴文</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
}
h1 {
color: #667eea;
margin-bottom: 20px;
}
h2 {
color: #764ba2;
margin: 30px 0 15px;
border-left: 4px solid #764ba2;
padding-left: 15px;
}
.api-endpoint {
background: #f8f9fa;
padding: 20px;
border: 2px solid #ddd;
margin: 15px 0;
border-radius: 10px;
}
.api-endpoint h3 {
color: #667eea;
margin-bottom: 10px;
}
.code-block {
background: #2d2d2d;
color: #f8f8f2;
padding: 15px;
border-radius: 5px;
overflow-x: auto;
margin: 10px 0;
}
.method {
display: inline-block;
padding: 2px 8px;
border-radius: 3px;
font-weight: bold;
margin-right: 10px;
}
.get { background: #61affe; color: white; }
.post { background: #49cc90; color: white; }
.put { background: #fca130; color: white; }
.delete { background: #f93e3e; color: white; }
</style>
</head>
<body>
<div class="container">
<h1>后端API设计</h1>
<h2>RESTful API设计原则</h2>
<ul>
<li>使用名词而非动词</li>
<li>使用复数形式</li>
<li>使用HTTP方法表示操作</li>
<li>返回适当的状态码</li>
<li>支持过滤、排序、分页</li>
</ul>
<h2>文章API</h2>
<div class="api-endpoint">
<h3>获取文章列表</h3>
<div class="code-block">
<pre>
<span class="method get">GET</span> /api/articles
查询参数:
- page: 页码(默认1)
- limit: 每页数量(默认10)
- category: 分类ID
- tag: 标签名称
- status: 文章状态
- sort: 排序字段(默认created_at)
- order: 排序方式(asc/desc,默认desc)
响应示例:
{
"success": true,
"data": {
"articles": [...],
"pagination": {
"page": 1,
"limit": 10,
"total": 100,
"pages": 10
}
}
}
</pre>
</div>
</div>
<div class="api-endpoint">
<h3>创建文章</h3>
<div class="code-block">
<pre>
<span class="method post">POST</span> /api/articles
请求体:
{
"title": "文章标题",
"content": "文章内容(Markdown)",
"excerpt": "文章摘要",
"cover_image": "封面图片URL",
"category_id": "分类ID",
"tags": ["标签1", "标签2"],
"status": "published"
}
响应示例:
{
"success": true,
"data": {
"article": {
"_id": "文章ID",
"title": "文章标题",
...
}
}
}
</pre>
</div>
</div>
<div class="api-endpoint">
<h3>更新文章</h3>
<div class="code-block">
<pre>
<span class="method put">PUT</span> /api/articles/:id
请求体:
{
"title": "新标题",
"content": "新内容",
...
}
响应示例:
{
"success": true,
"data": {
"article": {
"_id": "文章ID",
"title": "新标题",
...
}
}
}
</pre>
</div>
</div>
<div class="api-endpoint">
<h3>删除文章</h3>
<div class="code-block">
<pre>
<span class="method delete">DELETE</span> /api/articles/:id
响应示例:
{
"success": true,
"message": "文章已删除"
}
</pre>
</div>
</div>
<h2>认证API</h2>
<div class="api-endpoint">
<h3>用户注册</h3>
<div class="code-block">
<pre>
<span class="method post">POST</span> /api/auth/register
请求体:
{
"username": "用户名",
"email": "邮箱",
"password": "密码"
}
响应示例:
{
"success": true,
"data": {
"user": {
"_id": "用户ID",
"username": "用户名",
"email": "邮箱"
},
"token": "JWT令牌"
}
}
</pre>
</div>
</div>
<div class="api-endpoint">
<h3>用户登录</h3>
<div class="code-block">
<pre>
<span class="method post">POST</span> /api/auth/login
请求体:
{
"email": "邮箱",
"password": "密码"
}
响应示例:
{
"success": true,
"data": {
"user": {
"_id": "用户ID",
"username": "用户名",
"email": "邮箱"
},
"token": "JWT令牌"
}
}
</pre>
</div>
</div>
<div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
<strong>东巴文提示:</strong>API设计要遵循RESTful原则,保持一致性和可预测性。使用合适的HTTP状态码和错误处理机制,让API易于使用和调试。
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>前端实现 - 东巴文</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
}
h1 {
color: #667eea;
margin-bottom: 20px;
}
h2 {
color: #764ba2;
margin: 30px 0 15px;
border-left: 4px solid #764ba2;
padding-left: 15px;
}
.frontend-demo {
background: #f8f9fa;
padding: 20px;
border: 2px solid #ddd;
margin: 15px 0;
border-radius: 10px;
}
.frontend-demo h3 {
color: #667eea;
margin-bottom: 10px;
}
.code-block {
background: #2d2d2d;
color: #f8f8f2;
padding: 15px;
border-radius: 5px;
overflow-x: auto;
margin: 10px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>前端实现</h1>
<h2>文章列表页面</h2>
<div class="frontend-demo">
<h3>HTML结构</h3>
<div class="code-block">
<pre>
<!-- 文章列表 -->
<div class="article-list">
<!-- 文章卡片 -->
<article class="article-card">
<img src="cover.jpg" alt="文章封面" class="article-cover">
<div class="article-content">
<h2 class="article-title">
<a href="/article/slug">文章标题</a>
</h2>
<p class="article-excerpt">文章摘要...</p>
<div class="article-meta">
<span class="author">作者名</span>
<span class="date">2024-01-01</span>
<span class="category">分类名</span>
</div>
<div class="article-tags">
<a href="/tag/javascript" class="tag">JavaScript</a>
<a href="/tag/html" class="tag">HTML</a>
</div>
</div>
</article>
</div>
<!-- 分页 -->
<div class="pagination">
<a href="?page=1" class="page-link">1</a>
<a href="?page=2" class="page-link">2</a>
<a href="?page=3" class="page-link">3</a>
</div>
</pre>
</div>
</div>
<h2>文章详情页面</h2>
<div class="frontend-demo">
<h3>HTML结构</h3>
<div class="code-block">
<pre>
<!-- 文章详情 -->
<article class="article-detail">
<header class="article-header">
<h1 class="article-title">文章标题</h1>
<div class="article-meta">
<img src="author-avatar.jpg" alt="作者头像" class="author-avatar">
<div class="author-info">
<span class="author-name">作者名</span>
<time class="publish-date">2024-01-01</time>
</div>
</div>
</header>
<div class="article-cover">
<img src="cover.jpg" alt="文章封面">
</div>
<div class="article-content">
<!-- Markdown渲染后的HTML内容 -->
</div>
<footer class="article-footer">
<div class="article-tags">
<a href="/tag/javascript" class="tag">JavaScript</a>
</div>
<div class="article-actions">
<button class="like-btn">点赞</button>
<button class="share-btn">分享</button>
</div>
</footer>
</article>
<!-- 评论区域 -->
<section class="comments-section">
<h2>评论</h2>
<!-- 评论表单 -->
<form class="comment-form">
<textarea name="content" placeholder="发表评论..."></textarea>
<button type="submit">提交评论</button>
</form>
<!-- 评论列表 -->
<div class="comment-list">
<!-- 评论项 -->
</div>
</section>
</pre>
</div>
</div>
<h2>Markdown编辑器</h2>
<div class="frontend-demo">
<h3>编辑器实现</h3>
<div class="code-block">
<pre>
<!-- Markdown编辑器 -->
<div class="markdown-editor">
<div class="editor-toolbar">
<button data-action="bold"><strong>B</strong></button>
<button data-action="italic"><em>I</em></button>
<button data-action="heading">H</button>
<button data-action="link">链接</button>
<button data-action="image">图片</button>
<button data-action="code">代码</button>
</div>
<div class="editor-container">
<textarea id="markdown-input" placeholder="输入Markdown内容..."></textarea>
<div id="markdown-preview"></div>
</div>
</div>
<script>
// 简单的Markdown渲染器
function renderMarkdown(markdown) {
// 标题
markdown = markdown.replace(/^### (.*$)/gim, '<h3>$1</h3>');
markdown = markdown.replace(/^## (.*$)/gim, '<h2>$1</h2>');
markdown = markdown.replace(/^# (.*$)/gim, '<h1>$1</h1>');
// 粗体和斜体
markdown = markdown.replace(/\*\*(.*?)\*\*/gim, '<strong>$1</strong>');
markdown = markdown.replace(/\*(.*?)\*/gim, '<em>$1</em>');
// 链接
markdown = markdown.replace(/\[([^\]]+)\]\(([^\)]+)\)/gim, '<a href="$2">$1</a>');
// 代码块
markdown = markdown.replace(/```([\s\S]*?)```/gim, '<pre><code>$1</code></pre>');
markdown = markdown.replace(/`([^`]+)`/gim, '<code>$1</code>');
// 段落
markdown = markdown.replace(/\n/gim, '<br>');
return markdown;
}
// 实时预览
const input = document.getElementById('markdown-input');
const preview = document.getElementById('markdown-preview');
input.addEventListener('input', function() {
preview.innerHTML = renderMarkdown(this.value);
});
</script>
</pre>
</div>
</div>
<div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
<strong>东巴文提示:</strong>前端实现要注重用户体验。使用合理的布局、清晰的视觉层次和流畅的交互,让用户专注于内容本身。
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户认证 - 东巴文</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
}
h1 {
color: #667eea;
margin-bottom: 20px;
}
h2 {
color: #764ba2;
margin: 30px 0 15px;
border-left: 4px solid #764ba2;
padding-left: 15px;
}
.auth-demo {
background: #f8f9fa;
padding: 20px;
border: 2px solid #ddd;
margin: 15px 0;
border-radius: 10px;
}
.auth-demo h3 {
color: #667eea;
margin-bottom: 10px;
}
.code-block {
background: #2d2d2d;
color: #f8f8f2;
padding: 15px;
border-radius: 5px;
overflow-x: auto;
margin: 10px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>用户认证</h1>
<h2>JWT认证机制</h2>
<div class="auth-demo">
<h3>JWT令牌结构</h3>
<div class="code-block">
<pre>
// JWT由三部分组成:Header.Payload.Signature
// Header
{
"alg": "HS256",
"typ": "JWT"
}
// Payload
{
"userId": "用户ID",
"username": "用户名",
"role": "用户角色",
"iat": 1234567890, // 签发时间
"exp": 1234571490 // 过期时间
}
// Signature
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
</pre>
</div>
</div>
<h2>登录表单</h2>
<div class="auth-demo">
<h3>HTML实现</h3>
<div class="code-block">
<pre>
<form id="login-form" class="auth-form">
<div class="form-group">
<label for="email">邮箱</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" id="password" name="password" required>
</div>
<div class="form-options">
<label>
<input type="checkbox" name="remember"> 记住我
</label>
<a href="/forgot-password" class="forgot-link">忘记密码?</a>
</div>
<button type="submit" class="btn-primary">登录</button>
</form>
<script>
document.getElementById('login-form').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = {
email: formData.get('email'),
password: formData.get('password')
};
try {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
// 存储JWT令牌
localStorage.setItem('token', result.data.token);
localStorage.setItem('user', JSON.stringify(result.data.user));
// 跳转到首页
window.location.href = '/';
} else {
alert(result.message);
}
} catch (error) {
console.error('登录失败:', error);
alert('登录失败,请重试');
}
});
</script>
</pre>
</div>
</div>
<h2>认证中间件</h2>
<div class="auth-demo">
<h3>后端验证</h3>
<div class="code-block">
<pre>
// 认证中间件
function authMiddleware(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({
success: false,
message: '未提供认证令牌'
});
}
try {
// 验证JWT令牌
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
return res.status(401).json({
success: false,
message: '无效的认证令牌'
});
}
}
// 使用中间件保护路由
app.get('/api/profile', authMiddleware, (req, res) => {
res.json({
success: true,
data: {
user: req.user
}
});
});
</pre>
</div>
</div>
<h2>权限控制</h2>
<div class="auth-demo">
<h3>角色权限中间件</h3>
<div class="code-block">
<pre>
// 角色权限中间件
function roleMiddleware(...allowedRoles) {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({
success: false,
message: '未认证'
});
}
if (!allowedRoles.includes(req.user.role)) {
return res.status(403).json({
success: false,
message: '权限不足'
});
}
next();
};
}
// 使用示例
app.delete('/api/articles/:id',
authMiddleware,
roleMiddleware('admin', 'author'),
deleteArticle
);
</pre>
</div>
</div>
<div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
<strong>东巴文提示:</strong>用户认证是安全的关键环节。使用HTTPS传输、加密存储密码、设置合理的令牌过期时间,确保系统安全。
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>评论系统 - 东巴文</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
}
h1 {
color: #667eea;
margin-bottom: 20px;
}
h2 {
color: #764ba2;
margin: 30px 0 15px;
border-left: 4px solid #764ba2;
padding-left: 15px;
}
.comment-demo {
background: #f8f9fa;
padding: 20px;
border: 2px solid #ddd;
margin: 15px 0;
border-radius: 10px;
}
.comment-demo h3 {
color: #667eea;
margin-bottom: 10px;
}
.code-block {
background: #2d2d2d;
color: #f8f8f2;
padding: 15px;
border-radius: 5px;
overflow-x: auto;
margin: 10px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>评论系统</h1>
<h2>评论列表</h2>
<div class="comment-demo">
<h3>HTML结构</h3>
<div class="code-block">
<pre>
<div class="comments-section">
<h2>评论 (3)</h2>
<!-- 评论表单 -->
<form class="comment-form">
<textarea name="content" placeholder="发表评论..." required></textarea>
<button type="submit">提交评论</button>
</form>
<!-- 评论列表 -->
<div class="comment-list">
<!-- 评论项 -->
<div class="comment-item">
<img src="avatar.jpg" alt="用户头像" class="comment-avatar">
<div class="comment-body">
<div class="comment-header">
<span class="comment-author">用户名</span>
<span class="comment-date">2024-01-01</span>
</div>
<p class="comment-content">评论内容...</p>
<div class="comment-actions">
<button class="like-btn">点赞 (5)</button>
<button class="reply-btn">回复</button>
</div>
<!-- 回复列表 -->
<div class="reply-list">
<div class="comment-item reply">
<!-- 回复内容 -->
</div>
</div>
</div>
</div>
</div>
</div>
</pre>
</div>
</div>
<h2>评论提交</h2>
<div class="comment-demo">
<h3>JavaScript实现</h3>
<div class="code-block">
<pre>
// 提交评论
async function submitComment(articleId, content, parentId = null) {
const token = localStorage.getItem('token');
if (!token) {
alert('请先登录');
return;
}
try {
const response = await fetch('/api/comments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
article_id: articleId,
content: content,
parent_id: parentId
})
});
const result = await response.json();
if (result.success) {
// 重新加载评论列表
loadComments(articleId);
// 清空表单
document.querySelector('.comment-form textarea').value = '';
} else {
alert(result.message);
}
} catch (error) {
console.error('提交评论失败:', error);
alert('提交评论失败,请重试');
}
}
// 加载评论列表
async function loadComments(articleId) {
try {
const response = await fetch(`/api/comments?article_id=${articleId}`);
const result = await response.json();
if (result.success) {
renderComments(result.data.comments);
}
} catch (error) {
console.error('加载评论失败:', error);
}
}
// 渲染评论列表
function renderComments(comments) {
const commentList = document.querySelector('.comment-list');
commentList.innerHTML = comments.map(comment => `
<div class="comment-item">
<img src="${comment.user.avatar}" alt="头像" class="comment-avatar">
<div class="comment-body">
<div class="comment-header">
<span class="comment-author">${comment.user.username}</span>
<span class="comment-date">${formatDate(comment.created_at)}</span>
</div>
<p class="comment-content">${comment.content}</p>
<div class="comment-actions">
<button class="like-btn" onclick="likeComment('${comment._id}')">
点赞 (${comment.like_count})
</button>
<button class="reply-btn" onclick="showReplyForm('${comment._id}')">
回复
</button>
</div>
</div>
</div>
`).join('');
}
</pre>
</div>
</div>
<h2>评论审核</h2>
<div class="comment-demo">
<h3>审核流程</h3>
<div class="code-block">
<pre>
// 后端评论审核
app.post('/api/comments', authMiddleware, async (req, res) => {
const { article_id, content, parent_id } = req.body;
// 内容过滤
const filteredContent = filterSensitiveWords(content);
// 创建评论
const comment = await Comment.create({
article_id,
user_id: req.user.id,
content: filteredContent,
parent_id,
status: 'pending' // 待审核状态
});
// 发送通知给管理员
notifyAdmin('new_comment', comment);
res.json({
success: true,
message: '评论已提交,等待审核'
});
});
// 管理员审核评论
app.put('/api/admin/comments/:id/approve',
authMiddleware,
roleMiddleware('admin'),
async (req, res) => {
await Comment.findByIdAndUpdate(req.params.id, {
status: 'approved'
});
res.json({
success: true,
message: '评论已通过'
});
}
);
</pre>
</div>
</div>
<div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
<strong>东巴文提示:</strong>评论系统要平衡开放性和安全性。提供便捷的评论功能,同时防止垃圾信息和恶意内容。合理的审核机制是必要的。
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>搜索功能 - 东巴文</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
}
h1 {
color: #667eea;
margin-bottom: 20px;
}
h2 {
color: #764ba2;
margin: 30px 0 15px;
border-left: 4px solid #764ba2;
padding-left: 15px;
}
.search-demo {
background: #f8f9fa;
padding: 20px;
border: 2px solid #ddd;
margin: 15px 0;
border-radius: 10px;
}
.search-demo h3 {
color: #667eea;
margin-bottom: 10px;
}
.code-block {
background: #2d2d2d;
color: #f8f8f2;
padding: 15px;
border-radius: 5px;
overflow-x: auto;
margin: 10px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>搜索功能</h1>
<h2>搜索界面</h2>
<div class="search-demo">
<h3>HTML结构</h3>
<div class="code-block">
<pre>
<!-- 搜索框 -->
<div class="search-container">
<form class="search-form">
<input type="text"
id="search-input"
placeholder="搜索文章..."
autocomplete="off">
<button type="submit">搜索</button>
</form>
<!-- 搜索建议 -->
<div id="search-suggestions" class="search-suggestions">
<!-- 动态生成 -->
</div>
</div>
<!-- 搜索结果 -->
<div class="search-results">
<div class="search-info">
找到 <span id="result-count">0</span> 个结果
</div>
<div id="results-container">
<!-- 动态生成 -->
</div>
</div>
</pre>
</div>
</div>
<h2>实时搜索</h2>
<div class="search-demo">
<h3>JavaScript实现</h3>
<div class="code-block">
<pre>
// 防抖函数
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// 搜索建议
const searchInput = document.getElementById('search-input');
const suggestionsContainer = document.getElementById('search-suggestions');
const showSuggestions = debounce(async (query) => {
if (query.length < 2) {
suggestionsContainer.style.display = 'none';
return;
}
try {
const response = await fetch(`/api/search/suggestions?q=${encodeURIComponent(query)}`);
const result = await response.json();
if (result.success && result.data.suggestions.length > 0) {
suggestionsContainer.innerHTML = result.data.suggestions.map(item => `
<div class="suggestion-item" onclick="selectSuggestion('${item.title}')">
<span class="suggestion-title">${highlightMatch(item.title, query)}</span>
<span class="suggestion-category">${item.category}</span>
</div>
`).join('');
suggestionsContainer.style.display = 'block';
} else {
suggestionsContainer.style.display = 'none';
}
} catch (error) {
console.error('搜索建议失败:', error);
}
}, 300);
searchInput.addEventListener('input', (e) => {
showSuggestions(e.target.value);
});
// 高亮匹配文本
function highlightMatch(text, query) {
const regex = new RegExp(`(${query})`, 'gi');
return text.replace(regex, '<mark>$1</mark>');
}
// 选择建议
function selectSuggestion(title) {
searchInput.value = title;
suggestionsContainer.style.display = 'none';
performSearch(title);
}
</pre>
</div>
</div>
<h2>后端搜索</h2>
<div class="search-demo">
<h3>全文搜索实现</h3>
<div class="code-block">
<pre>
// MongoDB全文搜索
app.get('/api/search', async (req, res) => {
const { q, category, tag, sort, page = 1, limit = 10 } = req.query;
try {
// 构建查询条件
let query = { status: 'published' };
if (q) {
// 全文搜索
query.$text = { $search: q };
}
if (category) {
query.category_id = category;
}
if (tag) {
query.tags = tag;
}
// 排序选项
let sortOption = { created_at: -1 };
if (sort === 'popular') {
sortOption = { view_count: -1 };
} else if (sort === 'likes') {
sortOption = { like_count: -1 };
}
// 执行查询
const articles = await Article.find(query)
.sort(sortOption)
.skip((page - 1) * limit)
.limit(parseInt(limit))
.populate('author_id', 'username avatar')
.populate('category_id', 'name');
// 总数
const total = await Article.countDocuments(query);
res.json({
success: true,
data: {
articles,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
total,
pages: Math.ceil(total / limit)
}
}
});
} catch (error) {
res.status(500).json({
success: false,
message: '搜索失败'
});
}
});
</pre>
</div>
</div>
<h2>高级搜索</h2>
<div class="search-demo">
<h3>多条件搜索</h3>
<div class="code-block">
<pre>
// 高级搜索表单
<form class="advanced-search">
<div class="search-row">
<input type="text" name="keyword" placeholder="关键词">
</div>
<div class="search-row">
<select name="category">
<option value="">所有分类</option>
<option value="tech">技术</option>
<option value="life">生活</option>
</select>
<select name="date_range">
<option value="">所有时间</option>
<option value="week">最近一周</option>
<option value="month">最近一月</option>
<option value="year">最近一年</option>
</select>
<select name="sort">
<option value="date">按时间排序</option>
<option value="popular">按热度排序</option>
<option value="likes">按点赞排序</option>
</select>
</div>
<button type="submit">搜索</button>
</form>
</pre>
</div>
</div>
<div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
<strong>东巴文提示:</strong>搜索功能是内容型网站的核心功能。提供实时搜索建议、多条件筛选和排序选项,帮助用户快速找到所需内容。
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>部署与维护 - 东巴文</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
}
h1 {
color: #667eea;
margin-bottom: 20px;
}
h2 {
color: #764ba2;
margin: 30px 0 15px;
border-left: 4px solid #764ba2;
padding-left: 15px;
}
.deployment-card {
background: #d4edda;
border: 2px solid #28a745;
padding: 20px;
margin: 15px 0;
border-radius: 10px;
}
.deployment-card h3 {
color: #155724;
margin-bottom: 10px;
}
.code-block {
background: #2d2d2d;
color: #f8f8f2;
padding: 15px;
border-radius: 5px;
overflow-x: auto;
margin: 10px 0;
}
.info-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
.info-table th,
.info-table td {
padding: 12px;
text-align: left;
border: 1px solid #ddd;
}
.info-table th {
background: #667eea;
color: white;
}
</style>
</head>
<body>
<div class="container">
<h1>部署与维护</h1>
<h2>部署选项</h2>
<table class="info-table">
<thead>
<tr>
<th>部署方式</th>
<th>优点</th>
<th>缺点</th>
</tr>
</thead>
<tbody>
<tr>
<td>云服务器(VPS)</td>
<td>完全控制,灵活配置</td>
<td>需要运维知识,成本较高</td>
</tr>
<tr>
<td>PaaS平台</td>
<td>简单快捷,自动扩展</td>
<td>限制较多,成本随使用增长</td>
</tr>
<tr>
<td>容器化部署</td>
<td>环境一致,易于迁移</td>
<td>学习曲线陡峭</td>
</tr>
<tr>
<td>Serverless</td>
<td>按需付费,自动扩展</td>
<td>冷启动延迟,调试困难</td>
</tr>
</tbody>
</table>
<h2>服务器部署</h2>
<div class="deployment-card">
<h3>Node.js应用部署</h3>
<div class="code-block">
<pre>
# 1. 安装Node.js和npm
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
# 2. 安装PM2进程管理器
sudo npm install -g pm2
# 3. 克隆项目代码
git clone https://github.com/username/blog.git
cd blog
# 4. 安装依赖
npm install --production
# 5. 配置环境变量
cp .env.example .env
nano .env # 编辑配置文件
# 6. 启动应用
pm2 start ecosystem.config.js
# 7. 设置开机自启
pm2 startup
pm2 save
# 8. 配置Nginx反向代理
sudo nano /etc/nginx/sites-available/blog
</pre>
</div>
</div>
<h2>Nginx配置</h2>
<div class="deployment-card">
<h3>反向代理配置</h3>
<div class="code-block">
<pre>
server {
listen 80;
server_name example.com www.example.com;
# 重定向到HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# SSL证书配置
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL优化配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 静态文件缓存
location /static/ {
alias /var/www/blog/public/;
expires 30d;
add_header Cache-Control "public, immutable";
}
# API代理
location /api/ {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
# 前端路由
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
</pre>
</div>
</div>
<h2>数据库备份</h2>
<div class="deployment-card">
<h3>自动备份脚本</h3>
<div class="code-block">
<pre>
#!/bin/bash
# MongoDB备份脚本
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/var/backups/mongodb"
DB_NAME="blog"
# 创建备份目录
mkdir -p $BACKUP_DIR
# 执行备份
mongodump --db $DB_NAME --out $BACKUP_DIR/$DATE
# 压缩备份文件
tar -czf $BACKUP_DIR/$DATE.tar.gz -C $BACKUP_DIR $DATE
# 删除原始备份目录
rm -rf $BACKUP_DIR/$DATE
# 删除30天前的备份
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete
echo "备份完成: $DATE.tar.gz"
</pre>
</div>
</div>
<h2>监控与日志</h2>
<div class="deployment-card">
<h3>应用监控</h3>
<ul>
<li><strong>PM2监控:</strong> pm2 monit</li>
<li><strong>日志管理:</strong> pm2 logs</li>
<li><strong>性能监控:</strong> New Relic, Datadog</li>
<li><strong>错误追踪:</strong> Sentry</li>
<li><strong>正常运行时间:</strong> UptimeRobot</li>
</ul>
</div>
<h2>维护清单</h2>
<ul>
<li>✅ 定期更新依赖包</li>
<li>✅ 监控服务器资源使用</li>
<li>✅ 定期备份数据库</li>
<li>✅ 检查安全日志</li>
<li>✅ 更新SSL证书</li>
<li>✅ 清理日志文件</li>
<li>✅ 监控应用性能</li>
<li>✅ 定期安全审计</li>
</ul>
<div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin-top: 20px;">
<strong>东巴文提示:</strong>部署不是终点,而是新的起点。建立完善的监控和备份机制,定期维护和更新,确保系统稳定运行。
</div>
</div>
</body>
</html>
东巴文(db-w.cn) 提醒:博客系统是学习Web开发的最佳实践项目。从简单开始,逐步增加功能,在实践中学习和成长。记住,好的博客系统应该让内容创作变得简单愉快。