master
mvn clean 默认仅清理 target/,但 Vite 构建输出到 src/main/resources/static/(不在 target 下)。若旧产物残留, 部署后仍使用旧版前端文件。现在 mvn clean 会同步清空 static/, 确保每次部署都从干净的构建产物开始。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Jog System - 博客系统
一个基于 Spring Boot 3 + Vue 3 构建的现代化博客系统,支持文章发布、评论互动、用户管理等功能。
目录
项目概述
Jog System 是一个功能完善的博客内容管理系统,采用前后端分离架构,后端使用 Spring Boot 3 构建 RESTful API,前端使用 Vue 3 + Element Plus 构建现代化用户界面。系统支持管理员对平台进行统一管控,注册用户可发布博客、互动评论,访客可浏览公开内容。
项目特点
- 现代化技术栈:基于 Spring Boot 3.4 和 Vue 3 构建
- 安全可靠:集成 Spring Security + JWT 无状态认证
- 多模块架构:Maven 多模块设计,职责清晰
- 数据库迁移:使用 Flyway 管理数据库版本
- API 文档:集成 SpringDoc OpenAPI,自动生成接口文档
- 限流防护:支持接口限流,防止恶意请求
- XSS 防护:内置 XSS 过滤器,保障内容安全
核心功能
用户管理
| 功能 | 描述 |
|---|---|
| 管理员登录 | 支持用户名/手机号+密码登录,验证码机制,防暴力破解 |
| 用户注册 | 邮箱+密码注册,邮箱验证,密码强度校验 |
| 用户登录 | 支持多端登录(最多3个活跃会话),记住我功能 |
| 会话管理 | JWT Token 认证,Token 自动刷新 |
博客功能
| 功能 | 描述 |
|---|---|
| 文章发布 | 富文本编辑器,支持图片上传、视频嵌入 |
| 草稿保存 | 手动保存 + 自动保存(每30秒) |
| 文章可见性 | 公开、私密、仅粉丝可见 |
| 分类与标签 | 一篇文章必须绑定1个分类,最多5个标签 |
| 文章列表 | 支持排序、筛选、全文检索、分页 |
| 浏览量统计 | 自动统计文章浏览量(去重) |
评论功能
| 功能 | 描述 |
|---|---|
| 多级评论 | 支持楼中楼回复,最多嵌套3级 |
| 评论审核 | 可配置是否需要管理员审核 |
| 违规处理 | 管理员可删除或屏蔽违规评论 |
| 回复通知 | 评论被回复时发送站内通知 |
系统管理
| 功能 | 描述 |
|---|---|
| 用户管理 | 查看用户列表,重置用户密码 |
| 文章管理 | 管理所有文章,删除违规内容 |
| 评论管理 | 审核评论,处理违规内容 |
| 分类管理 | 创建、编辑、删除分类 |
| 标签管理 | 创建、删除标签 |
技术栈
后端技术
| 技术 | 版本 | 说明 |
|---|---|---|
| Spring Boot | 3.4.5 | 核心框架 |
| Spring Security | - | 安全框架 |
| JWT (jjwt) | 0.12.6 | Token 认证 |
| MyBatis-Plus | 3.5.9 | ORM 框架 |
| MySQL | 8.0+ | 关系型数据库 |
| Redis | 7.2.x | 缓存数据库 |
| Flyway | - | 数据库迁移 |
| SpringDoc OpenAPI | 2.8.6 | API 文档 |
| Hutool | 5.8.34 | 工具类库 |
| Jsoup | 1.18.1 | HTML 解析(XSS 过滤) |
前端技术
| 技术 | 版本 | 说明 |
|---|---|---|
| Vue.js | 3.5.x | 前端框架 |
| Vite | 6.0.x | 构建工具 |
| Element Plus | 2.9.x | UI 组件库 |
| Pinia | 2.3.x | 状态管理 |
| Vue Router | 4.5.x | 路由管理 |
| Axios | 1.7.x | HTTP 客户端 |
| Tiptap | 2.11.x | 富文本编辑器 |
项目结构
jog-system/
├── pom.xml # 父 POM,管理依赖版本
├── doc/ # 项目文档
│ ├── jog-system-requirements.md # 需求规格说明书
│ └── jog-system-technical-design.md # 技术设计说明书
│
├── jog-common/ # 公共模块
│ ├── pom.xml
│ └── src/main/java/fun/nojava/common/
│ ├── annotation/ # 自定义注解(如 @RateLimit)
│ ├── constant/ # 常量定义
│ ├── enums/ # 枚举定义
│ ├── exception/ # 统一异常处理
│ ├── model/ # 公共模型(ApiResult, PageResult)
│ └── util/ # 工具类
│
├── jog-framework/ # 框架核心模块
│ ├── pom.xml
│ └── src/main/java/fun/nojava/framework/
│ ├── aspect/ # AOP 切面(日志、限流)
│ ├── config/ # 配置类(Security, Web, JWT)
│ ├── filter/ # 过滤器(XSS 过滤)
│ ├── handler/ # 全局异常处理
│ ├── security/ # 安全相关(JWT 认证)
│ └── util/ # 框架工具类
│
├── jog-module-system/ # 系统管理模块
│ ├── pom.xml
│ └── src/main/java/fun/nojava/module/system/
│ ├── controller/ # 控制器
│ │ ├── admin/ # 后台管理接口
│ │ └── app/ # 前台用户接口
│ ├── service/ # 业务服务
│ ├── mapper/ # 数据访问
│ ├── entity/ # 实体类
│ └── dto/ # 数据传输对象
│
├── jog-module-blog/ # 博客内容模块
│ ├── pom.xml
│ └── src/main/java/fun/nojava/module/blog/
│ ├── controller/
│ ├── service/
│ ├── mapper/
│ ├── entity/
│ └── dto/
│
├── jog-module-comment/ # 评论模块
│ ├── pom.xml
│ └── src/main/java/fun/nojava/module/comment/
│ ├── controller/
│ ├── service/
│ ├── mapper/
│ ├── entity/
│ └── dto/
│
├── jog-admin/ # 后台管理启动模块
│ ├── pom.xml
│ └── src/main/
│ ├── java/fun/nojava/admin/ # 启动类
│ └── resources/
│ ├── application.yml # 应用配置
│ └── db/migration/ # Flyway 迁移脚本
│ ├── V1__init_schema.sql # 数据库表结构
│ └── V2__init_data.sql # 初始化数据
│
└── jog-frontend/ # 前端工程
├── package.json
├── vite.config.js
├── index.html
└── src/
├── api/ # API 接口封装
├── layouts/ # 布局组件
├── router/ # 路由配置
├── stores/ # Pinia 状态管理
├── utils/ # 工具函数
└── views/ # 页面组件
├── admin/ # 后台管理页面
└── app/ # 前台用户页面
模块依赖关系
jog-admin (启动入口)
├── jog-module-system
│ └── jog-framework
│ └── jog-common
├── jog-module-blog
│ └── jog-module-system
└── jog-module-comment
└── jog-module-blog
环境要求
开发环境
| 软件 | 版本要求 |
|---|---|
| JDK | 17 或更高 |
| Maven | 3.9+ |
| Node.js | 18.x 或更高 |
| MySQL | 8.0+ |
| Redis | 7.2.x |
推荐开发工具
- 后端:IntelliJ IDEA(推荐)或 Eclipse
- 前端:VS Code 或 WebStorm
- 数据库:MySQL Workbench 或 Navicat
- API 测试:Postman 或 Apifox
快速开始
1. 克隆项目
git clone https://github.com/your-username/jog-system.git
cd jog-system
2. 数据库配置
创建 MySQL 数据库:
CREATE DATABASE jog_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
3. 修改配置文件
编辑 jog-admin/src/main/resources/application.yml:
spring:
datasource:
url: jdbc:mysql://localhost:3306/jog_db?useUnicode=true&characterEncoding=utf8mb4&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: your_username
password: your_password
data:
redis:
host: localhost
port: 6379
4. 安装前端依赖
cd jog-frontend
npm install
5. 启动后端服务
cd ..
mvn clean install -DskipTests
cd jog-admin
mvn spring-boot:run
或者直接运行主类 fun.nojava.admin.JogAdminApplication。
6. 启动前端开发服务器
cd jog-frontend
npm run dev
前端开发服务器将在 http://localhost:5173 启动。
7. 访问应用
- 前端页面:http://localhost:5173
- 后端 API:http://localhost:8080
- Swagger 文档:http://localhost:8080/swagger-ui.html
8. 默认管理员账号
| 用户名 | 密码 | 角色 |
|---|---|---|
| admin | Admin@123 | 管理员 |
配置说明
应用配置 (application.yml)
server:
port: 8080 # 服务端口
spring:
application:
name: jog-system # 应用名称
datasource: # 数据源配置
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/jog_db
username: root
password: root
data:
redis: # Redis 配置
host: localhost
port: 6379
database: 0
flyway: # Flyway 配置
enabled: true
locations: classpath:db/migration
mail: # 邮件配置
host: smtp.example.com
port: 587
username: noreply@example.com
password: your-mail-password
jwt: # JWT 配置
secret: YourSuperSecretKeyForJwtTokenGenerationMustBeAtLeast256BitsLongForHS256Algorithm
access-token-expire: 7200 # Access Token 有效期(秒)
refresh-token-expire: 86400 # Refresh Token 有效期(秒)
refresh-token-expire-remember: 1209600 # 记住我时的有效期
mybatis-plus: # MyBatis-Plus 配置
mapper-locations: classpath*:/mapper/**/*.xml
configuration:
map-underscore-to-camel-case: true
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
springdoc: # Swagger 配置
api-docs:
enabled: true
path: /v3/api-docs
swagger-ui:
enabled: true
path: /swagger-ui.html
前端配置 (vite.config.js)
export default defineConfig({
server: {
port: 5173,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
},
},
},
build: {
outDir: '../jog-admin/src/main/resources/static',
emptyOutDir: true,
},
})
API 接口文档
接口分类
系统 API 按照访问权限分为三类:
| 前缀 | 权限 | 说明 |
|---|---|---|
/api/public/** |
无需认证 | 公开接口 |
/api/app/** |
需要用户登录 | 用户接口 |
/api/admin/** |
需要管理员权限 | 管理接口 |
认证接口
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/public/admin/login | 管理员登录 |
| POST | /api/public/user/login | 用户登录 |
| POST | /api/public/user/register | 用户注册 |
| POST | /api/public/refresh-token | 刷新 Token |
| GET | /api/public/captcha | 获取验证码 |
文章接口
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/public/article/list | 获取公开文章列表 |
| GET | /api/public/article/{id} | 获取文章详情 |
| POST | /api/app/article | 创建文章 |
| PUT | /api/app/article/{id} | 更新文章 |
| DELETE | /api/app/article/{id} | 删除文章 |
| GET | /api/app/article/mine | 获取我的文章 |
| POST | /api/app/article/{id}/like | 点赞/取消点赞 |
评论接口
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/public/comment/list | 获取评论列表 |
| POST | /api/app/comment | 发表评论 |
| DELETE | /api/app/comment/{id} | 删除评论 |
管理接口
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/admin/user/list | 获取用户列表 |
| GET | /api/admin/article/list | 获取所有文章 |
| DELETE | /api/admin/article/{id} | 删除文章 |
| GET | /api/admin/comment/list | 获取所有评论 |
| PUT | /api/admin/comment/{id}/audit | 审核评论 |
统一响应格式
{
"code": 200,
"message": "success",
"data": { ... },
"timestamp": 1715923200000
}
错误码说明
| 错误码 | 说明 |
|---|---|
| 200 | 成功 |
| 400 | 请求参数错误 |
| 401 | 未认证/Token 过期 |
| 403 | 无权限 |
| 404 | 资源不存在 |
| 429 | 请求过于频繁 |
| 500 | 服务器内部错误 |
数据库设计
核心表结构
用户表 (sys_user)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT | 主键 |
| username | VARCHAR(50) | 用户名 |
| VARCHAR(100) | 邮箱(唯一) | |
| password | VARCHAR(255) | 密码(BCrypt 加密) |
| user_type | TINYINT | 用户类型:0管理员 1普通用户 |
| status | TINYINT | 状态:0正常 1锁定 |
| email_verified | TINYINT | 邮箱是否验证 |
文章表 (blog_article)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT | 主键 |
| user_id | BIGINT | 作者ID |
| category_id | BIGINT | 分类ID |
| title | VARCHAR(200) | 标题 |
| content | LONGTEXT | 内容 |
| status | TINYINT | 状态:0草稿 1已发布 2回收站 |
| visibility | TINYINT | 可见性:0公开 1私密 2仅粉丝 |
| view_count | INT | 浏览量 |
评论表 (blog_comment)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT | 主键 |
| article_id | BIGINT | 文章ID |
| user_id | BIGINT | 评论者ID |
| parent_id | BIGINT | 父评论ID |
| content | VARCHAR(1000) | 评论内容 |
| level | TINYINT | 评论层级(最多3级) |
| status | TINYINT | 状态:0待审核 1已通过 2已屏蔽 |
数据库迁移
系统使用 Flyway 管理数据库版本,迁移脚本位于:
jog-admin/src/main/resources/db/migration/
├── V1__init_schema.sql # 表结构初始化
└── V2__init_data.sql # 初始数据
开发指南
后端开发
1. 创建新的业务模块
<!-- pom.xml -->
<project>
<parent>
<groupId>fun.nojava</groupId>
<artifactId>jog-system</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>jog-module-xxx</artifactId>
</project>
2. Controller 示例
@RestController
@RequestMapping("/api/app/article")
@RequiredArgsConstructor
public class ArticleController {
private final ArticleService articleService;
@PostMapping
@Operation(summary = "创建文章")
public ApiResult<Long> create(@Valid @RequestBody ArticleCreateDTO dto) {
return ApiResult.success(articleService.create(dto));
}
}
3. Service 示例
@Service
@RequiredArgsConstructor
public class ArticleServiceImpl implements ArticleService {
private final ArticleMapper articleMapper;
@Override
@Transactional
public Long create(ArticleCreateDTO dto) {
Article article = new Article();
BeanUtils.copyProperties(dto, article);
articleMapper.insert(article);
return article.getId();
}
}
前端开发
1. 创建新页面
<template>
<div class="page-container">
<!-- 页面内容 -->
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const data = ref([])
onMounted(() => {
fetchData()
})
async function fetchData() {
// 获取数据
}
</script>
2. 添加路由
// router/index.js
{
path: '/new-page',
name: 'NewPage',
component: () => import('@/views/NewPage.vue'),
meta: { title: '新页面', requiresAuth: true },
}
3. API 调用
// api/example.js
import request from '@/utils/request'
export function getData(params) {
return request.get('/api/app/example', { params })
}
export function createData(data) {
return request.post('/api/app/example', data)
}
构建部署
开发环境
# 后端
mvn spring-boot:run
# 前端
cd jog-frontend
npm run dev
生产环境
# 构建前端(自动输出到 jog-admin/src/main/resources/static)
cd jog-frontend
npm run build
# 打包后端(包含前端静态资源)
cd ..
mvn clean package -DskipTests
# 运行
java -jar jog-admin/target/jog-admin.jar
常见问题
Q1: 启动时报数据库连接错误?
A: 检查以下几点:
- MySQL 服务是否启动
- 数据库
jog_db是否已创建 application.yml中的数据库配置是否正确- MySQL 用户是否有足够的权限
Q2: Flyway 迁移失败?
A: 可能原因:
- 数据库已存在数据,与迁移脚本冲突
- 解决方法:清空数据库后重新启动,或设置
spring.flyway.baseline-on-migrate=true
Q3: JWT Token 无效?
A: 检查:
- Token 是否过期
- JWT secret 配置是否一致
- 请求头是否正确携带
Authorization: Bearer <token>
Q4: 前端代理不生效?
A: 确保:
vite.config.js中代理配置正确- 后端服务已启动在 8080 端口
- 使用
/api前缀访问后端接口
Q5: Redis 连接失败?
A: 检查:
- Redis 服务是否启动
application.yml中 Redis 配置是否正确- 端口是否被占用
贡献指南
欢迎贡献代码!请遵循以下步骤:
1. Fork 项目
点击右上角 Fork 按钮,将项目 Fork 到你的账户。
2. 克隆仓库
git clone https://github.com/your-username/jog-system.git
cd jog-system
3. 创建分支
git checkout -b feature/your-feature-name
4. 提交代码
git add .
git commit -m "feat: 添加新功能"
提交信息规范
| 前缀 | 说明 |
|---|---|
| feat | 新功能 |
| fix | 修复 Bug |
| docs | 文档更新 |
| style | 代码格式调整 |
| refactor | 重构 |
| test | 测试相关 |
| chore | 构建/工具相关 |
5. 推送分支
git push origin feature/your-feature-name
6. 创建 Pull Request
在 GitHub 上创建 Pull Request,描述你的修改内容。
许可证
本项目采用 MIT 许可证。
联系方式
如有问题或建议,欢迎提交 Issue 或 Pull Request。
Jog System - 简洁、安全、现代化的博客系统
Description
Languages
Java
72.7%
Vue
20.7%
JavaScript
5.5%
CSS
1%