323 lines
8.1 KiB
Plaintext
323 lines
8.1 KiB
Plaintext
### 灵猴社博客系统 - 后端详细设计(Go + MySQL)
|
||
版本:1.0
|
||
日期:2025-07-15
|
||
|
||
---
|
||
|
||
#### **1. 技术栈**
|
||
- **语言**: Go 1.21+
|
||
- **Web框架**: Gin
|
||
- **ORM**: GORM
|
||
- **数据库**: MySQL 8.0+
|
||
- **Markdown处理**: goldmark (支持扩展)
|
||
- **认证**: JWT
|
||
- **缓存**: Redis (可选)
|
||
- **部署**: Docker
|
||
|
||
---
|
||
|
||
#### **2. 数据库设计**
|
||
```sql
|
||
-- 用户表
|
||
CREATE TABLE users (
|
||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||
username VARCHAR(50) UNIQUE NOT NULL,
|
||
email VARCHAR(100) UNIQUE NOT NULL,
|
||
password_hash CHAR(60) NOT NULL, -- bcrypt加密
|
||
role ENUM('user', 'admin') DEFAULT 'user',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
-- 文章表
|
||
CREATE TABLE articles (
|
||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||
user_id INT NOT NULL,
|
||
title VARCHAR(200) NOT NULL,
|
||
slug VARCHAR(200) UNIQUE NOT NULL, -- SEO友好URL
|
||
markdown_content LONGTEXT NOT NULL,
|
||
html_content LONGTEXT NOT NULL, -- 渲染后的HTML
|
||
status ENUM('draft', 'published', 'private') DEFAULT 'draft',
|
||
published_at DATETIME,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||
);
|
||
|
||
-- 标签表 (多对多关系)
|
||
CREATE TABLE tags (
|
||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||
name VARCHAR(50) UNIQUE NOT NULL
|
||
);
|
||
|
||
-- 文章标签关联表
|
||
CREATE TABLE article_tags (
|
||
article_id INT NOT NULL,
|
||
tag_id INT NOT NULL,
|
||
PRIMARY KEY (article_id, tag_id),
|
||
FOREIGN KEY (article_id) REFERENCES articles(id) ON DELETE CASCADE,
|
||
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
|
||
);
|
||
|
||
-- 文章版本历史表
|
||
CREATE TABLE article_versions (
|
||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||
article_id INT NOT NULL,
|
||
markdown_content LONGTEXT NOT NULL,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (article_id) REFERENCES articles(id) ON DELETE CASCADE
|
||
);
|
||
|
||
-- 评论表
|
||
CREATE TABLE comments (
|
||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||
article_id INT NOT NULL,
|
||
user_id INT NOT NULL,
|
||
markdown_content TEXT NOT NULL,
|
||
html_content TEXT NOT NULL,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (article_id) REFERENCES articles(id) ON DELETE CASCADE,
|
||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||
);
|
||
|
||
-- 媒体资源表
|
||
CREATE TABLE media (
|
||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||
user_id INT NOT NULL,
|
||
filename VARCHAR(255) NOT NULL,
|
||
url VARCHAR(512) NOT NULL, -- CDN地址
|
||
mime_type VARCHAR(50) NOT NULL,
|
||
size BIGINT NOT NULL,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
#### **3. 核心模块设计**
|
||
##### **3.1 用户管理模块**
|
||
```go
|
||
// models/user.go
|
||
type User struct {
|
||
gorm.Model
|
||
Username string `gorm:"uniqueIndex"`
|
||
Email string `gorm:"uniqueIndex"`
|
||
PasswordHash string
|
||
Role string
|
||
}
|
||
|
||
// handlers/auth.go
|
||
func Register(c *gin.Context) {
|
||
// 验证邮箱/密码格式
|
||
// 密码bcrypt加密
|
||
// 生成JWT token
|
||
}
|
||
|
||
func Login(c *gin.Context) {
|
||
// 校验密码
|
||
// 生成JWT (包含用户ID和角色)
|
||
}
|
||
|
||
// middleware/auth.go
|
||
func AuthMiddleware() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
// 验证JWT并注入用户信息到Context
|
||
}
|
||
}
|
||
```
|
||
|
||
##### **3.2 Markdown处理模块**
|
||
```go
|
||
// services/markdown.go
|
||
func RenderMarkdown(content string) string {
|
||
md := goldmark.New(
|
||
goldmark.WithExtensions(extension.GFM), // GitHub Flavored Markdown
|
||
goldmark.WithExtensions(extension.Footnote),
|
||
goldmark.WithParserOptions(parser.WithAutoHeadingID()),
|
||
)
|
||
var buf bytes.Buffer
|
||
md.Convert([]byte(content), &buf)
|
||
return sanitizeHTML(buf.String()) // XSS过滤
|
||
}
|
||
|
||
// 支持扩展渲染
|
||
func RenderWithExtensions(content string) string {
|
||
// 保留LaTeX公式: $$...$$
|
||
// 保留Mermaid代码块: ```mermaid
|
||
// 前端通过额外JS库渲染
|
||
}
|
||
```
|
||
|
||
##### **3.3 文章管理模块**
|
||
```go
|
||
// models/article.go
|
||
type Article struct {
|
||
gorm.Model
|
||
UserID uint
|
||
Title string
|
||
Slug string `gorm:"uniqueIndex"`
|
||
MarkdownContent string
|
||
HTMLContent string
|
||
Status string
|
||
PublishedAt *time.Time
|
||
Tags []Tag `gorm:"many2many:article_tags;"`
|
||
}
|
||
|
||
// handlers/article.go
|
||
func CreateArticle(c *gin.Context) {
|
||
// 自动生成slug (如: "hello-world")
|
||
// 渲染Markdown为HTML
|
||
// 处理标签(新建或关联)
|
||
// 创建初始版本记录
|
||
}
|
||
|
||
func UpdateArticle(c *gin.Context) {
|
||
// 保存新版本到article_versions
|
||
// 定时发布逻辑:
|
||
if article.PublishedAt.After(time.Now()) {
|
||
go schedulePublish(article.ID, article.PublishedAt)
|
||
}
|
||
}
|
||
|
||
// 定时发布任务
|
||
func schedulePublish(articleID uint, publishTime time.Time) {
|
||
duration := time.Until(publishTime)
|
||
time.AfterFunc(duration, func() {
|
||
db.Model(&Article{}).Where("id=?", articleID).Update("status", "published")
|
||
})
|
||
}
|
||
```
|
||
|
||
##### **3.4 媒体上传模块**
|
||
```go
|
||
// handlers/media.go
|
||
func UploadMedia(c *gin.Context) {
|
||
file, _ := c.FormFile("file")
|
||
// 校验文件类型(图片/视频)
|
||
// 生成唯一文件名: UUID+时间戳
|
||
filename := fmt.Sprintf("%d_%s", time.Now().Unix(), file.Filename)
|
||
|
||
// 上传到CDN (伪代码)
|
||
url := cdn.Upload(file, filename)
|
||
|
||
// 保存记录到media表
|
||
media := Media{UserID: userID, Filename: filename, URL: url}
|
||
db.Create(&media)
|
||
|
||
c.JSON(200, gin.H{"url": url})
|
||
}
|
||
```
|
||
|
||
##### **3.5 评论模块**
|
||
```go
|
||
// models/comment.go
|
||
type Comment struct {
|
||
gorm.Model
|
||
ArticleID uint
|
||
UserID uint
|
||
MarkdownContent string
|
||
HTMLContent string
|
||
}
|
||
|
||
// handlers/comment.go
|
||
func AddComment(c *gin.Context) {
|
||
// Markdown内容渲染
|
||
// 敏感词过滤:
|
||
content := filter.SensitiveWords(c.PostForm("content"))
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### **4. API 接口设计**
|
||
##### **4.1 认证接口**
|
||
| 端点 | 方法 | 功能 |
|
||
|------|------|------|
|
||
| `/api/auth/register` | POST | 用户注册 |
|
||
| `/api/auth/login` | POST | 用户登录 |
|
||
| `/api/auth/refresh` | POST | 刷新Token |
|
||
|
||
##### **4.2 文章接口**
|
||
| 端点 | 方法 | 功能 |
|
||
|------|------|------|
|
||
| `/api/articles` | POST | 创建文章 |
|
||
| `/api/articles/:id` | PUT | 更新文章 |
|
||
| `/api/articles?status=published` | GET | 获取文章列表 |
|
||
| `/api/articles/:slug` | GET | 获取文章详情 |
|
||
| `/api/articles/:id/versions` | GET | 获取版本历史 |
|
||
|
||
##### **4.3 媒体接口**
|
||
| 端点 | 方法 | 功能 |
|
||
|------|------|------|
|
||
| `/api/media/upload` | POST | 上传文件 |
|
||
|
||
##### **4.4 管理接口**
|
||
| 端点 | 方法 | 权限 | 功能 |
|
||
|------|------|------|------|
|
||
| `/api/admin/users` | GET | admin | 用户列表 |
|
||
| `/api/admin/articles` | DELETE | admin | 批量删除文章 |
|
||
| `/api/comments/:id` | DELETE | admin/owner | 删除评论 |
|
||
|
||
---
|
||
|
||
#### **5. 安全设计**
|
||
1. **数据加密**
|
||
- 密码使用bcrypt哈希存储
|
||
- 敏感数据(邮箱)在数据库加密存储
|
||
|
||
2. **JWT 验证**
|
||
```go
|
||
// 生成Token
|
||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims{
|
||
UserID: user.ID,
|
||
Role: user.Role,
|
||
Exp: time.Now().Add(24*time.Hour).Unix(),
|
||
})
|
||
```
|
||
|
||
3. **XSS防护**
|
||
- Markdown渲染后使用`bluemonday`进行HTML净化
|
||
```go
|
||
import "github.com/microcosm-cc/bluemonday"
|
||
func sanitizeHTML(html string) string {
|
||
p := bluemonday.UGCPolicy()
|
||
return p.Sanitize(html)
|
||
}
|
||
```
|
||
|
||
4. **SQL注入防护**
|
||
- 使用GORM参数化查询
|
||
```go
|
||
db.Where("email = ?", email).First(&user)
|
||
```
|
||
|
||
---
|
||
|
||
#### **6. 性能优化**
|
||
1. **缓存策略**
|
||
- 热点文章HTML内容缓存到Redis
|
||
```go
|
||
func GetArticle(slug string) (Article, error) {
|
||
if html, err := redis.Get("article:"+slug); err == nil {
|
||
return Article{HTMLContent: html}, nil
|
||
}
|
||
// 数据库查询...
|
||
}
|
||
```
|
||
|
||
2. **异步处理**
|
||
- Markdown渲染使用goroutine池
|
||
```go
|
||
var renderPool = make(chan struct{}, 10) // 限流10并发
|
||
func AsyncRender(content string) string {
|
||
renderPool <- struct{}{}
|
||
defer func() { <-renderPool }()
|
||
return RenderMarkdown(content)
|
||
}
|
||
```
|
||
|
||
3. **CDN加速**
|
||
- 静态资源(图片/JS/CSS)通过CDN分发
|
||
|
||
|
||
|
||
> **文档说明**:此设计满足需求文档所有功能点,支持后续扩展API插件系统。 |