这次我们来看一个特别适合毕设、简历项目和前后端分离入门的实战项目:基于 SpringBoot + Vue3 的个人博客管理系统。
这个项目的价值不在于概念多新,而在于它把一条完整的技术链路跑通了:SpringBoot 提供后端 REST API,Vue3 + Vite 提供前端页面,MySQL 做数据持久化,再配合一套标准的管理后台,实现文章发布、分类管理、标签管理、评论管理等日常功能。对外展示端和管理后台都齐全,增删改查全覆盖,还带完整源码和项目文档,拿来写课程设计、毕业设计,或者作为面试项目去讲,都很合适。
如果你正在找 SpringBoot + Vue3 的前后端分离项目实战素材,或者想快速掌握前后端联调、数据库增删改查这些核心套路,这篇文章可以直接收藏。下面我按“项目能做什么 -> 环境准备 -> 启动部署 -> 功能验证 -> 接口测试 -> 常见排查 -> 工程建议”的顺序,把整套系统的落地过程拆开讲清楚。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | 前后端分离的个人博客管理系统 |
| 后端技术栈 | SpringBoot、MyBatis-Plus(或 JPA,以实际源码为准)、MySQL |
| 前端技术栈 | Vue3、Vite、Vue Router、Pinia、Element Plus 等 |
| 主要功能 | 文章增删改查、分类管理、标签管理、评论管理、用户登录、个人中心 |
| 包含内容 | 完整源码、项目文档、数据库初始化脚本 |
| 启动方式 | 后端 Maven 启动 + 前端 npm 启动 |
| 是否支持接口 API | 是,后端提供 RESTful 风格接口 |
| 是否支持批量任务 | 基础版支持批量删除,可自行扩展批量导入 |
| 推荐硬件 | 普通开发机即可运行,内存 8G 以上更稳 |
| 适合场景 | 毕设、课设、简历项目、前后端分离入门学习 |
从材料看,这个项目主打的是“全流程可跑通、增删改查全覆盖、带文档”。它的优势不一定是某条技术用得多深,而是结构完整、上手成本低,适合快速积累一个能讲清楚、能演示、能扩展的实战项目。
2. 适用场景与使用边界
这个项目适合三类人。第一类是准备毕业设计的学生,博客管理系统是一个经典题目,功能边界清晰、评审容易理解、工作量适中,不太容易出现“题目太大做不完”的情况。第二类是正在找工作的 Java 开发新人,简历上写“基于 SpringBoot + Vue3 的前后端分离博客系统”,比只写框架技术栈要具体得多,面试时可以从表结构设计、接口设计、分页查询、登录鉴权、部署方式等多个方向展开。第三类是刚学完 SpringBoot 和 Vue3 基础、想找一个完整项目练手的开发者,通过这个项目能看到一整套真实项目的代码组织方式,而不是孤立的 CRUD 示例。
能解决的问题也很明确:前端页面如何调后端接口、后端数据如何返回 JSON、数据库表怎么设计、文件上传怎么处理、登录状态怎么校验、项目如何打包部署,这些都是实际项目中逃不开的问题。
但要注意使用边界。这个项目不应该直接当生产系统去部署,毕竟个人博客系统的并发量、安全防护、数据备份方案和正式站点还有差距。如果是上线使用,需要自己补上 HTTPS、密码加密加强、接口限流、图片 CDN、日志监控这些能力。另外,如果用来做毕设或简历项目,建议自己把代码完整过一遍,尤其是表设计和接口实现,避免在答辩或面试时被问到细节却答不上来。
还有一个合规提示:博客系统涉及用户发布内容和评论,如果你后续用它做公共访问,需要考虑内容审核机制,避免出现违规内容;如果导入他人文章作为演示数据,请确保内容有授权或使用自己的原创内容。图像、字体、素材等资源也要注意版权。
3. 环境准备与前置条件
部署这套系统前,先确认本机环境。不同版本的 SpringBoot 对 JDK 的要求不同:SpringBoot 2.x 通常需要 JDK 8 或 JDK 11,SpringBoot 3.x 需要 JDK 17。Vue3 + Vite 项目对 Node.js 版本也有要求,一般建议 Node.js 16 以上,部分较新的 Vite 版本要求 Node.js 18 或 20。
| 环境项 | 建议配置 |
|---|---|
| JDK | 8 / 11 / 17,根据 SpringBoot 版本选择 |
| Maven | 3.6 以上 |
| Node.js | 16 / 18 / 20,推荐 LTS |
| 包管理器 | npm 或 pnpm |
| MySQL | 5.7 / 8.0 |
| 数据库客户端 | Navicat、DataGrip 或命令行均可 |
| IDE | IntelliJ IDEA 或 VS Code |
| 内存 | 8G 以上,普通开发本足够 |
| 磁盘空间 | 预留 5G 以上,包含依赖下载和构建产物 |
如果你打开项目发现 SpringBoot 版本太高导致配置项不兼容,可以先检查项目里的pom.xml,确认 SpringBoot 父依赖版本,再决定使用哪个 JDK。Vue3 项目如果出现 Vite 或 Node 版本不匹配,优先检查package.json里的 Vite 版本和本地 Node 版本。
启动前先用下面几条命令确认环境版本。
java -version mvn -v node -v npm -v mysql --version如果命令能正常输出版本号,环境基本没问题。如果某个命令提示“无法识别”,说明对应软件没有安装或没有配置环境变量,先补齐再继续。
MySQL 侧需要提前建好数据库。通常项目源码里会带上blog.sql或schema.sql之类的初始化脚本,执行一次即可创建数据库表和基础数据。如果没有脚本,也可以自己设计表,后面我会给出一个常见的表结构参考。
4. 安装部署与启动方式
4.1 获取源码与目录结构
拿到源码后,先看目录结构。典型的前后端分离项目会分成两个子目录:
blog-system/ ├── backend/ # SpringBoot 后端工程 │ ├── src/ │ ├── pom.xml │ └── sql/ └── frontend/ # Vue3 前端工程 ├── src/ ├── index.html └── package.json后端工程通常包含controller、service、mapper、entity、config等包,前端工程包含api、views、components、router、store等目录。先把整体结构看一遍,再逐个模块打开,启动顺序建议是:先启动 MySQL 并导入数据,再启动后端服务,最后启动前端开发服务器。
4.2 创建数据库并导入初始化脚本
在 MySQL 中创建一个数据库,例如blog_db:
CREATE DATABASE IF NOT EXISTS blog_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;然后使用数据库客户端导入项目提供的 SQL 初始化脚本。如果没有现成脚本,可以参考下面这套最小表结构设计。
-- 用户表 CREATE TABLE `sys_user` ( `id` bigint NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL, `password` varchar(100) NOT NULL, `nickname` varchar(50) DEFAULT NULL, `avatar` varchar(255) DEFAULT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 文章分类表 CREATE TABLE `blog_category` ( `id` bigint NOT NULL AUTO_INCREMENT, `category_name` varchar(50) NOT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 文章标签表 CREATE TABLE `blog_tag` ( `id` bigint NOT NULL AUTO_INCREMENT, `tag_name` varchar(50) NOT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 文章表 CREATE TABLE `blog_article` ( `id` bigint NOT NULL AUTO_INCREMENT, `title` varchar(200) NOT NULL, `summary` varchar(500) DEFAULT NULL, `content` longtext, `cover_image` varchar(255) DEFAULT NULL, `category_id` bigint DEFAULT NULL, `status` tinyint DEFAULT 1 COMMENT '1:发布 0:草稿', `view_count` int DEFAULT 0, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 文章标签关联表 CREATE TABLE `blog_article_tag` ( `article_id` bigint NOT NULL, `tag_id` bigint NOT NULL, PRIMARY KEY (`article_id`, `tag_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 评论表 CREATE TABLE `blog_comment` ( `id` bigint NOT NULL AUTO_INCREMENT, `article_id` bigint NOT NULL, `user_id` bigint DEFAULT NULL, `content` varchar(1000) NOT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;这套表结构覆盖了文章、分类、标签、评论和用户五个核心模块,标签表和文章表通过中间表关联,是博客系统比较典型的设计方式。表名和字段名以实际源码为准,这里给出的是通用参考。
4.3 修改后端配置文件
导入数据后,打开后端工程的application.yml或application.properties,修改数据库连接信息。重点确认数据库 URL、用户名、密码。
server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/blog_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml type-aliases-package: com.example.blog.entity如果你的 MySQL 是 5.7,需要确认driver-class-name是否兼容;如果后端用了 SpringBoot 3 和 MySQL 8,驱动一般使用com.mysql.cj.jdbc.Driver。配置里的密码一定要改成自己本机 MySQL 的实际密码,否则后端起不来。
4.4 启动后端服务
进入后端工程目录,使用 Maven 启动:
cd backend mvn spring-boot:run也可以先打包再运行:
mvn clean package -DskipTests java -jar target/blog-backend.jar启动后看到类似Tomcat started on port 8080的日志,说明后端服务已经起来了。这时可以先用浏览器访问一个简单的接口地址,例如http://localhost:8080/api/article/list,看是否能返回 JSON 数据。
4.5 安装前端依赖并启动 Vite 开发服务器
打开一个新的终端窗口,进入前端目录:
cd frontend npm install npm run dev如果npm install速度较慢,可以切换到国内镜像源:
npm config set registry https://registry.npmmirror.com依赖安装完成后,npm run dev会启动 Vite 开发服务器,默认端口一般是5173。启动成功后,终端会显示本地访问地址,例如http://localhost:5173。
4.6 启动后的访问路径
打开浏览器访问http://localhost:5173,正常情况下可以看到博客系统的前台页面或后台登录页。如果你的后端端口不是 8080,或者开发环境配置了不同的接口前缀,需要检查前端src/api目录下的请求封装,确认baseURL指向正确。
常见的前后端分离联调方式是:前端开发服务器通过 Vite 代理转发请求到后端。在vite.config.js里添加代理:
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], server: { host: '0.0.0.0', port: 5173, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } })配置好代理后,前端里所有以/api开头的请求都会被转发到后端,不需要在前端代码里写死完整的后端地址,联调阶段会省很多事。
5. 功能测试与效果验证
系统启动后,按照下面的功能测试流程逐个验证。这里以“文章管理”为主线,覆盖登录、新增、查询、编辑、删除等增删改查核心操作。
5.1 登录与权限管理测试
测试目的:确认用户登录接口可用,登录状态能被正确记录。
操作步骤:在浏览器打开后台登录页,输入管理员账号和密码,点击登录。
预期结果:登录成功后跳转到后台首页,页面右上角显示当前用户昵称。
判断成功的标准:刷新页面后登录状态仍然保持,说明 token 或 session 机制生效。如果刷新后跳回登录页,说明登录状态没有持久化,需要检查后端的 token 校验逻辑或前端的路由守卫配置。
5.2 文章新增测试
测试目的:验证文章内容能否正常写入数据库,分类、标签等关联关系是否正确保存。
操作步骤:在后台管理里选择“文章管理 -> 新增文章”,填写标题、摘要、正文内容,选择分类和标签,点击发布。
预期结果:提示保存成功,文章列表出现新记录,数据库blog_article表中可以看到对应数据行。
判断成功的标准:文章详情页可以正常渲染内容,标题、封面、摘要显示正确。如果发布后列表查不到,重点排查状态字段是否写成了草稿,或前端列表接口没有加状态过滤条件。
5.3 文章列表和分页查询测试
测试目的:确认分页查询功能正常,数据量变大时能按页加载。
操作步骤:在文章列表页面切换页码、修改每页条数、按标题关键字搜索。
预期结果:列表只显示当前页数据,总数和页码渲染正确,关键字搜索能过滤出匹配结果。
判断成功的标准:后端返回的 JSON 中包含total、records、current、size等分页字段。如果分页失效,看一下后端是否配置了分页插件,以及前端是否正确传入了pageNum和pageSize参数。
5.4 文章编辑测试
测试目的:验证回显和更新功能。
操作步骤:在文章列表选择一篇文章,点击编辑,确认表单能正确回显原数据,修改正文后保存。
预期结果:修改内容后列表立即更新,详情页展示修改后的内容。
判断成功的标准:数据库update_time字段自动刷新。如果回显失败,一般是接口路径没有传对 id 参数,或者前端配置的编辑页面路由缺少动态参数。
5.5 删除与回收站测试
测试目的:验证物理删除和逻辑删除的差异。
操作步骤:在文章列表点击删除,确认记录从列表中消失。
预期结果:如果是逻辑删除,数据库记录仍在但status被修改;如果是物理删除,记录直接消失。
判断成功的标准:删除后列表刷新无报错,关联的标签中间表记录也被清理。如果使用 MyBatis-Plus 的逻辑删除功能,需要在实体类的删除字段上加上@TableLogic注解,并且查询时框架会自动拼接deleted = 0条件。
5.6 分类、标签、评论模块测试
测试目的:验证关联模块的增删改查是否正常。
操作步骤:新增一个分类,给文章设置标签,在文章详情页或后台评论管理里添加评论。
预期结果:分类列表、标签列表都能与文章正常关联,评论能在文章详情页展示。
判断成功的标准:数据库关联表中能查到对应数据,前端页面联动显示正常。这里有一个常见问题:删除分类时如果该分类下还有文章,建议提示“请先处理该分类下的文章”,防止产生悬空数据。
6. 接口 API 与批量任务
这个项目后端提供的是 RESTful 风格接口。下面给出一个通用的接口设计模板,具体路径和参数需要按项目源码调整。
6.1 核心接口示例
| 功能 | 请求方式 | 接口路径 |
|---|---|---|
| 获取文章分页列表 | GET | /api/article/list |
| 获取文章详情 | GET | /api/article/{id} |
| 新增文章 | POST | /api/article |
| 编辑文章 | PUT | /api/article |
| 删除文章 | DELETE | /api/article/{id} |
| 获取分类列表 | GET | /api/category/list |
| 获取评论列表 | GET | /api/comment/list |
| 用户登录 | POST | /api/auth/login |
6.2 后端 Controller 模板
后端代码的分层思路是 Controller 接收请求 -> Service 处理业务逻辑 -> Mapper 操作数据库。新增文章的 Controller 大致是这样的:
@RestController @RequestMapping("/api/article") public class ArticleController { @Resource private ArticleService articleService; @PostMapping public Result save(@RequestBody Article article) { boolean success = articleService.saveOrUpdate(article); return success ? Result.success() : Result.error("保存失败"); } @GetMapping("/list") public Result page(@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(required = false) String keyword) { return Result.success(articleService.pageQuery(pageNum, pageSize, keyword)); } @DeleteMapping("/{id}") public Result delete(@PathVariable Long id) { boolean success = articleService.removeById(id); return success ? Result.success() : Result.error("删除失败"); } }Result是统一响应体,一般包含状态码、消息和数据三个字段。推荐保持这种封装方式,前端可以根据code字段判断请求是否成功,而不是依赖 HTTP 状态码。
6.3 前端 axios 调用示例
前端使用 axios 调用接口,推荐把请求统一封装到src/api目录。
import axios from 'axios' import { ElMessage } from 'element-plus' const request = axios.create({ baseURL: '/api', timeout: 10000 }) // 请求拦截器,自动携带 token request.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = 'Bearer ' + token } return config }) // 响应拦截器,统一处理业务错误 request.interceptors.response.use( response => { const res = response.data if (res.code !== 200) { ElMessage.error(res.message || '请求失败') return Promise.reject(new Error(res.message)) } return res }, error => { ElMessage.error('网络异常,请稍后重试') return Promise.reject(error) } ) export function getArticleList(params) { return request.get('/article/list', { params }) } export function saveArticle(data) { return request.post('/article', data) } export function deleteArticle(id) { return request.delete(`/article/${id}`) }这段封装代码处理了三件事:统一设置请求前缀、自动携带登录凭证、统一处理错误提示。实际项目里的拦截器还可以扩展响应结果直接返回data字段、对 401 状态码做跳转登录等逻辑。
6.4 批量任务验证
后台管理系统最常见的批量操作是批量删除。前端把选中行的 id 数组传给后端:
export function batchDeleteArticle(ids) { return request.delete('/article/batch', { data: ids }) }后端接收 List 参数后执行批量删除:
@DeleteMapping("/batch") public Result batchDelete(@RequestBody List<Long> ids) { boolean success = articleService.removeBatchByIds(ids); return success ? Result.success() : Result.error("批量删除失败"); }这个逻辑可以进一步扩展成批量导出、批量发布、批量导入。批量导入常见做法是前端上传 Excel 文件,后端解析后逐行写入数据库。如果你只是完成毕设,建议先把批量删除和分页查询做得扎实,这已经是面试高频考点了。
6.5 使用 Postman 或 Apifox 调试接口
接口联调时使用 Postman、Apifox 或 IDEA 自带的 HTTP Client 都可以。启动后端服务后,直接在工具里发送请求验证。下面是一个创建文章的 JSON 请求体模板:
{ "title": "SpringBoot + Vue3 博客系统搭建实践", "summary": "本文记录前后端分离博客系统的部署过程", "content": "这是一段演示正文内容,可以从简写起。", "categoryId": 1, "tagIds": [1, 2, 3], "status": 1 }调试时重点关注三个地方:Content-Type是否设置为application/json、请求体字段名是否和实体类字段对应、登录接口返回的 token 是否在后续请求中带了。
7. 资源占用与性能观察
前后端分离项目跑在本地开发环境时,资源占用不算高,但仍有一些地方值得观察。
首先是后端 Java 进程的 JVM 内存。SpringBoot 默认启动时堆内存可能占用几百 MB,如果你同时开着 IDEA、MySQL、前端 Vite 服务,整体内存占用会比较明显。如果电脑内存只有 8G,开发时建议关掉不必要的浏览器标签页和后台程序。
Vite 开发服务器本身很轻量,启动快,热更新响应也快。但node_modules体积不小,安装依赖时磁盘和内存都会有一些压力。构建生产包时,前端产物体积取决于依赖的组件库大小,Element Plus 这类全量引入会把体积拉大不少,这时候可以考虑按需引入。
MySQL 侧重点是慢查询。如果文章表数据量增长到十万级以上,文章列表分页查询要关注category_id、status等字段是否建了索引。只要给表加上合适索引,分页查询性能通常不会有明显问题。
显存这个词在这个项目里不适用,但 CPU 和内存的占用可以这样观察:Windows 打开任务管理器,Mac 打开活动监视器,启动后端和前端服务后,分别看 Java 和 Node 进程的资源占用。如果后端启动特别慢,注意观察是否在编译阶段卡住;如果前端构建报内存溢出,可以给 Node 增加内存上限:
NODE_OPTIONS=--max-old-space-size=2048 npm run build8. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 后端启动失败,提示数据库连接错误 | MySQL 没启动、密码错误、数据库名错误 | 检查 application.yml,确认 MySQL 服务状态 | 修改配置,重启 MySQL |
| 前端页面能打开但接口报错 | 前后端跨域或代理配置错误 | 查看浏览器 Network 面板,观察请求 URL | 在 vite.config.js 里配置 proxy |
| 登录后无法保持状态 | token 未持久化或拦截器未生效 | 查看 localStorage 中是否有 token | 检查登录接口的返回处理和请求拦截器 |
| SpringBoot 版本太高,配置不兼容 | 项目使用 SpringBoot 3,本机 JDK 是 8 | 查看 pom.xml 中 SpringBoot 版本,检查 JDK 版本 | 使用 JDK 17,或回退 SpringBoot 2.x |
| 前端依赖安装失败 | Node 版本不匹配、网络问题、镜像源不稳 | 检查报错信息,查看 Node 版本 | 升级/降低 Node,换 npm 镜像源 |
| 接口返回 404 | 请求路径错误,或前后端路径不一致 | 对比前端接口调用路径和后端 Controller 的 @RequestMapping | 统一路径,重启服务 |
| 分页查询不生效 | 缺少分页插件配置 | 查看后端日志,观察 SQL 语句 | 配置 MyBatis-Plus 分页插件 |
| 删除数据时报外键约束错误 | 有关联表数据未清理 | 查看报错信息,检查外键关联 | 先删除关联数据或使用级联删除 |
这里重点说两个最常见的坑。
第一个是端口冲突。前端 Vite 默认 5173 端口,后端 SpringBoot 默认 8080 端口,如果被占用,启动时会直接报Port already in use。解决方式很简单,换一个端口即可。后端换端口就改application.yml里的server.port,前端换端口就在vite.config.js里改server.port。
第二个是 CORS 跨域问题。如果你没有配置 Vite 代理,而是直接在前端代码里访问http://localhost:8080/api/...,浏览器会拦截跨域请求。解决跨域可以在后端加一个全局跨域配置,也可以使用 Vite 代理。对开发联调来说,Vite 代理更简单,推荐优先配置。
9. 最佳实践与使用建议
这套博客系统一旦跑通,建议按照工程化的思路去维护,而不是只停留在“能运行”的程度。
第一次跑通时,先不要做任何修改,按照默认数据完整走一遍:登录 -> 新增文章 -> 列表查询 -> 编辑 -> 删除。确认全流程没问题后,再开始改代码。这样能避免“改了又不知道是哪步出问题”的情况。
代码组织上,后端一定要坚持 Controller -> Service -> Mapper 三层结构,业务逻辑写在 Service 里,Controller 里只做参数接收和结果返回。很多初学者习惯把业务逻辑全写在 Controller 里,短时间能跑,但项目稍大一点就会很难维护。
前端也建议按模块组织:api目录放接口请求,views目录放页面,components目录放公共组件,router目录放路由配置,store目录放全局状态。做这个博客系统时,前端可以把路由守卫和请求拦截器这两块打磨好,面试时很加分。
数据库层面,给常用查询字段加索引,文章表内容字段用longtext,标题字段限制长度,用户密码必须加密存储。如果你的项目还停留在明文密码阶段,强烈建议改成 BCrypt 加密,这是技术债里最容易被面试官追问的一条。
批量操作和数据导入方面,建议增加操作日志。删除文章、发布文章这类操作如果没有任何记录,线上出了问题很难追溯。加日志的方式很简单,在 Service 层打印关键操作,或者写入一张日志表。
还有一点要特别提醒:不管是用作毕设还是简历项目,都要注意数据安全和内容合规。系统里如果有用户注册和评论功能,要设置内容过滤和敏感词校验,避免被恶意数据注入。演示数据建议用自己写的技术文章,不要直接抓取未经授权的第三方站点内容。如果后续把系统部署到公网,必须把默认管理员密码改掉,关闭不必要的端口,配置好数据库访问白名单。
10. 总结与下一步
这个 SpringBoot + Vue3 博客管理系统最值得尝试的点在于:它把前后端分离项目的完整链路打包成了一只手能数的核心模块,文章管理、分类管理、标签管理、评论管理、用户登录,每一个都是实际开发里高频使用的功能。你真正动手跑一遍之后,获得的不是一个“看懂了”的虚拟经验,而是一套能运行、能演示、能封装的完整代码资产。
建议你最先验证的是文章从新增到展示的全流程。其他功能都可以先放一放,先把“前端表单提交 -> 后端接收 -> 数据库存储 -> 列表回显”这条主线走通,整个项目的骨架就抓住了。
最容易踩的坑集中在两个地方:数据库连接配置和前后端联调路径。数据库连接出错,后端直接启动失败;代理配置不生效,前端页面打不开接口数据。这两个问题不出意外的话一定会遇到,遇到时对照上面第 8 节的排查表解决即可。
后续如果要在这个项目上继续扩展,方向可以从这几个维度考虑:接入 Redis 做登录会话缓存和热点文章统计,接入 ElasticSearch 做文章全文搜索,接入对象存储服务做图片上传,用 Docker 把前后端和 MySQL 打包部署,或者增加一个简单的用户中心模块,支持用户注册、个人信息编辑、我的文章列表。每加一个模块,这个项目在简历上的含金量就会再上一档。先把基础版本跑通,再基于它去做增量开发,这条路最稳。