☰
SpringBoot+Vue3+MyBatis个人博客系统开发实战:从架构到部署
2026/10/11 11:54:32 网站建设 项目流程

1. 项目整体设计思路与方案选型

1.1 技术栈选择背后的真实考量

SpringBoot + Vue3 + MyBatis 这套组合,是当下个人博客系统最稳的搭配之一。从后端到前端,每一层的选型都有明确的理由,不是看着流行就无脑跟风。

后端用 SpringBoot,核心在于它把 Spring 家族的配置地狱彻底收拾干净了。以前搭 SSM 项目,光是 XML 配置文件就能写几十行,现在起步一个 starter 依赖加上自动配置,几分钟就能跑起来一个 Web 服务。个人博客这种体量的项目,不需要分布式那一套重型中间件,SpringBoot 的轻量特性刚好匹配。

持久层选 MyBatis,考虑的是灵活性和可控性。个人博客的查询往往伴随着动态条件——按分类筛选、按标签匹配、按关键词搜索,这些场景用 MyBatis 动态 SQL 处理起来相当顺手。更重要的是,SQL 写在自己手里,遇到慢查询可以随时优化,不像某些 ORM 框架那样包了一层又一层,出了问题无从下手。

前端用 Vue3,最大的收益是组合式 API 带来的逻辑复用能力。博客系统的管理后台和前台展示逻辑差异很大,使用组合式函数可以把标签获取、文章整理、用户状态这些跨模块逻辑抽出来复用,代码量比 Options API 少不少。配合 Vite 开发服务器,热更新速度大概是 Webpack 时代的十几倍,联调体验完全是两个档次。

数据库选 MySQL 没什么悬念,互联网仓储层的默认答案。个人博客的读写比大概在 10:1 甚至更高,MySQL 在查询密集型场景下做得足够好,加上 InnoDB 对事务的支持,文章评论、用户授权这些需要一致性的业务也能兜住。

1.2 前后端分离架构给开发流程带来的变化

前后端分离意味着前端页面和后端接口可以并行开发,不必相互等待。实际开发中,我习惯先约定好接口文档,把请求路径、参数、响应结构敲定,然后前端同事直接用 Mock 数据跑页面,后端专心写接口逻辑,最后联调一次搞定。

这种模式对个人开发者同样有价值。我自己在做这套博客系统时,先完成后端所有接口和数据库表设计,再着手写 Vue3 页面。因为界面细节往往会在开发过程中不断调整,后端接口是稳定的契约,前端随便折腾都不影响已完成的接口逻辑,开发节奏非常清晰。

接口交互统一走 JSON,前端通过 Axios 封装请求,后端用拦截器处理跨域和鉴权。这种交互方式让系统边界非常干净,未来如果想给朋友开放数据接口,或者接一个小程序客户端,复用成本极低。

1.3 数据库表结构规划

个人博客系统的数据规模不大,但表之间的关系需要设计得清爽。我的方案是五张核心表:用户表、文章表、分类表、标签表、文章标签关联表。

用户表字段包括主键、用户名、密码、邮箱、头像地址、角色标识和创建时间。密码必须用加盐哈希处理,我会用 BCrypt 算法,这个后面在鉴权模块会细说。

文章表是核心表,字段涵盖主键、标题、摘要、正文内容、封面图地址、浏览量、点赞数、评论数、所属分类 ID、创建时间和更新时间。这里有个容易被忽略的点:正文内容类型我用的是 LONGTEXT,而不是 VARCHAR,一篇图文并茂的 Markdown 长文轻松超过 65535 字节,这个坑我踩过。

分类表和标签表结构类似,都是主键加名称,区别在于分类是一级结构,标签是多对多关系,所以额外增加了一张关联表。为什么不给文章表直接加标签字段?因为一个标签可能对应几十篇文章,反查需求很常见,多对多必须拆表。

索引设计上,文章表对创建时间建了普通索引,排序分页走索引不会产生文件排序。分类表和标签表给名称加唯一索引,防止重复数据在生产环境上悄悄出现。

2. 核心模块拆解与关键实现

2.1 后端工程搭建与统一响应封装

工程结构采用标准的包分层:controller 负责接口路由,service 处理业务逻辑,mapper 做数据访问,entity 映射数据表,dto 承载前端交互数据。建议团队开发时在 controller 层引入 VO 概念,把给前端展示的字段和数据库字段做一次彻底的切割,避免把内部字段意外暴露出去。

统一响应封装是每次写接口必须考虑清楚的第一步。前端收到响应时需要知道一个请求是成功还是失败,数据是什么,如果失败原因是什么。我的封装结构是一个通用响应对象,包含状态码、消息和数据三个字段。状态码用 200 表示成功,400 表示参数错误,401 表示未登录,500 表示服务端异常。前端拿到非 200 的响应时,可以直接用统一的弹窗组件提示,不用每个页面自己去判断。

代码层面用泛型实现这个统一响应类,提供静态方法直接构造成功或失败的结果。这样一来 controller 层的代码会非常干净,每个接口就差一步直接返回业务数据,剩下的壳子都是模板化的。

2.2 JWT 鉴权与登录态管理

个人博客系统的鉴权,用 JWT 是最省心的方案。服务端在用户登录成功后签发一个加密签名的令牌,客户端后续请求带上这个令牌,服务端解析验签后就能识别用户身份。

JWT 由三部分组成:头部、负载、签名。头部声明算法,负载存用户信息,签名用密钥加密。注意不要往负载里塞敏感数据,比如密码,因为 JWT 的负载只是 Base64 编码,扫描工具或浏览器插件可以直接解码,泄露风险很大。一般只放用户 ID、角色和过期时间。

后端集成 JWT 的流程是:写一个拦截器或过滤器,拦截需要登录的接口路径,从请求头的 Authorization 字段取出令牌字符串,签名校验通过后把用户 ID 放入线程上下文,后续业务逻辑直接调用查询方法获取当前用户信息。

密码校验是配套环节,用户表存的是 BCrypt 加密后的哈希值。BCrypt 自动加盐,相同密码每次加密结果都不相同,自带彩虹表防御能力。工具类里一行调用即可完成校验,不用自己写加密算法。

2.3 文章模块的实现细节

文章模块是整个博客系统的核心。后端接口我拆成两块:管理员接口和管理端接口各司其职。管理员接口需要登录和角色权限校验,负责文章的增删改;浏览接口对游客开放,负责分页查询和详情查看。

创建文章时,标题和内容是常规字段,但有几个细节需要特别处理。第一是文章摘要,前端编辑器如果没单独填写摘要,后端要自动从正文中截取前 150 个字符作为降级方案,避免列表页卡片出现空白。第二是 Markdown 代码块里的特殊字符,直接把正文内容插入数据库没问题,但如果有富文本编辑需求,要考虑 XSS 攻击,前端渲染时应把内容当作纯文本处理或者依赖专门的 Markdown 渲染库做安全过滤。

分页查询用 MyBatis Plus 自带的分页插件,一条语句搞定分页计算。列表查询返回文章概述信息,不加载正文内容,数据库的 SELECT 字段列表里明确排除正文列,这样在大数据量下能有效降低数据库 IO 压力。详情页打开时再按 ID 查完整内容,同时把浏览量加一。

新增文章时还有一个关联操作:保存文章标签。事务必须保证文章主表数据插入成功的同时,关联标签记录一并写入。如果先插入文章成功,再插入关联表失败,就会产生脏数据,让文章带着不存在的标签 ID。所以这两个操作必须放在同一个事务里,加上 @Transactional 注解兜底。

2.4 Vue3 前端架构与页面实现

Vue3 工程用 Vite 构建,目录结构按照功能划分:api 目录集中管理所有后端接口调用,views 目录放页面组件,components 目录放通用组件,router 目录配置路由表,store 目录用 Pinia 管理全局状态。

接口封装是前端工程化的第一课。Axios 实例统一创建,设置请求超时时间,添加请求拦截器自动把 JWT 令牌塞进请求头。响应拦截器判断状态码,非 200 的统一弹出错误提示,401 的自动清理登录状态并跳转登录页。这样每个页面编写业务代码时完全不用关心鉴权和错误处理逻辑,只管在成功回调中处理数据即可。

博客前台页面设计上我分了几个核心视图:首页文章卡片流、文章详情页、分类归档页、标签页和关于页。首页打开时调用文章分页接口,使用无限滚动或者分页按钮加载数据。我这里倾向于分页按钮,因为 SEO 的考虑上,首页的页码链接更容易被搜索引擎收录,无限滚动对爬虫不友好。

文章详情页值得单独说一说。输入 URL 里带文章 ID,然后发起接口请求。页面顶部渲染标题、作者头像、发布时间和分类信息,接着是大面积的 Markdown 正文渲染区域。正文由前端用 Markdown 解析库处理,自定义一些代码高亮主题。评论区放在正文下面,用户登录后可以发表评论,游客则看到登录引导。

管理后台使用 Vue Router 嵌套路由,父路由是后台布局组件,子路由切换文章列表、写文章和系统设置等页面。后台所有路由统一通过路由守卫拦截,没有登录状态的用户无法进入,角色不是管理员的直接打回首页。

2.5 Pinia 状态管理与权限控制

全局状态放在 Pinia 中管理,最核心的 store 是用户状态。用户登录成功后,服务端返回 JWT 令牌和基础用户信息,这两个数据存进 store 并同步写入 localStorage。页面刷新后,store 初始化时从 localStorage 读取数据恢复登录态,保证用户不会因为刷新就被踢下线。

权限控制通常通过两个层次实现。路由守卫层检查目标路由的 meta 信息,如果标记了需要管理员权限而当前用户角色不符,直接跳转 404。页面内部层对修改和删除按钮做 v-if 判断,非管理员用户看不到这些操作入口。双保险设计确保即使有人通过浏览器调试工具强行改动接口参数,后端也能拦截住。

3. 实操过程与核心环节实现

3.1 开发环境准备清单

开始动手前,先检查一下本地环境是否齐备。JDK 要求 8 以上,我这边用的是 11 长期支持版。Maven 3.6 以上负责依赖管理。Node.js 推荐 16 以上版本,Vite 4 对 Node 版本有硬性要求。IDE 方面后端用 IntelliJ 系列,前端用 VS Code,插件装好 Vue 扩展和 ESLint 就够了。

MySQL 推荐使用 5.7 以上版本或者 MySQL 8.x,注意连接驱动要匹配版本。MySQL 8 的默认认证插件是 caching_sha2_password,SpringBoot 项目里需要用对应的驱动类,否则会报无法连接的错误。这一点是新手常见卡壳点。

初始化数据库时建议顺手建一个专用账号,账号权限只开放给当前数据库,不要把 root 密码直接写在项目配置里,安全习惯要早养成。

3.2 后端项目搭建保姆级步骤

第一步,用 Maven 骨架或直接在构建工具里创建 SpringBoot 工程,依赖包里勾选 Spring Web、MyBatis 场景启动器、MySQL 驱动、Lombok 和 Spring Security,不过 Spring Security 在这里主要用于密码加密工具,完整拦截框架可以简化处理。

第二步,配置数据源。在配置文件中填写数据库地址、账号和密码。注意时区参数要带上,否则连接 MySQL 8 会报时区错误。完整配置示例如下:

spring: datasource: url: jdbc:mysql://localhost:3306/blog_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: blog_user password: your_secure_password driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.blog.entity

第三步,编写实体类和 Mapper 接口。实体类字段和数据库字段一一对应,使用 Lombok 的注解生成 getter/setter。Mapper 接口写方法名和参数,SQL 语句放在同名的 XML 文件中,命名空间指向接口全限定名,这是 MyBatis 的运行契约。

第四步,实现 Service 层。这里的原则是接口和实现类分离,业务逻辑写在实现类中,事务注解加在具体方法上。比如修改文章时,先更新文章表,再删除旧的标签关联,重新插入新关联,这两个步骤必须在一个事务内。

第五步,Controller 层定义 RESTful 接口。路径设计遵循资源导向原则,比如文章相关的接口:

GET /api/article/list # 分页查询文章列表 GET /api/article/{id} # 查询文章详情 POST /api/article # 新增文章(管理员) PUT /api/article/{id} # 修改文章(管理员) DELETE /api/article/{id} # 删除文章(管理员)

3.3 Vue3 前端工程创建与实现

创建 Vue3 工程用 Vite 官方脚手架,一条命令完成初始化。然后按需安装依赖,Axios 负责 HTTP 请求,Vue Router 处理路由,Pinia 做状态管理,Markdown 解析选轻量库,代码高亮默认使用 highlight.js。

路由表配置采用懒加载方式,按需导入页面组件。前台路由和后台路由分开写,后台部分使用嵌套结构,子路由挂在后台布局下,便于统一展示侧边栏和顶部导航。每一条后台路由增加 meta 字段,写入角色要求。

Request 工具类封装是整个前端项目的骨架。我习惯在所有页面开发之前,先把 Axios 实例、拦截器、统一类型定义做完。之后写页面时,每建一个接口请求函数就是复用一行代码。请求头必须加上 Content-Type 为 application/json,和 SpringBoot 接收 @RequestBody 参数配对,否则后端解析不到参数。

页面开发顺序上,我建议先把路由骨架搭好,再依次填充页面。首页和文章详情页是核心展示页面,优先实现。管理后台先实现登录页和后台主框架,再逐步补充文章管理界面。联调时,前端开发服务器默认端口是 5173,后端接口跑在 8080,跨域让服务端统一放开,开发环境的代理配置方便,但不跨域配置会让前端每次请求都被浏览器拦截。

3.4 前后端联调跨域配置

联调阶段面对的第一个坑就是跨域。浏览器同源策略规定,不同端口之间的请求默认被拦截。前端页面的源是 http://localhost:5173,后端接口的源是 http://localhost:8080,协议和域名相同但端口不同,所以存在跨域问题。

开发环境推荐用 Vite 的代理功能解决跨域。在配置文件里为 /api 前缀的请求设置代理,把目标指向后端地址。这样前端代码里请求的地址是相对路径 /api/login,浏览器看到的是同源请求,自然不存在跨域问题。

生产环境的跨域交给 Nginx 处理。Nginx 配置反向代理,把前端页面和后端接口的请求分发到对应服务。同时在后端保留 CORS 配置兜底,避免意外情况直接弹浏览器跨域错误。注意生产环境和开发环境的接口地址不同,推荐在代码中通过环境变量区分。

4. 常见问题排查与避坑记录

4.1 Mapper 找不到 SQL 语句的排查方法

项目中高频率出现的经典报错是提示 Invalid bound statement。原因基本都指向 SQL 映射文件和 Mapper 接口没有正确建立联系。排查顺序建议从下往上走:先确认 resources 目录下 mapper 文件夹里的 XML 文件存在且命名正确,然后检查配置文件里的 mapper-locations 路径是否匹配,再看 XML 文件的 namespace 是否写成了接口全限定名,最后核对 SQL 的方法 ID 是否和接口方法名一致。这几个环节任何一处不对,MyBatis 都找不到对应的映射语句。我第一次遇到这个报错是路径漏写了一个星号,配置写成了 classpath:mapper/*.xml,实际目录是 mapper 下的二级子目录,调整配置后问题解决。

4.2 时间字段精度与格式问题

后端把 LocalDateTime 序列化传给前端时,默认输出格式是 ISO 标准的带 T 字符串,比如 2025-01-15T10:30:00。前端拿到这个字符串直接渲染会显示类似 2025-01-15T10:30 的样式,很不友好。解决办法是在统一响应里引入格式化依赖,对时间类型做序列化格式化,统一输出成 yyyy-MM-dd HH:mm:ss。另外 MySQL 的 datetime 类型默认精度是秒,如果业务需要毫秒级时间戳,表字段要用 datetime(3)。

4.3 图片上传与虚拟路径映射

博客系统的封面图通常需要上传到服务器本地磁盘。文件保存路径放在项目 resources 目录里是一个常见错误,因为项目重新打包部署时会让 resources 目录被清空或者覆盖,图片丢失得不偿失。推荐把上传文件保存到服务器固定目录,比如 /data/blog/images,和项目代码彻底隔离。然后配置虚拟路径映射,让 /upload/** 前缀的 URL 直接映射到这个磁盘目录。后端代码中图片访问地址完整保存,前端展示时拼接域名和映射前缀。

4.4 部署踩坑:打包与运行环境

前后端分离项目部署时有两个环境容易出错。后端用 Maven 打包生成 Jar 包,运行习惯是直接调用系统脚本执行启动,可以加参数指定端口。MySQL 连接信息如果用了环境变量,记得在服务器上提前导出。

前端打包时,Vite 默认构建目标目录是 dist。打包完成后把静态文件交给 Nginx 托管,Nginx 配置里要处理前端路由的刷新问题。Vue Router 默认使用 History 模式,URL 中不包含哈希标记,刷新页面时 Nginx 需要把找不到的资源路径全部指向入口 HTML,否则会出现静态资源白屏的问题。

4.5 性能优化与缓存策略

个人博客系统的性能瓶颈往往在数据库端。热点文章被反复点击浏览时,每次打开详情页都会实时查询数据库,其实完全没必要。用 Redis 或者简单的本地缓存把文章详情页缓存几分钟,流量上来后数据库压力会下降一个数量级。我的做法是引入 Spring Cache 抽象,给文章详情接口加缓存注解,设置 5 分钟过期时间。

前端静态资源缓存交给 Nginx 配置,dist 目录下的带哈希文件名设置长缓存,入口 HTML 设置 no-cache,这样浏览器既能缓存静态文件加速再次访问,部署新版本时也能第一时间拉取最新入口。

5. 个人体验与扩展方向

5.1 这套系统还能怎么延伸

博客系统的技术边界可以随意扩展。SEO 优化方面,可以做服务端渲染改造,解决前端页面在搜索引擎收录上的天然劣势。目前很多团队已经用 Nuxt 无缝衔接 Vue3 技术栈,改造起来比想象中的小。

评论区增加多级嵌套功能,需要引入无限极树的递归组装算法,对有歧义的分页查询方式也要谨慎处理。搜索功能目前是基于 SQL 的 LIKE 模糊匹配,数据量过万之后查询速度会明显下滑,届时接入全文检索组件是更优的方案。

5.2 我的合作感言

用这套技术栈完成一个完整的博客系统,整个过程让我对前后端分离的协作模式有了更透彻的理解。接口先行、数据驱动、职责切割,这些事情听着简单,真正动手时才能体会到设计决策对开发效率的直接影响。对于想进阶的开发者,强烈建议在现有基础上加一些个性化模块,比如文章归档日历、阅读时长统计、访客地图,技术学习就是在不断动手的过程中沉淀下来的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询