
30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度很多同学在准备毕业设计或者面试项目时常常苦于找不到一个结构清晰、技术栈主流、能跑起来的完整项目。自己从零搭建又耗时耗力网上找到的源码要么环境复杂要么依赖缺失跑起来一堆报错。今天分享一个基于 SpringBoot 3 和 Vue 3 的博客管理系统这是一个典型的前后端分离项目涵盖了用户管理、文章发布、分类标签、评论等核心功能。项目结构清晰代码规范依赖完整半小时内就能在你的本地环境成功运行。无论是用于学习前后端分离架构还是作为毕业设计、丰富个人简历都是一个非常不错的选择。本文将手把手带你完成从环境准备、项目导入、数据库配置到前后端启动的全过程并提供完整的源码获取方式。即使你是刚接触 SpringBoot 或 Vue 3 的新手也能跟着步骤顺利搭建。1. 项目概述与技术栈1.1 什么是博客管理系统博客管理系统Blog Management System是一个用于创建、发布、管理和展示网络文章博客的Web应用。它通常包含后台管理界面供作者操作以及前台页面供读者浏览。一个完整的博客系统通常具备以下核心模块用户认证与授权管理员登录、权限控制。文章管理文章的增、删、改、查CRUD。分类与标签管理对文章进行归类。评论管理用户对文章的评论与回复。数据统计简单的文章浏览数、评论数统计。1.2 为什么选择 SpringBoot Vue3 前后端分离SpringBoot作为Java后端开发的“事实标准”它极大地简化了Spring应用的初始搭建和开发过程内嵌Tomcat提供自动配置和起步依赖让开发者能快速构建独立、生产级的应用。Vue 3是当前最主流的前端框架之一相比于Vue 2它在性能基于Proxy的响应式系统、TypeScript支持、组合式API等方面有显著提升开发体验更好更适合构建现代复杂的单页面应用SPA。前后端分离这是一种现代化的架构模式。后端SpringBoot专注于提供RESTful API处理业务逻辑和数据持久化前端Vue 3负责页面渲染和用户交互。两者通过HTTP接口通常是JSON格式进行通信。这种架构的好处是职责清晰、便于并行开发、前端可以独立部署且后端API可以被多种客户端Web、移动端复用。本项目的完整技术栈如下后端SpringBoot 3.x, Spring Security安全框架, JWT令牌认证, MyBatis-Plus数据访问层增强, MySQL, Maven。前端Vue 3, Vue Router路由, Pinia状态管理, Element PlusUI组件库, AxiosHTTP客户端, Vite构建工具。开发工具IntelliJ IDEA后端, Visual Studio Code前端, Navicat或DBeaver数据库。2. 环境准备与项目结构在开始之前请确保你的本地开发环境已就绪。2.1 必备软件安装JDK版本 17 或以上。SpringBoot 3.x 需要 JDK 17 的支持。安装后配置好JAVA_HOME环境变量。Node.js版本 16 或以上推荐 LTS 版本。它将同时安装 npmNode包管理器。安装后可以在命令行输入node -v和npm -v检查。Maven版本 3.6 或以上。用于管理后端项目的依赖和构建。安装后配置好MAVEN_HOME环境变量并添加bin目录到PATH。MySQL版本 5.7 或 8.0。用于数据存储。请记住你安装时设置的 root 用户密码。IDE后端IntelliJ IDEA社区版或旗舰版。前端Visual Studio Code并安装 Vue 官方扩展Volar。2.2 获取项目源码你可以通过提供的链接或网盘地址获取完整的项目源码压缩包。解压后你会看到类似如下的目录结构blog-system/ ├── blog-backend/ # SpringBoot 后端项目 │ ├── src/ │ │ ├── main/ │ │ │ ├── java/com/example/blog/ │ │ │ │ ├── config/ # 配置类安全、跨域等 │ │ │ │ ├── controller/ # 控制器接收请求返回响应 │ │ │ │ ├── entity/ # 实体类对应数据库表 │ │ │ │ ├── mapper/ # MyBatis-Plus 的 Mapper 接口 │ │ │ │ ├── service/ # 业务逻辑层接口和实现 │ │ │ │ └── utils/ # 工具类JWT、响应封装等 │ │ │ └── resources/ │ │ │ ├── application.yml # 主配置文件 │ │ │ └── mapper/ # MyBatis XML 映射文件如有 │ │ └── test/ │ └── pom.xml # Maven 项目对象模型管理依赖 └── blog-frontend/ # Vue 3 前端项目 ├── public/ # 静态资源 ├── src/ │ ├── api/ # 封装所有后端 API 请求 │ ├── assets/ # 图片、样式等资源 │ ├── components/ # 可复用的 Vue 组件 │ ├── router/ # Vue Router 路由配置 │ ├── stores/ # Pinia 状态管理 │ ├── utils/ # 前端工具函数 │ ├── views/ # 页面视图组件 │ ├── App.vue # 根组件 │ └── main.js # 应用入口文件 ├── .env.development # 开发环境变量 ├── .env.production # 生产环境变量 ├── index.html # 主 HTML 文件 ├── package.json # 项目依赖和脚本 └── vite.config.js # Vite 构建配置这个结构清晰地展示了前后端分离的物理划分是理解项目的第一步。3. 后端项目配置与启动3.1 数据库初始化打开你的 MySQL 客户端如命令行、Navicat。创建一个新的数据库字符集建议使用utf8mb4排序规则使用utf8mb4_general_ci。CREATE DATABASE blog_db CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;在项目的blog-backend/src/main/resources目录下找到schema.sql文件如果项目提供了。这个文件包含了创建所有表的 SQL 语句。在 MySQL 客户端中执行这个文件。如果没有提供通常项目会在首次启动时通过 MyBatis-Plus 的自动建表功能或 Flyway/Liquibase 来初始化这需要在application.yml中配置。3.2 修改后端配置文件后端项目的核心配置在application.yml中。你需要根据你的本地环境修改以下几处关键配置# blog-backend/src/main/resources/application.yml server: port: 8080 # 后端服务启动端口 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver # 修改为你本地的MySQL连接信息数据库名、用户名、密码 url: jdbc:mysql://localhost:3306/blog_db?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai username: root password: your_mysql_password # 替换为你的密码 jackson: time-zone: GMT8 date-format: yyyy-MM-dd HH:mm:ss # MyBatis-Plus 配置 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台输出SQL调试用 global-config: db-config: logic-delete-field: isDeleted # 全局逻辑删除字段名如果实体类有 logic-delete-value: 1 # 逻辑已删除值 logic-not-delete-value: 0 # 逻辑未删除值 # JWT 配置示例具体密钥需修改 jwt: secret: yourSuperSecretKeyHereChangeThisToSomethingLongAndRandom # JWT签名密钥务必修改 expiration: 604800 # token有效期秒7天 header: Authorization特别注意jwt.secret是一个用于签名和验证 JWT Token 的密钥在生产环境中必须使用足够复杂且保密的字符串绝对不要使用示例中的值。3.3 导入并启动后端项目使用 IntelliJ IDEA 打开blog-backend文件夹。IDEA 会自动识别为 Maven 项目并开始下载依赖观察右下角进度条。如果网络较慢可以配置 Maven 使用国内镜像源。依赖下载完成后找到主启动类通常位于src/main/java/com/example/blog/BlogApplication.java类名可能不同但会有SpringBootApplication注解。右键点击这个类选择Run ‘BlogApplication’。观察控制台输出如果没有报错并看到类似Tomcat started on port(s): 8080和Started BlogApplication in X.XXX seconds的日志说明后端启动成功。你可以在浏览器中访问http://localhost:8080/doc.html如果集成了 Knife4j/Swagger来查看和测试后端 API 接口。4. 前端项目配置与启动4.1 安装前端依赖前端项目使用 npm 管理依赖。在启动前需要先安装所有依赖包。使用 VS Code 打开blog-frontend文件夹。打开 VS Code 的终端Terminal - New Terminal。在终端中确保当前路径在前端项目根目录下然后执行安装命令npm install # 或使用淘宝镜像加速 # cnpm install这个命令会根据package.json文件下载所有需要的库如 Vue、Element Plus、Axios等到node_modules目录。4.2 修改前端环境配置前端需要知道后端 API 的地址。配置通常在环境变量文件中。打开blog-frontend/.env.development文件开发环境配置。修改VITE_API_BASE_URL变量指向你刚刚启动的后端服务地址和端口。# .env.development VITE_API_BASE_URLhttp://localhost:8080/api这里假设你的后端 API 统一以/api开头。请根据你后端controller的实际路径进行调整。4.3 启动前端开发服务器依赖安装完成后就可以启动前端开发服务器了。在 VS Code 的终端中仍在项目根目录运行启动命令npm run dev命令执行后终端会输出本地访问地址通常是http://localhost:5173Vite 默认端口。打开浏览器访问这个地址如http://localhost:5173。你应该能看到博客系统的前端登录或首页界面。至此前后端服务都已成功启动一个完整的博客管理系统已经在你的本地运行起来了5. 核心功能模块代码详解为了让项目不只是“跑起来”更能“学明白”我们深入看几个核心模块的代码实现。5.1 后端用户登录与JWT认证这是前后端分离项目的安全基石。流程是用户提交用户名密码 - 后端验证 - 生成JWT Token返回 - 前端存储Token并在后续请求中携带。1. 实体类 (User.java)// blog-backend/src/main/java/com/example/blog/entity/User.java package com.example.blog.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.time.LocalDateTime; Data TableName(sys_user) // 对应数据库表名 public class User { TableId(type IdType.AUTO) // 主键自增 private Long id; private String username; // 用户名 private String password; // 加密后的密码 private String nickname; // 昵称 private String avatar; // 头像地址 private String email; private Integer status; // 状态 0-正常 1-禁用 TableField(fill FieldFill.INSERT) // 插入时自动填充 private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) // 插入和更新时自动填充 private LocalDateTime updateTime; }2. 登录接口 (AuthController.java)// blog-backend/src/main/java/com/example/blog/controller/AuthController.java package com.example.blog.controller; import com.example.blog.common.Result; import com.example.blog.entity.User; import com.example.blog.service.UserService; import com.example.blog.utils.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; RestController RequestMapping(/api/auth) public class AuthController { Autowired private UserService userService; Autowired private JwtUtil jwtUtil; PostMapping(/login) public Result login(RequestBody MapString, String loginForm) { String username loginForm.get(username); String password loginForm.get(password); // 1. 验证用户名密码 User user userService.login(username, password); if (user null) { return Result.error(用户名或密码错误); } // 2. 生成JWT Token String token jwtUtil.generateToken(user.getId().toString(), user.getUsername()); // 3. 返回用户信息和Token MapString, Object data new HashMap(); data.put(user, user); data.put(token, token); return Result.success(登录成功, data); } }3. JWT工具类 (JwtUtil.java) - 核心片段// blog-backend/src/main/java/com/example/blog/utils/JwtUtil.java package com.example.blog.utils; import io.jsonwebtoken.*; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.Date; Component public class JwtUtil { Value(${jwt.secret}) private String secret; // 从配置文件中注入密钥 Value(${jwt.expiration}) private Long expiration; // 有效期 // 生成Token public String generateToken(String userId, String username) { Date now new Date(); Date expiryDate new Date(now.getTime() expiration * 1000); return Jwts.builder() .setSubject(userId) .claim(username, username) // 自定义声明 .setIssuedAt(now) .setExpiration(expiryDate) .signWith(SignatureAlgorithm.HS512, secret) // 使用HS512算法和密钥签名 .compact(); } // 验证并解析Token public Claims parseToken(String token) { return Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody(); } // ... 其他方法验证Token是否过期、获取用户信息等 }5.2 前端请求封装与状态管理前端需要统一管理API请求和用户登录状态。1. Axios请求拦截器 (request.js)// blog-frontend/src/utils/request.js import axios from axios; import { ElMessage } from element-plus; import { useUserStore } from /stores/user; // Pinia store // 创建axios实例 const service axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, // 读取环境变量中的基础URL timeout: 10000, // 请求超时时间 }); // 请求拦截器在发送请求前统一处理例如添加Token service.interceptors.request.use( (config) { const userStore useUserStore(); if (userStore.token) { // 如果存在token将其添加到请求头中 config.headers[Authorization] Bearer ${userStore.token}; } return config; }, (error) { console.error(Request Error:, error); return Promise.reject(error); } ); // 响应拦截器统一处理响应数据或错误 service.interceptors.response.use( (response) { const res response.data; // 假设后端统一返回格式为 { code: 200, message: success, data: ... } if (res.code 200) { return res.data; // 直接返回业务数据 } else { // 业务逻辑错误例如密码错误 ElMessage.error(res.message || Error); return Promise.reject(new Error(res.message || Error)); } }, (error) { // HTTP状态码错误例如 401, 404, 500 console.error(Response Error:, error.response); if (error.response error.response.status 401) { ElMessage.error(登录已过期请重新登录); // 触发登出逻辑清空token和用户信息跳转到登录页 const userStore useUserStore(); userStore.logout(); window.location.href /login; } else { ElMessage.error(error.response?.data?.message || 网络请求失败); } return Promise.reject(error); } ); export default service;2. Pinia状态管理 - 用户Store (user.js)// blog-frontend/src/stores/user.js import { defineStore } from pinia; import { loginApi, getUserInfoApi, logoutApi } from /api/user; // 引入API import { removeToken, setToken } from /utils/auth; // 假设有操作token的工具函数 export const useUserStore defineStore(user, { state: () ({ token: localStorage.getItem(token) || , // 从本地存储初始化 userInfo: JSON.parse(localStorage.getItem(userInfo) || {}), }), actions: { // 登录动作 async login(loginForm) { try { const res await loginApi(loginForm); this.token res.token; this.userInfo res.user; // 持久化到本地存储 setToken(res.token); localStorage.setItem(userInfo, JSON.stringify(res.user)); return Promise.resolve(res); } catch (error) { return Promise.reject(error); } }, // 获取用户信息 async getUserInfo() { if (!this.token) return; try { const res await getUserInfoApi(); this.userInfo res; localStorage.setItem(userInfo, JSON.stringify(res)); } catch (error) { // 获取失败可能是token失效 this.logout(); } }, // 登出动作 logout() { this.token ; this.userInfo {}; removeToken(); localStorage.removeItem(userInfo); // 可以调用后端登出API // logoutApi(); }, }, });5.3 文章管理功能实现文章管理是博客的核心涉及前后端协作的完整CRUD流程。1. 后端文章接口 (ArticleController.java)// blog-backend/src/main/java/com/example/blog/controller/ArticleController.java package com.example.blog.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.example.blog.common.Result; import com.example.blog.entity.Article; import com.example.blog.service.ArticleService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/api/article) public class ArticleController { Autowired private ArticleService articleService; // 新增或更新文章 PostMapping public Result saveOrUpdate(RequestBody Article article) { // 这里可以加入权限校验例如只有作者本人或管理员可以操作 boolean success articleService.saveOrUpdate(article); return success ? Result.success(操作成功) : Result.error(操作失败); } // 分页查询文章列表 GetMapping(/page) public Result findPage(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(defaultValue ) String title) { PageArticle page new Page(pageNum, pageSize); LambdaQueryWrapperArticle queryWrapper new LambdaQueryWrapper(); queryWrapper.like(!title.isEmpty(), Article::getTitle, title); // 标题模糊查询 queryWrapper.orderByDesc(Article::getCreateTime); // 按创建时间倒序 IPageArticle pageResult articleService.page(page, queryWrapper); return Result.success(pageResult); } // 根据ID查询文章详情 GetMapping(/{id}) public Result getById(PathVariable Long id) { Article article articleService.getById(id); if (article ! null) { // 可以在这里增加浏览数等逻辑 return Result.success(article); } return Result.error(文章不存在); } // 根据ID删除文章逻辑删除 DeleteMapping(/{id}) public Result delete(PathVariable Long id) { boolean success articleService.removeById(id); return success ? Result.success(删除成功) : Result.error(删除失败); } }2. 前端文章列表页面 (ArticleList.vue)!-- blog-frontend/src/views/article/ArticleList.vue -- template div classarticle-list div classheader el-input v-modelsearchForm.title placeholder请输入文章标题 stylewidth: 300px; keyup.enterhandleSearch template #append el-button :iconSearch clickhandleSearch / /template /el-input el-button typeprimary :iconPlus clickhandleAdd新增文章/el-button /div el-table :datatableData stylewidth: 100% v-loadingloading el-table-column propid labelID width80 / el-table-column proptitle label标题 show-overflow-tooltip / el-table-column propcategoryName label分类 width120 / el-table-column propviewCount label浏览 width80 / el-table-column propcreateTime label创建时间 width180 template #defaultscope {{ formatDate(scope.row.createTime) }} /template /el-table-column el-table-column label操作 width200 fixedright template #defaultscope el-button typeprimary link :iconView clickhandleView(scope.row)查看/el-button el-button typeprimary link :iconEdit clickhandleEdit(scope.row)编辑/el-button el-button typedanger link :iconDelete clickhandleDelete(scope.row)删除/el-button /template /el-table-column /el-table div classpagination el-pagination v-model:current-pagepageParams.pageNum v-model:page-sizepageParams.pageSize :page-sizes[10, 20, 50, 100] :totaltotal layouttotal, sizes, prev, pager, next, jumper size-changehandleSizeChange current-changehandleCurrentChange / /div !-- 新增/编辑对话框 -- ArticleDialog v-modeldialogVisible :form-datacurrentArticle successhandleDialogSuccess / /div /template script setup import { ref, reactive, onMounted } from vue; import { Search, Plus, View, Edit, Delete } from element-plus/icons-vue; import { ElMessage, ElMessageBox } from element-plus; import { getArticlePageApi, deleteArticleApi } from /api/article; import ArticleDialog from ./components/ArticleDialog.vue; import { formatDate } from /utils/date; const loading ref(false); const tableData ref([]); const total ref(0); const dialogVisible ref(false); const currentArticle ref({}); // 查询条件 const searchForm reactive({ title: , }); // 分页参数 const pageParams reactive({ pageNum: 1, pageSize: 10, }); // 获取文章列表 const fetchData async () { loading.value true; try { const params { ...pageParams, ...searchForm, }; const res await getArticlePageApi(params); tableData.value res.records; total.value res.total; } catch (error) { console.error(获取文章列表失败:, error); } finally { loading.value false; } }; // 搜索 const handleSearch () { pageParams.pageNum 1; // 搜索时回到第一页 fetchData(); }; // 分页大小变化 const handleSizeChange (val) { pageParams.pageSize val; fetchData(); }; // 当前页变化 const handleCurrentChange (val) { pageParams.pageNum val; fetchData(); }; // 新增 const handleAdd () { currentArticle.value {}; dialogVisible.value true; }; // 编辑 const handleEdit (row) { currentArticle.value { ...row }; dialogVisible.value true; }; // 查看 const handleView (row) { // 跳转到文章详情页传递文章ID // router.push(/article/detail/${row.id}); }; // 删除 const handleDelete (row) { ElMessageBox.confirm(确定要删除文章“${row.title}”吗, 提示, { confirmButtonText: 确定, cancelButtonText: 取消, type: warning, }).then(async () { try { await deleteArticleApi(row.id); ElMessage.success(删除成功); fetchData(); // 刷新列表 } catch (error) { ElMessage.error(删除失败); } }).catch(() {}); }; // 对话框操作成功后的回调 const handleDialogSuccess () { dialogVisible.value false; fetchData(); // 刷新列表 }; onMounted(() { fetchData(); }); /script style scoped .article-list { padding: 20px; } .header { display: flex; justify-content: space-between; margin-bottom: 20px; } .pagination { margin-top: 20px; display: flex; justify-content: flex-end; } /style6. 项目部署与打包本地开发完成后你可能需要将项目打包部署到服务器或用于演示。6.1 后端打包 (SpringBoot)SpringBoot项目使用Maven打包非常方便会生成一个可执行的Jar文件。在blog-backend目录下打开终端。执行Maven打包命令mvn clean package -DskipTestsclean清理旧的构建文件。package打包项目。-DskipTests跳过测试加快打包速度。打包成功后在target目录下会生成一个blog-backend-0.0.1-SNAPSHOT.jar名称可能不同的文件。你可以将这个Jar文件上传到服务器使用java -jar blog-backend-0.0.1-SNAPSHOT.jar命令运行。生产环境建议使用nohup或配置为系统服务。6.2 前端打包 (Vue 3)Vue项目需要打包成静态文件HTML, JS, CSS然后由Nginx等Web服务器托管。在blog-frontend目录下打开终端。首先修改生产环境配置文件.env.production将API地址指向你的线上后端服务地址。# .env.production VITE_API_BASE_URLhttps://your-domain.com/api执行打包命令npm run build命令执行完毕后会在项目根目录下生成一个dist文件夹里面就是打包好的所有静态资源。将dist文件夹内的所有文件上传到你的Web服务器如Nginx的网站根目录并配置Nginx将所有非静态文件请求重定向到index.html用于支持Vue Router的history模式。Nginx配置示例server { listen 80; server_name your-domain.com; # 你的域名 root /path/to/your/dist; # dist文件夹的绝对路径 location / { try_files $uri $uri/ /index.html; # 关键配置支持前端路由 } # 代理后端API请求解决跨域问题如果前后端不同域 location /api/ { proxy_pass http://localhost:8080/api/; # 代理到后端服务 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }7. 常见问题与解决方案 (FAQ)在搭建和运行过程中你可能会遇到以下问题问题现象可能原因解决方案后端启动失败端口被占用8080端口已被其他程序如另一个Tomcat使用。1. 在application.yml中修改server.port为其他端口如 8081。2. 在命令行查找占用端口的进程并结束它Windows:netstat -ano | findstr :8080Linux/Mac:lsof -i :8080。前端npm install失败网络超时npm默认源在国外网络不稳定。1. 使用淘宝镜像npm config set registry https://registry.npmmirror.com然后重试。2. 使用cnpm命令。前端访问localhost:5173报错无法连接到后端API前端配置的API地址 (VITE_API_BASE_URL) 错误或后端服务未启动。1. 检查后端服务是否在localhost:8080正常运行。2. 检查blog-frontend/.env.development文件中的VITE_API_BASE_URL是否正确指向后端地址和端口。登录成功但进行其他操作如新增文章时提示“未授权”或“Token无效”前端没有正确在请求头中携带Token或后端Token验证失败。1. 检查前端request.js中的请求拦截器是否从Pinia store或localStorage正确获取了token并添加到Authorization头。2. 检查后端JWT配置的secret是否一致Token是否已过期。数据库连接失败MySQL服务未启动或application.yml中的数据库连接信息url, username, password错误。1. 确保MySQL服务已启动。2. 仔细核对application.yml中的数据库名、用户名和密码。3. 检查MySQL用户是否有远程连接权限如果数据库不在本机。前端页面样式错乱Element Plus组件不显示Element Plus组件未正确引入或注册。1. 检查package.json中是否有element-plus依赖。2. 检查是否在main.js或按需导入的配置文件中正确引入了Element Plus及其样式。打包后前端页面空白或路由失效1. 静态资源路径错误。2. 未配置Nginx的try_files规则。1. 检查vite.config.js中是否配置了正确的base如果项目部署在子路径。2. 确保Web服务器如Nginx正确配置了将所有路由重定向到index.html。8. 项目扩展与优化建议这个基础项目已经具备了核心功能但如果你想将其用于更复杂的场景或作为毕业设计的亮点可以考虑以下扩展方向增加文章审核与发布状态为文章添加status字段如草稿、待审核、已发布、已拒绝并实现管理员审核流程。实现文章点赞、收藏功能新建like和favorite表记录用户与文章的互动关系。引入富文本编辑器将简单的文本框替换为功能强大的富文本编辑器如WangEditor、TinyMCE或Quill支持图片上传、代码高亮等。添加文章SEO优化为每篇文章生成独立的、对搜索引擎友好的URLSlug并自动生成description和keywords的meta标签。实现文件上传服务将用户上传的头像、文章图片存储到对象存储如阿里云OSS、腾讯云COS或本地服务器并做好文件管理。集成第三方登录使用 OAuth 2.0 协议接入微信、QQ、Github 等第三方登录方式。加入缓存机制对于首页文章列表、热门文章等不常变的数据使用 Redis 进行缓存显著提升访问速度。完善后台权限管理使用 RBAC基于角色的访问控制模型细化权限例如区分文章作者、栏目管理员、系统管理员等角色。前端性能优化路由懒加载在router/index.js中使用() import(‘…’)语法实现组件按需加载。图片懒加载对于长列表中的图片使用Intersection Observer API或vue-lazyload插件。API请求防抖/节流对搜索框等频繁触发请求的场景进行优化。容器化部署编写Dockerfile和docker-compose.yml文件将前后端和数据库容器化实现一键部署这会是简历上的一大亮点。这个 SpringBoot Vue 3 博客管理系统项目从技术选型到代码结构都符合当前企业级开发的主流实践。通过亲手搭建和深入研究其中的代码你不仅能掌握前后端分离开发的完整流程更能深入理解用户认证、状态管理、组件化开发、RESTful API设计等核心概念。 30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度