Files
Jog/doc/jog-system-technical-design.md
2026-05-17 15:55:06 +08:00

55 KiB
Raw Permalink Blame History

博客系统技术设计说明书

文档版本 修订日期 修订人 修订内容
V1.0 2026-05-17 初始版本,完整技术设计

1. 项目概述

1.1 项目定位

基于需求文档 blog-system-requirements.md 定义的博客系统功能需求与非功能性需求,本技术设计文档将作为 AI 编程的唯一输入依据,指导系统从零开始的完整开发。

1.2 技术栈选型

层级 技术 版本/说明
后端框架 Spring Boot 3.4.x(最新稳定版)
JDK OpenJDK 21LTS
项目构建 Maven 3.9+
数据库 MySQL 8.0+
缓存 Redis 7.2.xBSD 3-Clause 许可证,用于会话管理、验证码、限流计数)
ORM MyBatis-Plus 3.5.x
认证鉴权 Spring Security + JWT 无状态令牌认证
接口文档 SpringDoc OpenAPI 2.xSwagger UI
前端框架 Vue.js 3.xVite 构建)
UI 组件库 Element Plus 2.x
富文本编辑器 TiptapMIT 许可证)/ TinyMCE 社区版(LGPL,不使用 Premium 免费开源版
数据库迁移 Flyway 9.x

1.3 项目结构(单体应用、前后端一体化构建)

整个项目为一个 Maven 多模块项目,前端构建产物集成到后端静态资源目录中,通过 mvn package 一次编译生成可直接部署的 FAT JAR。

blog-system/
├── pom.xml                          # 父 POM
├── blog-common/                     # 公共模块
│   ├── pom.xml
│   └── src/main/java/com/blog/common/
│       ├── annotation/              # 自定义注解
│       ├── config/                  # 公共配置
│       ├── constant/                # 常量定义
│       ├── enums/                   # 枚举定义
│       ├── exception/               # 统一异常
│       ├── model/                   # 公共模型(分页、统一响应)
│       └── util/                    # 工具类
│
├── blog-framework/                  # 框架核心模块
│   ├── pom.xml
│   └── src/main/java/com/blog/framework/
│       ├── config/                  # Spring Boot 配置
│       ├── security/                # Spring Security + JWT
│       ├── interceptor/             # 拦截器
│       ├── aspect/                  # AOP 切面
│       ├── filter/                  # 过滤器
│       ├── handler/                 # 全局异常处理
│       └── rateLimiter/             # 限流组件
│
├── blog-module-system/              # 系统管理模块
│   ├── pom.xml
│   └── src/main/java/com/blog/module/system/
│       ├── controller/
│       │   ├── admin/               # 后台管理接口
│       │   └── app/                 # 前台用户接口
│       ├── service/
│       ├── mapper/
│       ├── entity/
│       └── dto/
│
├── blog-module-blog/                # 博客内容模块
│   ├── pom.xml
│   └── src/main/java/com/blog/module/blog/
│       ├── controller/
│       │   ├── admin/
│       │   ├── app/
│       │   └── api/                 # 公开接口(无需认证)
│       ├── service/
│       ├── mapper/
│       ├── entity/
│       └── dto/
│
├── blog-module-comment/             # 评论模块
│   ├── pom.xml
│   └── src/main/java/com/blog/module/comment/
│       ├── controller/
│       ├── service/
│       ├── mapper/
│       ├── entity/
│       └── dto/
│
├── blog-admin/                      # 后台管理 Web 模块
│   ├── pom.xml
│   └── src/main/
│       ├── java/com/blog/admin/
│       │   └── BlogAdminApplication.java
│       └── resources/
│           ├── application.yml
│           ├── application-dev.yml
│           └── application-prod.yml
│
└── blog-frontend/                   # 前端工程(Vue 3
    ├── package.json
    ├── vite.config.ts
    ├── index.html
    └── src/
        ├── api/                     # API 调用封装
        ├── assets/                  # 静态资源
        ├── components/              # 公共组件
        ├── layouts/                 # 布局组件
        ├── router/                  # 路由
        ├── store/                   # Pinia 状态管理
        ├── utils/                   # 工具函数
        ├── views/                   # 页面
        │   ├── admin/               # 后台管理页面
        │   └── front/               # 前台展示页面
        └── App.vue

前后端一体化构建流程

mvn clean package

执行上述命令时:

  1. blog-frontend 模块通过 frontend-maven-plugin 自动安装 Node.js 依赖并执行 npm run build
  2. 构建产物 (dist/) 通过 Maven 资源插件复制到 blog-admin/src/main/resources/static/
  3. blog-admin 模块打包为 FAT JAR,内嵌 Tomcat,直接通过 java -jar blog-admin.jar 启动

2. 系统架构设计

2.1 分层架构

系统采用经典的四层架构,严格遵循各层职责单一原则:

┌─────────────────────────────────────────────────────┐
│                   Controller 层                       │
│  ┌───────────────┐  ┌───────────────┐                │
│  │  admin/       │  │  app/         │  │  api/       │
│  │  后台管理接口   │  │  前台用户接口  │  │  公开接口    │
│  └──────┬────────┘  └──────┬────────┘  └──────┬─────┘│
│         │                  │                  │        │
├─────────┼──────────────────┼──────────────────┼────────┤
│         │   DTO / VO 数据校验与转换                  │
├─────────┼──────────────────┼──────────────────┼────────┤
│         ▼                  ▼                  ▼        │
│                   Service 层                           │
│  ┌─────────────────────────────────────────────────┐  │
│  │  接口定义(Interface) → 实现类(Impl            │  │
│  │  事务管理 @Transactional                          │  │
│  │  业务校验 → 调用 Mapper → 返回结果                 │  │
│  └──────────────────────┬──────────────────────────┘  │
│                         │                             │
├─────────────────────────┼─────────────────────────────┤
│                         ▼                             │
│                   Mapper 层                            │
│  ┌─────────────────────────────────────────────────┐  │
│  │  MyBatis-Plus BaseMapper 扩展                    │  │
│  │  自定义 XML / 注解 SQL                           │  │
│  └──────────────────────┬──────────────────────────┘  │
│                         │                             │
├─────────────────────────┼─────────────────────────────┤
│                         ▼                             │
│                   Entity 层                            │
│  ┌─────────────────────────────────────────────────┐  │
│  │  数据库表映射实体(@TableName, @TableId          │  │
│  │  逻辑删除 @TableLogic                            │  │
│  └─────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

2.2 请求处理链路

Client Request
     │
     ▼
Filter Chain: CorsFilter → RateLimitFilter → XssFilter
     │
     ▼
DispatcherServlet
     │
     ▼
Interceptor: LoginInterceptor(校验 JWT Token
     │
     ▼
AOP Aspect: LogAspect(操作日志)→ RateLimitAspect(限流)
     │
     ▼
Controller → 参数校验(@Valid / @Validated
     │
     ▼
Service → 业务处理
     │
     ▼
Mapper → 数据库操作
     │
     ▼
统一响应封装 → JSON 返回

2.3 认证鉴权架构

使用 JWTJSON Web Token 实现无状态认证,结合 Spring Security 进行权限控制。

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  客户端       │────▶│  LoginController │───▶│  AuthService   │
│  (浏览器)     │     │  /api/auth/*   │     │  认证服务      │
└──────────────┘     └──────────────┘     └──────┬───────┘
                                                 │
              ┌──────────────────────────────────┤
              ▼                                  ▼
     ┌────────────────┐                ┌──────────────────┐
     │ 校验通过         │                │  Redis 缓存会话    │
     │ 生成 AccessToken │◀───────────────│  多端登录控制      │
     │ + RefreshToken  │                │  最多 3 个活跃端   │
     └────────┬───────┘                └──────────────────┘
              │
              ▼
     ┌────────────────┐
     │ 返回 Token 给    │
     │ 客户端(HTTP Only│
     │ Cookie 或 Header│
     └────────────────┘

Token 策略

Token 类型 有效期 用途
AccessToken 2 小时 携带在请求头 Authorization: Bearer <token> 中,鉴权通过后访问受保护资源
RefreshToken 14 天(记住我)/ 24 小时 用于刷新 AccessToken,存储在 Redis 中

2.4 统一响应格式

所有 API 接口统一返回如下结构:

{
  "code": 200,
  "message": "success",
  "data": {},
  "timestamp": 1715932800000
}
字段 类型 说明
code Integer 业务状态码(200=成功, 400=参数错误, 401=未认证, 403=无权限, 404=资源不存在, 429=请求过频, 500=服务端错误)
message String 提示信息
data Object 响应数据,分页时包含 {records, total, page, pageSize}
timestamp Long 响应时间戳

2.5 异常体系

BusinessException (业务异常,code + message)
    ├── BadRequestException       (400)
    ├── UnauthorizedException     (401)
    ├── ForbiddenException        (403)
    ├── ResourceNotFoundException (404)
    ├── RateLimitException        (429)
    └── DuplicateOperationException (409)

全局异常处理器 GlobalExceptionHandler 捕获所有异常并统一返回标准响应格式。


3. 模块划分与职责

3.1 模块总览

模块 职责 关键接口前缀
blog-module-system 用户管理、角色权限、登录/注册、登录日志、系统配置 /api/auth/**, /api/admin/system/**
blog-module-blog 博客文章 CRUD、分类管理、标签管理、草稿管理、全文检索 /api/blog/**, /api/admin/blog/**
blog-module-comment 评论 CRUD、多级回复、评论审核、敏感词过滤、回复通知 /api/comment/**, /api/admin/comment/**

3.2 模块间依赖关系

blog-common (无依赖)
    ↑
blog-framework (依赖 blog-common)
    ↑
┌───────────────┼───────────────────┐
│               │                   │
blog-module-system  blog-module-blog──┐
│               │                   │   │
│               │                   │   │
└───────────────┼───────────────────┘   │
                │                       │
                ▼                       ▼
         blog-module-comment        blog-module-blog

说明:

  • blog-module-system 无业务模块依赖
  • blog-module-blog 依赖 blog-module-system(获取用户信息、鉴权)
  • blog-module-comment 依赖 blog-module-blog(获取文章信息)和 blog-module-system(获取用户信息、通知)

3.3 业务能力清单

按需求文档功能需求编号映射的模块能力:

需求编号 功能点 所属模块 接口说明
FR-ADM-LOGIN-01~06 管理员登录 blog-module-system 管理员认证、验证码、锁定、日志
FR-USER-REG-01~06 用户注册 blog-module-system 邮箱注册、验证、频率限制
FR-USER-LOGIN-01~06 用户登录 blog-module-system 邮箱登录、多端限制、第三方预留
FR-BLOG-PUB-01~07 博客发布 blog-module-blog 富文本编辑、草稿、状态管理、标签
FR-BLOG-LIST-01~08 博客列表查看 blog-module-blog 排序、筛选、检索、分页、浏览量
FR-COMMENT-01~07 评论功能 blog-module-comment 多级回复、审核、屏蔽、通知

4. 数据模型设计

4.1 数据库 E-R 关系概览

User (1) ──────< Blog (N)        # 用户拥有多篇博客
Blog (N) ──────< BlogTag (N)     # 博客关联多个标签(中间表)
Tag (N)  ──────< BlogTag (N)     # 标签被多篇博客使用
Category (1) ──< Blog (N)        # 分类下有多篇博客
Blog (1) ──────< Comment (N)     # 博客有多条评论
Comment (N) ───< Comment (N)     # 评论自关联(多级回复)
User (1) ──────< Comment (N)     # 用户发表多条评论
User (1) ──────< UserFollow (N)  # 用户关注关系
Blog (1) ──────< BlogView (N)    # 博客浏览记录
User (1) ──────< Notification (N) # 用户接收多条通知

4.2 数据字典

4.2.1 用户表 sys_user

字段名 类型 长度 主键 必填 默认值 说明
id BIGINT Y Y 自增 用户 ID
username VARCHAR 50 N NULL 用户名(管理员专用)
email VARCHAR 100 Y 邮箱(唯一索引)
phone VARCHAR 20 N NULL 手机号(管理员专用)
password VARCHAR 255 Y bcrypt 加盐哈希值
nickname VARCHAR 50 N NULL 昵称
avatar VARCHAR 500 N NULL 头像 URL
user_type TINYINT Y 1 用户类型:0=超级管理员, 1=注册用户
status TINYINT Y 0 状态:0=正常, 1=锁定
locked_until DATETIME N NULL 锁定截止时间
login_fail_count INT Y 0 连续登录失败次数
email_verified TINYINT Y 0 邮箱是否已验证:0=未验证, 1=已验证
last_login_ip VARCHAR 50 N NULL 最后登录 IP
last_login_time DATETIME N NULL 最后登录时间
created_at DATETIME Y CURRENT_TIMESTAMP 创建时间
updated_at DATETIME Y CURRENT_TIMESTAMP ON UPDATE 更新时间
deleted TINYINT Y 0 逻辑删除:0=未删除, 1=已删除

索引

  • uk_email:唯一索引(email, deleted
  • uk_username:唯一索引(username, deleted
  • idx_status:普通索引(status

初始化数据

  • 系统初始化 Flyway 脚本自动插入超级管理员账号(username: admin, password: Admin@2026,需登录后强制修改)

4.2.2 用户会话表 sys_user_session

字段名 类型 长度 主键 必填 说明
id BIGINT Y Y 自增 ID
user_id BIGINT N Y 用户 ID(外键)
token VARCHAR 500 Y JWT Token(或标识)
device_fingerprint VARCHAR 200 N 设备指纹
ip_address VARCHAR 50 N 登录 IP
user_agent VARCHAR 500 N 浏览器 UA
expire_time DATETIME Y 过期时间
created_at DATETIME Y 创建时间

索引

  • idx_user_id:普通索引(user_id
  • idx_token:唯一索引(token

多端限制逻辑

  • 查询 sys_user_session 统计 user_id 的活跃会话数(未过期的)
  • 如果 ≥ 3,删除最早的一条,再插入新会话
  • 实际 Token 校验走 Redis 缓存,DB 做持久化兜底

4.2.3 登录日志表 sys_login_log

字段名 类型 长度 主键 必填 说明
id BIGINT Y Y 自增 ID
user_id BIGINT N 用户 ID(失败时可能为空)
username VARCHAR 50 N 登录时使用的用户名/邮箱
login_type TINYINT Y 登录类型:0=管理员登录, 1=用户登录
result TINYINT Y 结果:0=失败, 1=成功
fail_reason VARCHAR 200 N 失败原因
ip_address VARCHAR 50 Y 登录 IP
device_fingerprint VARCHAR 200 N 设备指纹
created_at DATETIME Y 创建时间

索引

  • idx_user_id:普通索引(user_id
  • idx_created_at:普通索引(created_at

4.2.4 博客分类表 blog_category

字段名 类型 长度 主键 必填 默认值 说明
id BIGINT Y Y 自增 分类 ID
name VARCHAR 50 Y 分类名称(唯一)
description VARCHAR 200 N NULL 分类描述
sort_order INT Y 0 排序序号
status TINYINT Y 0 状态:0=启用, 1=禁用
created_at DATETIME Y CURRENT_TIMESTAMP 创建时间
updated_at DATETIME Y CURRENT_TIMESTAMP ON UPDATE 更新时间
deleted TINYINT Y 0 逻辑删除

索引uk_name:唯一索引(name, deleted

4.2.5 博客标签表 blog_tag

字段名 类型 长度 主键 必填 默认值 说明
id BIGINT Y Y 自增 标签 ID
name VARCHAR 30 Y 标签名称(唯一)
created_at DATETIME Y CURRENT_TIMESTAMP 创建时间
deleted TINYINT Y 0 逻辑删除

4.2.6 博客文章表 blog_article

字段名 类型 长度 主键 必填 默认值 说明
id BIGINT Y Y 自增 文章 ID
author_id BIGINT Y 作者用户 ID(外键)
category_id BIGINT N NULL 分类 ID(外键)
title VARCHAR 200 Y 文章标题
summary VARCHAR 500 N NULL 文章摘要(自动截取前 120 字)
content LONGTEXT Y 文章正文(HTML 格式)
content_text LONGTEXT N NULL 纯文本内容(用于全文检索)
cover_image VARCHAR 500 N NULL 封面图 URL
status TINYINT Y 0 发布状态:0=草稿, 1=已发布, 2=回收站
visibility TINYINT Y 0 可见性:0=公开, 1=私密, 2=仅粉丝可见
view_count INT Y 0 浏览量
comment_count INT Y 0 评论数
like_count INT Y 0 点赞数
is_top TINYINT Y 0 是否置顶:0=否, 1=是
published_at DATETIME N NULL 发布时间
created_at DATETIME Y CURRENT_TIMESTAMP 创建时间
updated_at DATETIME Y CURRENT_TIMESTAMP ON UPDATE 更新时间
deleted TINYINT Y 0 逻辑删除

索引

  • idx_author_id:普通索引(author_id
  • idx_category_id:普通索引(category_id
  • idx_status_visibility:联合索引(status, visibility
  • idx_published_at:普通索引(published_at
  • idx_view_count:普通索引(view_count
  • FULLTEXT idx_fulltext:全文索引(title, content_text

4.2.7 文章-标签关联表 blog_article_tag

字段名 类型 长度 主键 必填 说明
id BIGINT Y Y 自增 ID
article_id BIGINT Y 文章 ID(外键)
tag_id BIGINT Y 标签 ID(外键)

索引uk_article_tag:唯一索引(article_id, tag_id

4.2.8 文章浏览记录表 blog_article_view

字段名 类型 长度 主键 必填 说明
id BIGINT Y Y 自增 ID
article_id BIGINT Y 文章 ID(外键)
user_id BIGINT N 用户 ID(未登录为 NULL
ip_address VARCHAR 50 Y 访问者 IP
created_at DATETIME Y 访问时间

索引

  • idx_article_date:联合索引(article_id, DATE(created_at)
  • idx_user_article:唯一索引(user_id, article_id, DATE(created_at)),用于同一天同一用户去重

浏览量计数逻辑

  • 同一用户对同一篇文章每天只计入 1 次浏览量
  • 作者本人访问不计入浏览量
  • 未登录访客通过 IP + User-Agent 组合去重(每天仅计 1 次)

4.2.9 评论表 blog_comment

字段名 类型 长度 主键 必填 默认值 说明
id BIGINT Y Y 自增 评论 ID
article_id BIGINT Y 文章 ID(外键)
user_id BIGINT Y 评论者用户 ID(外键)
parent_id BIGINT N NULL 父评论 IDNULL 表示顶级评论)
reply_to_id BIGINT N NULL 被回复的评论 ID
reply_to_user_id BIGINT N NULL 被回复的用户 ID
content TEXT Y 评论内容(已过滤 XSS
level TINYINT Y 1 评论层级:1~3
status TINYINT Y 1 状态:0=待审核, 1=已通过, 2=已屏蔽, 3=已删除
is_author TINYINT Y 0 是否为文章作者:0=否, 1=是
created_at DATETIME Y CURRENT_TIMESTAMP 创建时间
deleted TINYINT Y 0 逻辑删除

索引

  • idx_article_id:普通索引(article_id
  • idx_parent_id:普通索引(parent_id
  • idx_user_id:普通索引(user_id
  • idx_status:普通索引(status

4.2.10 用户关注表 sys_user_follow

字段名 类型 长度 主键 必填 说明
id BIGINT Y Y 自增 ID
follower_id BIGINT Y 关注者用户 ID
followee_id BIGINT Y 被关注者用户 ID
created_at DATETIME Y 创建时间

索引uk_follower_followee:唯一索引(follower_id, followee_id

4.2.11 通知表 sys_notification

字段名 类型 长度 主键 必填 默认值 说明
id BIGINT Y Y 自增 通知 ID
receiver_id BIGINT Y 接收通知的用户 ID
sender_id BIGINT N NULL 触发通知的用户 ID
type TINYINT Y 通知类型:0=回复评论, 1=点赞, 2=系统通知
content VARCHAR 500 Y 通知内容
related_id BIGINT N NULL 关联的业务 ID(如评论 ID
is_read TINYINT Y 0 是否已读:0=未读, 1=已读
created_at DATETIME Y CURRENT_TIMESTAMP 创建时间

索引

  • idx_receiver_read:联合索引(receiver_id, is_read
  • idx_created_at:普通索引(created_at

4.2.12 系统配置表 sys_config

字段名 类型 长度 主键 必填 说明
id BIGINT Y Y 自增 ID
config_key VARCHAR 100 Y 配置键(唯一)
config_value TEXT Y 配置值
description VARCHAR 200 N 配置说明
updated_at DATETIME Y 更新时间

初始配置数据

config_key config_value description
comment_audit_enabled false 评论审核开关
oauth_wechat_enabled false 微信登录开关
oauth_github_enabled false GitHub 登录开关

4.2.13 敏感词表 sys_sensitive_word

字段名 类型 长度 主键 必填 说明
id BIGINT Y Y 自增 ID
word VARCHAR 100 Y 敏感词
replacement VARCHAR 100 Y 替换词(默认 ***
created_at DATETIME Y 创建时间

5. API 接口设计

5.1 接口规范

  • 基础路径/api
  • 公开接口:无需认证,路径前缀 /api/public/**
  • 前台用户接口:需 JWT 认证,路径前缀 /api/app/**
  • 后台管理接口:需 JWT 认证 + 管理员角色,路径前缀 /api/admin/**
  • 分页参数:统一使用 page(页码从 1 开始)和 pageSize(默认 15
  • 请求方法:遵循 RESTful 规范

5.2 认证模块接口

5.2.1 管理员登录

接口 方法 路径 认证 说明
管理员登录 POST /api/admin/auth/login 管理员账号密码登录
获取验证码 GET /api/public/captcha 获取图形验证码
管理员退出 POST /api/admin/auth/logout 需认证 退出并清除会话
获取管理员信息 GET /api/admin/auth/profile 需认证 获取当前管理员信息
查询登录日志 GET /api/admin/auth/login-logs Admin 分页查询登录日志
POST /api/admin/auth/login

Request

{
  "account": "admin | 13800138000",
  "password": "Admin@2026",
  "captchaKey": "UUID (失败3次后必传)",
  "captchaCode": "验证码 (失败3次后必传)",
  "deviceFingerprint": "设备指纹"
}

Response (200)

{
  "code": 200,
  "message": "登录成功",
  "data": {
    "accessToken": "eyJhbGci...",
    "refreshToken": "eyJhbGci...",
    "expiresIn": 7200,
    "userInfo": {
      "id": 1,
      "username": "admin",
      "nickname": "超级管理员",
      "avatar": null
    }
  }
}

Response (429 - 触发限流)

{
  "code": 429,
  "message": "登录过于频繁,请15分钟后再试"
}
GET /api/public/captcha

Response

{
  "code": 200,
  "data": {
    "captchaKey": "a1b2c3d4-e5f6-...",
    "captchaImage": "data:image/png;base64,iVBORw0KGgo..."
  }
}

5.2.2 用户登录/注册

接口 方法 路径 认证 说明
用户注册 POST /api/public/user/register 邮箱注册
验证邮箱 GET /api/public/user/verify-email 点击验证链接
重新发送验证邮件 POST /api/public/user/resend-verification 重新发送验证邮件
用户登录 POST /api/app/auth/login 邮箱密码登录
用户退出 POST /api/app/auth/logout 需认证 退出登录
刷新 Token POST /api/app/auth/refresh 使用 RefreshToken 刷新
获取用户信息 GET /api/app/auth/profile 需认证 获取当前登录用户信息
管理员重置用户密码 PUT /api/admin/system/user/{userId}/reset-password Admin 管理员重置指定用户密码
POST /api/public/user/register

Request

{
  "email": "user@example.com",
  "password": "Abc@123456",
  "confirmPassword": "Abc@123456"
}

Response (200)

{
  "code": 200,
  "message": "注册成功,请查看邮箱完成验证"
}

业务逻辑

  1. 校验邮箱格式和密码强度
  2. 校验邮箱是否已存在
  3. 校验同 IP 注册频率(1h 内 ≤ 3 次)
  4. 密码 bcrypt 加密
  5. 创建用户(status=0正常, email_verified=0
  6. 发送验证邮件(含 24h 有效期的 token)
  7. 记录注册日志
POST /api/app/auth/login

Request

{
  "email": "user@example.com",
  "password": "Abc@123456",
  "deviceFingerprint": "设备指纹",
  "rememberMe": false
}

Response (200)

{
  "code": 200,
  "data": {
    "accessToken": "eyJhbGci...",
    "refreshToken": "eyJhbGci...",
    "expiresIn": 7200,
    "userInfo": {
      "id": 2,
      "email": "user@example.com",
      "nickname": "用户昵称",
      "avatar": null
    }
  }
}

业务逻辑

  1. 验证邮箱 + 密码
  2. 检查账号是否锁定(locked_until > now 则拒绝)
  3. 检查 email_verified
  4. 多端限制检查(同一账号最多 3 个活跃会话)
  5. 生成 AccessToken2h 有效)+ RefreshToken24h 或 14d
  6. 记录登录日志
  7. 重置登录失败计数

5.3 博客模块接口

5.3.1 博客文章 CRUD

接口 方法 路径 认证 说明
创建文章 POST /api/app/blog/articles 需认证 创建新文章(草稿或直接发布)
编辑文章 PUT /api/app/blog/articles/{id} 需认证 修改文章(仅作者)
删除文章 DELETE /api/app/blog/articles/{id} 需认证 逻辑删除(仅作者)
获取文章详情 GET /api/public/blog/articles/{id} 公开可见的文章详情
获取我的文章列表 GET /api/app/blog/articles 需认证 获取当前用户的所有文章
获取公开文章列表 GET /api/public/blog/articles 公开文章的列表浏览
修改文章可见性 PATCH /api/app/blog/articles/{id}/visibility 需认证 修改发布状态
保存草稿 POST /api/app/blog/articles/draft 需认证 保存为草稿
自动保存草稿 PUT /api/app/blog/articles/{id}/draft 需认证 自动保存草稿
GET /api/public/blog/articles — 公开文章列表

Query Parameters

参数 类型 必填 默认值 说明
page Integer N 1 页码
pageSize Integer N 15 每页条数
categoryId Long N 分类 ID 筛选
tagId Long N 标签 ID 筛选
keyword String N 关键词全文检索
sortBy String N publishedAt 排序字段:publishedAt, viewCount
sortOrder String N desc 排序方向:asc, desc

Response

{
  "code": 200,
  "data": {
    "records": [
      {
        "id": 1,
        "title": "Spring Boot 入门指南",
        "summary": "本文介绍如何使用 Spring Boot 快速构建 Web 应用...",
        "coverImage": "https://...",
        "author": {
          "id": 2,
          "nickname": "作者昵称",
          "avatar": null
        },
        "category": {
          "id": 1,
          "name": "技术教程"
        },
        "tags": [
          {"id": 1, "name": "Java"},
          {"id": 2, "name": "Spring Boot"}
        ],
        "viewCount": 1280,
        "commentCount": 15,
        "publishedAt": "2026-05-15T10:30:00"
      }
    ],
    "total": 100,
    "page": 1,
    "pageSize": 15
  }
}

全文检索实现

  • 使用 MySQL FULLTEXT INDEX + MATCH...AGAINST 实现
  • 关键词高亮由前端在搜索结果中处理
GET /api/public/blog/articles/{id} — 文章详情

Response

{
  "code": 200,
  "data": {
    "id": 1,
    "title": "Spring Boot 入门指南",
    "content": "<h1>...</h1><p>...</p>",
    "author": {...},
    "category": {...},
    "tags": [...],
    "viewCount": 1280,
    "commentCount": 15,
    "isLiked": false,
    "visibility": 0,
    "publishedAt": "2026-05-15T10:30:00"
  }
}

业务逻辑

  1. 判断文章可见性:
    • status ≠ 已发布 → 404
    • visibility = 私密 且当前用户非作者 → 404
    • visibility = 仅粉丝可见 且当前用户非作者且非粉丝 → 404
  2. 浏览量更新(异步):
    • 同一用户同一天仅计 1 次
    • 作者本人不计
    • 调用 CompletableFuture 异步写入 blog_article_view
POST /api/app/blog/articles — 创建文章

Request

{
  "title": "文章标题",
  "content": "<h1>富文本内容</h1>",
  "categoryId": 1,
  "tagIds": [1, 2, 3],
  "coverImage": "https://...",
  "visibility": 0,
  "status": 0
}

参数说明

  • status=0 保存为草稿,status=1 直接发布
  • visibility 仅在发布时生效

Response (200)

{
  "code": 200,
  "data": {
    "id": 42
  }
}

业务逻辑

  1. 校验标题非空、内容非空
  2. 校验分类存在且启用
  3. 校验标签数量 ≤ 5
  4. XSS 过滤 content(使用 Jsoup 清理)
  5. 自动生成 summary(截取 content_text 前 120 字)
  6. 设置 published_atstatus=1 时)
  7. 插入 blog_article 和 blog_article_tag

5.3.2 分类与标签管理

接口 方法 路径 认证 说明
创建分类 POST /api/admin/blog/categories Admin 新增分类
编辑分类 PUT /api/admin/blog/categories/{id} Admin 修改分类
删除分类 DELETE /api/admin/blog/categories/{id} Admin 删除分类(有文章时禁止删除)
分类列表 GET /api/public/blog/categories 获取所有分类
创建标签 POST /api/admin/blog/tags Admin 新增标签
删除标签 DELETE /api/admin/blog/tags/{id} Admin 删除标签
标签列表 GET /api/public/blog/tags 获取所有标签

5.3.3 图片上传接口

接口 方法 路径 认证 说明
上传图片 POST /api/app/upload/image 需认证 上传文章图片

Requestmultipart/form-data,字段名 file

Response

{
  "code": 200,
  "data": {
    "url": "https://cdn.example.com/images/2026/05/abc123.jpg"
  }
}

业务规则

  • 支持格式:JPEG, PNG, GIF, WebP
  • 单图限制:≤ 10MB
  • 禁止上传 .exe, .js, .bat 等可执行文件
  • 上传后进行图片安全扫描(依赖第三方服务)

5.4 评论模块接口

接口 方法 路径 认证 说明
发表评论 POST /api/app/comments 需认证 对文章发表评论或回复
获取文章评论 GET /api/public/comments/{articleId} 获取指定文章的评论列表
删除评论 DELETE /api/admin/comments/{id} Admin 物理删除
屏蔽评论 PATCH /api/admin/comments/{id}/block Admin 逻辑屏蔽
审核评论 PATCH /api/admin/comments/{id}/approve Admin 审核通过
批量审核评论 POST /api/admin/comments/batch-approve Admin 批量审核
配置评论审核开关 PUT /api/admin/system/config/comment-audit Admin 开启/关闭评论审核

POST /api/app/comments — 发表评论

Request

{
  "articleId": 1,
  "content": "写得很棒,学习了!",
  "parentId": null,
  "replyToId": null
}

回复评论 Request

{
  "articleId": 1,
  "content": "感谢回复!",
  "parentId": 5,
  "replyToId": 8
}

Response (200)

{
  "code": 200,
  "data": {
    "id": 10,
    "status": 0
  }
}

当评论审核开启时 status=0(待审核),否则 status=1(已通过)

业务逻辑

  1. 校验文章存在且可见
  2. 校验 parentId 有效性:
    • 如果 parentId 非空,确认父评论存在且属于同一文章
    • 检查层级:查询父评论的 level,如果父评论 level ≥ 3,则设置为第 3 级的平级评论
  3. 敏感词过滤(替换为 ***
  4. XSS 过滤
  5. 判断评论者是否为文章作者(is_author)
  6. 评论审核开关判断:
    • 开启 → status=0(待审核)
    • 关闭 → status=1(已通过)
  7. 异步发送回复通知

GET /api/public/comments/{articleId} — 获取文章评论

Query Parameters

参数 类型 必填 默认值 说明
page Integer N 1 页码
pageSize Integer N 15 每页条数(顶级评论数)

Response

{
  "code": 200,
  "data": {
    "records": [
      {
        "id": 1,
        "content": "好文章!",
        "user": {
          "id": 2,
          "nickname": "小明",
          "avatar": null
        },
        "isAuthor": false,
        "level": 1,
        "createdAt": "2026-05-16T10:00:00",
        "children": [
          {
            "id": 2,
            "content": "谢谢支持!",
            "user": {
              "id": 1,
              "nickname": "作者大大",
              "avatar": null
            },
            "isAuthor": true,
            "level": 2,
            "replyToUserId": 2,
            "createdAt": "2026-05-16T10:05:00",
            "children": []
          }
        ]
      }
    ],
    "total": 20,
    "page": 1,
    "pageSize": 15
  }
}

5.5 管理后台接口

接口 方法 路径 认证 说明
用户列表 GET /api/admin/system/users Admin 分页查询用户列表
获取用户详情 GET /api/admin/system/users/{id} Admin 获取指定用户信息
禁用/启用用户 PATCH /api/admin/system/users/{id}/status Admin 修改用户状态
重置用户密码 PUT /api/admin/system/users/{id}/reset-password Admin 重置密码
操作日志列表 GET /api/admin/system/logs Admin 分页查询操作日志
系统配置列表 GET /api/admin/system/configs Admin 获取所有配置
更新系统配置 PUT /api/admin/system/configs/{key} Admin 更新配置项
敏感词列表 GET /api/admin/system/sensitive-words Admin 分页查询敏感词
添加敏感词 POST /api/admin/system/sensitive-words Admin 新增敏感词
删除敏感词 DELETE /api/admin/system/sensitive-words/{id} Admin 删除敏感词
后台仪表盘统计 GET /api/admin/dashboard/stats Admin 获取统计数据

5.6 OAuth 2.0 第三方登录扩展接口(预留)

接口 方法 路径 认证 说明
微信登录授权 GET /api/oauth/wechat/authorize 跳转微信授权页
微信登录回调 GET /api/oauth/wechat/callback 微信回调处理
GitHub 登录授权 GET /api/oauth/github/authorize 跳转 GitHub 授权页
GitHub 登录回调 GET /api/oauth/github/callback GitHub 回调处理

说明:当前版本仅定义接口路径和空实现。当 sys_config 表中 oauth_wechat_enabled / oauth_github_enabledtrue 时启用。预留 OAuth2Service 接口和 OAuth2UserInfo 模型,后续接入时实现接口即可。

5.7 接口权限映射速查表

接口路径范围 角色要求 鉴权方式
/api/public/** 无(允许匿名访问) 无需 Token
/api/app/** 注册用户 JWT Token + 用户角色校验
/api/admin/** 超级管理员 JWT Token + 管理员角色校验
/api/oauth/** 无(OAuth 流程) 无(暂为预留空实现)

6. 核心业务流程

6.1 用户注册流程

用户填写注册表单 (邮箱 + 密码)
        │
        ▼
前端校验:邮箱格式、密码强度、两次密码一致
        │
        ▼
POST /api/public/user/register
        │
        ▼
后端校验:
  1. 邮箱格式正则校验
  2. 密码强度校验(8-32位,至少3类字符)
  3. 邮箱唯一性检查
  4. IP 注册频率检查(1h ≤ 3次)
        │
        ▼
密码 bcrypt 加密
        │
        ▼
创建用户 (email_verified = 0)
        │
        ▼
生成邮箱验证 TokenUUID,有效期 24h
        │
        ▼
发送验证邮件(含验证链接)
        │
        ▼
返回「注册成功,请查看邮箱完成验证」
        │
        ▼
用户点击验证链接 → GET /api/public/user/verify-email?token=xxx
        │
        ▼
校验 Token 有效性 → 用户 email_verified = 1
        │
        ▼
返回「邮箱验证成功,请登录」

6.2 管理员/用户登录流程(含防暴力破解)

用户输入账号密码
        │
        ▼
后端查询账号是否存在
        │
        ▼ (不存在)
返回「账号或密码错误」(模糊提示,不泄露具体字段)
        │
        ▼ (存在)
检查用户状态:
  - status=1 (锁定) 且 locked_until > now → 返回「账号已被锁定,请 X 分钟后重试」
  - 否则继续
        │
        ▼
验证密码(bcrypt.matches
        │
        ▼ (失败)
记录失败次数 + 1
        │
        ▼  (失败次数分析)
  - 失败 3 次(管理员)→ 下次需输入验证码
  - 失败 5 次 → 锁定账号 N 分钟(管理员30min,用户15min
  - 同一 IP 10 次/5min → IP 封禁 15 分钟
        │
        ▼ (成功)
重置失败计数
        │
        ▼
多端登录控制(仅前台用户):
  查询活跃会话数,≥ 3 个时剔除最早会话
        │
        ▼
生成 JWT Token + RefreshToken
        │
        ▼
记录登录日志(成功)
        │
        ▼
返回 Token + 用户信息

6.3 博客发布流程

用户进入编辑器(需认证)
        │
        ▼
用户编写内容(富文本)
  支持:图片上传、视频嵌入
        │
        ▼
每 30 秒自动保存草稿 (PUT /api/app/blog/articles/{id}/draft)
        │
        ▼ (用户点击发布)
前端弹窗二次确认:选择可见性(公开/私密/仅粉丝可见)
        │
        ▼
POST /api/app/blog/articles
        │
        ▼
后端校验:
  1. 标题、内容非空
  2. 分类存在且启用
  3. 标签数 ≤ 5
  4. 图片/内容安全检测
  5. XSS 过滤
        │
        ▼
生成摘要(纯文本截取前 120 字)
        │
        ▼
设置 published_at = now
  插入 blog_article + blog_article_tag
        │
        ▼
返回成功 + 文章 ID
        │
        ▼
前端跳转到文章详情页

6.4 多级评论流程

用户查看文章 → 查看评论列表 (GET /api/public/comments/{articleId})
        │
        ▼
用户填写评论内容 → 点击发表
        │
        ▼
POST /api/app/comments
        │
        ▼
后端校验:
  1. 文章存在且用户有权限查看
  2. 内容非空、≤ 2000 字
  3. 敏感词过滤 → 替换为 ***
  4. XSS 过滤
        │
        ▼
↓ 是回复评论?                                    ↓ 否,顶级评论
│                                                │
查询父评论信息                                      │
检查层级:                                          │
  parent.level = 1 → 新评论 level = 2              │
  parent.level = 2 → 新评论 level = 3              │
  parent.level ≥ 3 → 自动设为 level=3 的平级       │
│                                                │
│                                                ▼
判断评论者是否为文章作者 → 设置 is_author
        │
        ▼
评论审核开关判断:
  ON  → status=0 (待审核)
  OFF → status=1 (已通过)
        │
        ▼
异步发送通知:
  如果开启了审核且通过,或审核关闭:
  回复评论 → 通知被回复人
        │
        ▼
返回评论结果

6.5 浏览量统计流程

用户访问文章详情页
        │
        ▼
后端接收 GET /api/public/blog/articles/{id} 请求
        │
        ▼
判断是否需要计数:
  1. 当前用户 == 文章作者 → 不计
  2. 当前用户已登录:
     - 查询 blog_article_view 中 user_id + today 是否有记录
     - 有 → 不计;无 → 计 1 次
  3. 当前用户未登录(访客):
     - 查询 blog_article_view 中 ip_address + today 是否有记录
     - 有 → 不计;无 → 计 1 次
        │
        ▼ (需要计数)
使用 CompletableFuture.runAsync() 异步执行:
  1. 插入浏览记录 blog_article_view
  2. UPDATE blog_article SET view_count = view_count + 1 WHERE id = ?
        │
        ▼
返回文章详情(含当前 view_count

7. 开发规范

7.1 包命名规范

com.blog.{module}.{layer}
占位符 说明 示例
{module} 模块名 common, framework, module.system, module.blog
{layer} 分层 controller, service, mapper, entity, dto, config

7.2 命名约定

元素 规范 示例
类名 UpperCamelCase BlogArticleController, AuthService
方法名 lowerCamelCase getUserById, createArticle
变量名 lowerCamelCase articleList, currentUser
常量 UPPER_SNAKE_CASE MAX_LOGIN_ATTEMPTS
数据库表 小写+下划线 blog_article, sys_user
数据库字段 小写+下划线 view_count, published_at
请求映射路径 小写+连字符 /api/public/blog/articles
JSON 字段 lowerCamelCase viewCount, publishedAt

7.3 Controller 层规范

@RestController
@RequestMapping("/api/app/blog/articles")
@Tag(name = "博客文章管理", description = "前台博客文章接口")
public class BlogArticleController {

    @GetMapping
    @Operation(summary = "获取我的文章列表")
    public ApiResult<PageResult<BlogArticleVO>> listMyArticles(
            @Valid PageParam pageParam,
            @RequestParam(required = false) Long categoryId) {
        // ...
    }

    @PostMapping
    @Operation(summary = "创建文章")
    public ApiResult<IdVO> createArticle(@Valid @RequestBody ArticleCreateDTO dto) {
        // ...
    }
}

7.4 Service 层规范

  • 每个 Service 先定义接口,再写实现类
  • 接口命名:XxxService(如 BlogArticleService
  • 实现类命名:XxxServiceImpl(如 BlogArticleServiceImpl
  • 使用 @Service 注解,事务方法加 @Transactional(rollbackFor = Exception.class)

7.5 异常处理规范

  • 禁止在 Controller 中使用 try-catch 捕获业务异常
  • 业务异常直接 throw new BusinessException(code, message)
  • GlobalExceptionHandler 统一捕获并返回标准响应

7.6 日志规范

使用 Lombok @Slf4j 注解,日志级别使用规则:

级别 使用场景
ERROR 系统异常、数据库错误、调用第三方服务失败
WARN 参数校验失败、业务异常(如登录失败)、限流触发
INFO 关键业务流程(如用户注册成功、文章发布)、接口调用入参出参(可开关)
DEBUG 开发调试信息,禁止在生产环境输出

7.7 安全编码规范

要求 实现方式
密码存储 始终使用 bcrypt 哈希,禁止 MD5/SHA1 明文存储
SQL 注入防护 全程使用 MyBatis-Plus 参数化查询,禁止 ${} 拼接
XSS 防护 用户输入输出前使用 Jsoup.clean() 过滤 HTML 标签
CSRF 防护 前端请求需携带自定义 Header(如 X-Requested-With: XMLHttpRequest),后端校验 Origin
敏感信息脱敏 日志中密码、Token 等使用 **** 替代
文件上传安全 校验 Content-Type 和文件魔术头,限制可执行文件上传
接口防刷 核心接口使用限流注解 @RateLimit

7.8 限流注解使用

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
    String key() default "";          // 限流 key
    int maxCount() default 10;        // 最大访问次数
    int duration() default 60;        // 时间窗口(秒)
    TimeUnit unit() default TimeUnit.SECONDS;
}

使用 Redis 滑动窗口计数器实现:

// 登录接口限流:同一 IP 5分钟内最多 10 次
@RateLimit(key = "login:ip:#{ip}", maxCount = 10, duration = 300)

// 注册接口限流:同一 IP 1小时内最多 3 次
@RateLimit(key = "register:ip:#{ip}", maxCount = 3, duration = 3600)

// 评论提交限流:同一用户 1分钟内最多 5 次
@RateLimit(key = "comment:user:#{userId}", maxCount = 5, duration = 60)

8. 项目配置文件规范

8.1 application.yml 核心配置

server:
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/blog_system?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: ${DB_PASSWORD}
    driver-class-name: com.mysql.cj.jdbc.Driver
  data:
    redis:
      host: localhost
      port: 6379
      password: ${REDIS_PASSWORD}
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 50MB
  flyway:
    enabled: true
    locations: classpath:db/migration
    baseline-on-migrate: true

jwt:
  secret: ${JWT_SECRET}
  access-token-expire: 7200          # AccessToken 有效期(秒)
  refresh-token-expire: 86400        # RefreshToken 有效期(秒,记住我模式 14 天)
  refresh-token-expire-remember: 1209600

app:
  upload:
    image-max-size: 10485760         # 10MB
    allowed-types: image/jpeg,image/png,image/gif,image/webp
  rate-limit:
    login-max-attempts: 5            # 登录最大失败次数
    login-lock-duration: 15          # 锁定分钟数(用户)
    admin-login-lock-duration: 30    # 锁定分钟数(管理员)
    ip-block-threshold: 10           # IP 封禁阈值
    ip-block-duration: 15            # IP 封禁分钟数

8.2 Maven 多模块依赖管理

<!-- 父 POM 关键依赖版本管理 -->
<properties>
    <spring-boot.version>3.4.x</spring-boot.version>
    <mybatis-plus.version>3.5.9</mybatis-plus.version>
    <jjwt.version>0.12.6</jjwt.version>
    <springdoc.version>2.7.0</springdoc.version>
    <jsoup.version>1.18.1</jsoup.version>
</properties>

9. 构建与部署

9.1 一体化构建流程

mvn clean package

执行步骤:

  1. blog-framework → 编译
  2. blog-module-system → 编译
  3. blog-module-blog → 编译
  4. blog-module-comment → 编译
  5. blog-frontend自动安装 Node.js 依赖 → npm run build → 复制 dist/ 到 blog-admin 的 static 目录
  6. blog-admin → 打包为 FAT JAR(包含所有模块 + 前端静态资源)

9.2 部署方式

# 生产环境启动
java -jar blog-admin.jar --spring.profiles.active=prod

# 或使用外部配置
java -jar blog-admin.jar --spring.config.location=/path/to/application-prod.yml

FAT JAR 包含:

  • 所有后端模块的字节码
  • MySQL Driver、Redis Client 等依赖
  • 前端静态资源(HTML/CSS/JS
  • 内嵌 Tomcat 容器

10. 数据库初始化脚本(Flyway)

Flyway 脚本位于 blog-admin/src/main/resources/db/migration/

db/migration/
├── V1__init_schema.sql             # 建表:sys_user, sys_user_session, sys_login_log, blog_category, blog_tag, blog_article, blog_article_tag, blog_comment, sys_user_follow, sys_notification, sys_config, sys_sensitive_word, blog_article_view
├── V2__init_data.sql               # 初始化:超级管理员账号、默认分类、默认配置项
├── V3__init_indexes.sql            # 建索引:全文索引、联合索引
└── V4__init_sensitive_words.sql    # 初始化敏感词库

V2 初始化数据关键内容

-- 超级管理员(密码: Admin@2026bcrypt 哈希)
INSERT INTO sys_user (username, email, password, nickname, user_type, status, email_verified)
VALUES ('admin', 'admin@blogsystem.com',
        '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy',
        '超级管理员', 0, 0, 1);

-- 默认分类
INSERT INTO blog_category (name, description) VALUES
('技术教程', '编程语言、框架、工具等技术教程'),
('生活随笔', '日常生活感悟与记录'),
('资源分享', '优质资源与工具推荐');

-- 默认配置
INSERT INTO sys_config (config_key, config_value, description) VALUES
('comment_audit_enabled', 'false', '评论审核开关'),
('oauth_wechat_enabled', 'false', '微信登录开关'),
('oauth_github_enabled', 'false', 'GitHub 登录开关');

11. 接口文档与测试

  • 开发环境:访问 /swagger-ui.html 查看 Swagger 接口文档(由 SpringDoc OpenAPI 自动生成)
  • API 测试:所有接口附带 JSON 请求/响应示例,可直接导入 Postman
  • 单元测试:每个 Service 层方法需编写对应的单元测试,覆盖率 ≥ 80%(使用 JUnit 5 + Mockito
  • 集成测试:关键业务流程(登录、注册、发布、评论)需编写集成测试

文档结束

本文档基于 blog-system-requirements.md 需求文档编写,覆盖了后端技术架构、模块划分、接口定义、数据模型、业务流程及开发规范六大核心内容。AI 编程可依据本文档中定义的模块结构、数据字段、接口路径和业务逻辑完成系统的完整开发。前后端一体化构建,通过 mvn clean package 一条命令即可生成可直接部署的 FAT JAR。