恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
个人博客全栈开发与部署:Spring Boot + Vue3 实训完整指南
首页
资讯中心
/
个人博客全栈开发与部署:Spring Boot + Vue3 实训完整指南
个人博客全栈开发与部署:Spring Boot + Vue3 实训完整指南
发布时间:2026/10/9 6:08:18
干这一行最怕的不是项目做不出来而是项目一做完就不知道该拿它怎么办。个人博客这个实训题拿到手的时候我第一反应是“这题我熟”但真正带着大家从零到一跑完一遍之后才发现越是这种看起来人人都会做的题目越能把基本功、工程思维和防坑经验全逼出来。这篇博客就好好把个人博客从设计、技术选型到实现、部署的完整路径拆一遍把我踩过的坑和总结的经验一并放进来做个实实在在的参考。1. 项目整体设计与技术选型思路1.1 实训题怎么拆个人博客不只是“写文章”个人博客听起来是个很小的项目很多人的第一反应是“不就是前台展示文章、后台发文章嘛”实际上把它当实训项目来做时它覆盖的知识点远比想象中多。一个完整的个人博客至少要包含文章的创建与编辑、分类标签管理、评论互动、搜索、阅读量统计、后台登录鉴权、前端响应式页面以及最后的上线部署。拆开之后你会发现这其实就是一个简化版的 CMS 内容管理系统几乎涵盖了 Web 开发最典型的所有场景。所以做实训的选题别只盯着“实现了个博客”这个结果要看到它背后的价值它要你处理列表与详情的数据流转处理文本编辑和富文本渲染处理一对多、多对多的关系建模还要处理文件上传、登录会话、接口安全、部署配置这些平时单点练习很难串起来的内容。真正跑通这个闭环你的 Web 基础就算立住了。1.2 技术栈到底怎么选别盲目追新要立足实训目的实训项目的技术选型我的建议是“以能完整实现、能独立讲解、能快速部署”为优先而不是以“看起来高大上”为优先。我们这轮走的是“Java Spring Boot Vue 3 MySQL”的组合放在国内实训场景里非常主流找工作写简历也够典型后端是成熟的 MVC 架构前端是组件化开发数据库侧有完整的关系模型整套体系学下来基本上就是企业里中小型 web 工程的微缩版。我在对比方案的时候也认真考虑过 Flask SQLite、纯 PHP、甚至 Next.js 全栈方案。Flask 的问题是 SQLite 在并发和复杂查询的教学演示上偏弱且部署时需要额外折腾 WSGI纯 PHP 虽然部署极简单但项目结构和代码规范容易写飞Next.js 全栈足够现代可是对实训者要求太高很多人会被 SSR、API Route 这些概念绕晕。Spring Boot 的生态规范、注解式开发、大量现成教程意味着你在遇到问题时能找到足够多的参考这对实训项目来说非常重要。1.3 先立原则哪些功能必须做哪些必须砍做实训项目最忌讳“什么都想加”。我们在正式开始前先把功能清单分成三类基础必备、加分可选、坚决不做。基础必备是文章 CRUD、分类标签、评论、登录、统计访问量加分可选是 Markdown 编辑器、代码高亮、RSS 订阅、分页搜索坚决不做的是即时聊天、在线写作协同、多用户权限体系这些超出实训体量的功能。砍掉多余功能的理由很简单实训项目的周期通常是几周你有限的时间应该花在把核心链路打磨扎实而不是把五个功能做出五个半成品。控制项目体量也是工程能力的体现能克制住需求蔓延比堆功能更能体现成熟度。2. 核心功能模块拆解与难点预判2.1 文章模块不止是“存进去、取出来”文章模块是博客的心脏但又最容易做浅。很多人的实现方式就是一张表存标题和正文然后列表页 select 一下详情页再 select 一下完事。这么写确实能跑但距离 “可用的博客”还有距离因为你还得考虑列表页要不要显示摘要摘要是从正文里截取还是单独存字段文章是 markdown 格式存还是 HTML 格式存需不需要定时发布要不要草稿箱我的做法是文章表里预留summary字段发布时不传就自动从正文前 160 个字符截取。正文统一存 Markdown 原文展示层再做渲染这样既方便编辑也方便未来换主题或做 api 输出。草稿状态用status区分0 草稿、1 发布、2 回收站。一开始就预留这些字段后面加功能就不用改表结构这是我在多次项目里被“后期加字段”支配之后总结出来的经验。2.2 分类和标签多对多关系是绕不开的坎分类和标签是博客最常见的组织方式它们之间的差异适合拿出单独说一下分类是层级结构通常一对一文章只属于一个分类标签是扁平结构一篇文章可以打多个标签一个标签也能挂多篇文章这是典型的多对多关系。多对多关系的正确建模方式是三张表一张文章表、一张标签表、一张关联表。关联表里就存两列article_id和tag_id联合起来作为主键。很多初学者会把标签直接塞进文章表的一个字段里用逗号分隔等到后面想按标签筛选文章时就会发现 SQL 写得极其痛苦。我见过不止一个实训同学在这里返工一次是查询想用like模糊匹配结果把所有“包含这个子串”的文章全揪出来了另一次是改标签名时要遍历所有文章去更新字符串原地爆炸。2.3 评论模块自关联表和审核状态不能少评论模块是博客里被严重低估的部分。新手最容易忽略的是评论的层级结构也就是“楼中楼”。如果你只需要一级评论那就简单得多父评论字段为空就行但通常你要支持回复某条评论所以评论表需要设计一个parent_id自关联字段为 0 表示顶级评论不为 0 则表示回复的是哪条评论。更重要的一个点审核状态。实训项目虽然不上真实生产环境但我在设计时强制加入了status字段0 待审核、1 已通过、2 已驳回。这样做的原因是评论区一旦放开垃圾评论就是必须面对的问题哪怕是实训做给自己看也要培养这个意识。前台只展示审核通过的评论后台管理员可以看到全部评论并操作审核这套逻辑做进去之后你的评论模块才称得上“完整”。2.4 管理后台个人博客里技术含量最高的部分管理后台经常被当成“随便写写”的部分但它的技术含量其实比前台高得多。前台大多数时候是“查”数据后台则是“增删改查”全套还要处理登录状态、文件上传、表单校验、权限控制等等复杂度一下子翻倍。以文章管理为例你要做一个可用性说得过去的编辑页面至少得处理富文本/Markdown 编辑器接入、图片上传与回显、标签多选、分类树选择、定时发布时间设置、草稿保存。每一项拆开都没那么难但组合在一起就极其考验你对表单数据模型、异步接口、组件通信的理解。后台是“吃功夫”的部分实训答辩时老师最喜欢深问的往往也是这里。3. 数据库设计与后端接口实现3.1 五张核心表的结构先想清楚关系再动手这一步决定了项目能走多远。我最终使用的表结构分为五张核心表加两张关联表具体字段如下文章表articleid、title、summary、content、status、category_id、view_count、create_time、update_time、publish_time分类表categoryid、name、description标签表tagid、name文章标签关联表article_tagarticle_id、tag_id联合主键评论表commentid、article_id、nickname、content、parent_id、status、create_time用户表userid、username、password_hash、avatar、create_time设计要点有三个。第一密码字段存的是 BCrypt 哈希后面加用户注册也不用担心明文泄露问题第二文章和分类是“多对一”所以把category_id放在文章表里而不是单独建一张关联表第三文章和标签是多对多所以我坚持使用关联表而不是冗余字段。你不需要一开始设计得极其复杂但这几个基础关系一定要从一开始就是对的。3.2 统一返回体和接口格式早期想不到后期哭着补实训项目最大的“开发效率杀手”之一是接口返回格式不统一。一开始大家图省事有的接口返回{ code: 0, data: ... }有的直接返回一个数组还有的出错时返回{ message: error }前端解析时得挨个接口写特殊处理改到一半就想骂人。我的建议是一开始就定死一个全局返回结构code、message、data三个字段。成功时code为 0失败时返回非 0 错误码data统一放核心数据。前端写一个request.js封装 axios 拦截器所有请求都走同一套逻辑。这样一旦遇到后端报错、token 过期、权限不足这些情况前端就能统一处理不用每个页面重复写判断。这个习惯适用于你将来所有的 Web 项目越早养成本越低。后端返回代码示例Spring Boot 的实际写法大概是这样Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(0); result.setMessage(success); result.setData(data); return result; } public static T ResultT error(Integer code, String message) { ResultT result new Result(); result.setCode(code); result.setMessage(message); return result; } }接口设计上还需要遵循一个原则列表接口必须分页。博客列表用page和pageSize两个参数返回数据中带上total这样前端才能渲染正确的分页组件。不要等到文章数超过一页才来加一开始就做成分页后面省很多事。3.3 登录认证选型JWT 还是 Session评价一个实训项目的“工程含量”随便问他一句“你怎么做登录认证”就能看出来。Session 和 JWT 都可以用但我更推荐 JWT原因很务实前后端分离场景下 JWT 天然无状态后端不用维护 Session 存储移动端比例大的场景下JWT 也可以直接复用同一套接口。JWT 的核心逻辑是用户登录成功后后端签发一个带过期时间的 token 给前端前端每次请求把 token 放在请求头Authorization里后端通过拦截器校验 token 是否有效并从 token 中解析用户信息。附带的好处是你可以把用户 id、用户名放进去后续接口里直接用省得每次查数据库。代码层面Spring Boot 里做这种校验的关键是 HandlerInterceptor核心逻辑大致如下public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); if (token null || !JwtUtil.verify(token)) { response.setStatus(401); return false; } Integer userId JwtUtil.getUserId(token); request.setAttribute(userId, userId); return true; } }我踩过一个坑前端 axios 请求时如果不加拦截器token 不会自动带上去后端就一直收不到所以前端必须设置请求拦截器。顺手封装一下所有接口就都能带上 token这块 90% 的联调问题都是从这里来的。4. 前端页面实现要点4.1 页面路由与组件结构先把导航想明白前端的总体结构要有清晰的导航路径博客前台大致是首页文章列表、分类页、标签页、文章详情页、关于页管理后台是登录页、后台布局页、文章管理页、分类标签管理页、评论管理页。我建议前台和后台路由彻底分开各自有独立的布局组件这样两个系统之间互不干扰代码结构也清爽得多。Vue 3 中可以使用 Vue Router 的嵌套路由来实现这个结构。父路由/admin下挂一个布局组件子路由渲染到布局的router-view /里。后台登录之后用路由守卫判断是否有 token没有就被踢回登录页。这样你在开发时只需要关注单个页面内的逻辑而导航、布局、鉴权的统一逻辑是全局维护的。4.2 编辑器的正确选择Markdown 是实训最优解输入框里写正文的方式不是不行而是你很快就想要加粗、加标题、插图片的排版能力这时候就得选编辑器。我强烈推荐 Markdown 编辑器比如md-editor-v3或v-md-editor原因有两条一是 Markdown 文本存储轻、渲染解析库成熟二是你日后如果需要迁移内容Markdown 文件本身就是最通用的文本格式不会锁死在某个编辑器逻辑里。编辑器需要配合marked或markdown-it做展示渲染代码高亮可以用highlight.js。这里要提醒一个容易踩的坑编辑器和渲染层必须使用同一种 Markdown 语法风格不然你在后台预览没问题到了前台渲染却对不上。尤其是代码块语言标记、表格写法、图片相对路径解析这四处最容易出现前后台不一致。我在实训中遇到过一个很经典的图片问题上传的图片被存到后端本地磁盘的upload/目录Markdown 里写入的是相对路径本地开发时前端跨域导致图片加载不出来。视情况不同你可以用 Nginx 做代理让前端访问/upload/时直接转发到后端也可以后端把图片转成 base64 存库。我的推荐是本地开发阶段在 Vue 的 vite 配置里加一个 proxy把/upload代理到后端生产环境则统一交给 Nginx 处理静态资源映射。4.3 管理后台的表格页方案不用高级组件也能做得专业后台最核心的页面是“文章管理页”本质上就是一个表格 搜索 分页 操作按钮。如果你用的组件库是 Element Plus实现这个页面其实非常模块化。el-table负责展示el-pagination负责分页顶部放一个搜索框支持按标题模糊查询操作列放编辑、删除、置顶三个按钮。看起来简单但“查询条件和分页参数如何联动”才是这里核心的知识点。我的实现思路是维护一个query响应式对象包含page、pageSize、keyword、status等字段。每次搜索按钮点击时把page重置为 1再拉接口切换分页时只改page不发额外请求以外的逻辑。数据返回时后端给total字段前端把它赋给分页组件的total这样整个表格页的状态管理就闭环了。一个干净利落的表格页背后就是你处理“筛选条件、分页状态、请求数据、刷新视图”四者关系的能力这个思路换到任何中后台项目都能用。5. 部署与上线实用指南5.1 前后端分离项目部署Nginx 后端进程就够用实训项目的部署并不需要上容器、上 DevOps 那些重东西一台最基础的云服务器 Nginx 一个 Java 进程就够了把流程跑通才是关键。我的部署方案是前端构建后的静态文件放在服务器/var/www/blog目录nginx 直接指过去后端打成 jar 包放到/opt/blog用nohup java -jar blog.jar启动Nginx 做两件事一是把/api开头的请求反向代理到http://localhost:8080二是把图片路径/upload也代理过去。这里给一个具体可用的 Nginx 配置片段直接抄作业就行server { listen 80; server_name your-domain.com; root /var/www/blog; index index.html; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /upload/ { proxy_pass http://127.0.0.1:8080/upload/; } location / { try_files $uri $uri/ /index.html; } }try_files那行尤其关键它保证了前端路由在刷新页面时不会 404否则你在/article/123刷新一下就会被 Nginx 误判成请求不存在的文件直接白屏。5.2 跨域、端口、防火墙部署前必查的三件事实训项目部署时最常见的问题是“本地跑得好好的上线就废了”原因基本就集中在三件事上。第一前端请求地址必须改成服务器域名或 IP不能再写localhost第二后端启动端口要被防火墙放行或者干脆只通过 Nginx 暴露 80 端口后端不直接对外开放第三跨域配置要确认正确如果你用了 Spring Boot 的CrossOrigin注解而部署时又用 Nginx 做了代理那开发环境需要的跨域支持在生产环境其实已经不需要了但旧的跨域配置可能反过来干扰请求头。我给实训同学的标准检查顺序是先curl http://localhost:8080/api/article/list验证后端本地通不通再curl http://your-server.com/api/article/list验证服务器端口和防火墙最后用浏览器打开前端页面看控制台报错。按照这个顺序排查基本能在十分钟内定位 90% 的部署问题。5.3 什么时候才需要上 Redis先别急着加中间件动不动就上 Redis 是实训项目里最常见的过度设计。个人博客的访问量在实训阶段根本达不到需要 Redis 做缓存的程度MySQL 完全扛得住。我曾经见过一个实训同学给博客加了 Redis 缓存、消息队列、ES 搜索引擎结果光是配置这些中间件就花了两天时间最后答辩时连核心业务都讲得磕磕绊绊。我的判断标准很简单当数据量达到一万篇文章、接口响应明显变慢的时候再来讨论优化方案不迟。实训项目更重要的是把业务链路跑通、把部署流程跑熟。阅读量计数器这种操作直接用UPDATE article SET view_count view_count 1 WHERE id ?一条 SQL 搞定不需要发明轮子。把缓存、搜索这些中间件留到后续扩展阶段配合真实的性能问题进行优化才算用到了刀刃上。6. 常见问题速查表与项目复盘6.1 高频问题速查从报错到排查思路我在带这个实训项目期间把大家反复踩到的坑汇总成了下面的对照表每一条都是真实发生过的现象根因解决方案前端请求接口 404后端接口路径和前端不一致打开浏览器 Network 面板比对 URL统一为/api前缀列表数据能查到但图片打不开图片访问路径被前端 dev server 拦截配置 vite proxy 代理/upload到后端登录成功后请求仍返回 401前端 axios 没在请求头带 token检查 axios 请求拦截器是否配置了Authorization前端刷新页面白屏 404Nginx 没配try_files在location /中加入try_files $uri $uri/ /index.html;文章正文字数太长保存失败MySQL 默认text类型容量不够把content字段改为longtext或改后端接收参数大小限制标签筛选文章结果不准标签关系未走关联表查询使用关联表 join 查询禁止用字段存放标签字符串点击阅读量发现没变化阅读量接口没加事务重试确认更新语句是view_count 1而不是先查再写死如果遇到控制台出现的是语法错误或某个组件库的报错我的建议是先别急着看百度准确把报错信息复制到文本里理清楚在哪个文件、哪个步骤触发的再带着具体路径去搜。盲目搜索的不仅搜不到答案还会让你越绕越远。6.2 答辩和总结实训项目的“交付力”从哪来实训项目的最终评价不只靠代码本身还要靠你的表达逻辑。个人博客虽然功能常规但如果被问到“为什么这样设计”时答不上来项目分一样会受影响。这里给一套自我提问清单为什么文章和标签是多对多而不是直接在文章表写死评论为什么要设计审核状态JWT 过期时间是多久、过期后前端怎么处理这些问题的答案都能在设计阶段找到出处所以请务必在开发时把每个关键决策记录到 README 里。更建议你在项目里写一个README.md里面包含项目简介、技术栈说明、功能清单、表结构说明、启动部署步骤、常见问题解答。这一份文档的价值有两个它既是帮助老师快速理解项目的入口也是你将来回顾项目时的第一手资料。实训项目可能只陪你几周但这套“技术选型有依据、调试有记录、部署有脚本”的工作方式才是真正能带走的东西。6.3 再深入一步个人博客的多种扩展方向实训结束不代表这个项目就没有价值了个人博客本身就是极其适合持续迭代的载体。比较自然的扩展方向有三个第一个是把静态资源上传改成对接阿里云 OSS消除本地磁盘依赖第二个是增加站内搜索小规模可以先考虑 MySQL 的全文索引文章量上来后再考虑更专业的搜索引擎第三个是支持主题切换和自定义页面把前端从前台页面扩展到可配置化。另外还有一个我自己很推荐的小功能写作统计。在后台增加一个“数据概览页”展示本月文章数、评论数、总阅读量用几个图表把数据可视化。这个功能开发成本不高却能让项目的完整度再上一个台阶答辩时图表一摆直观且有说服力。个人博客项目看着简单实际上每一个模块都有值得深挖的“为什么”。把基础链路走扎实把工程习惯养好它完全可以成为你从学生切换到开发者思维的第一个转折点。我始终认为项目不在大而在于你真正理解了每一行代码背后的选择逻辑这才是实训真正的意义所在。