做了这么多年开发接到最多的需求就是“帮我做个个人博客”一到毕业季更多十个学生里恨不得五个都是博客系统。刚开始我不太理解为什么大家都扎堆做这个后来带过几个毕设项目才明白博客系统这个题目看着简单但技术栈覆盖得是真的全前前后后能把一个人从后端开发到前端交互再到服务器部署全流程打磨一遍性价比极高。用SpringBoot做个人博客系统既是经典入门又是能拿得出手的完整作品属于那种“下限低、上限也高”的选题。这篇文章就结合我实际带项目的经验从技术选型、系统设计、核心实现到部署上线和常见坑位把一个基于SpringBoot的个人博客系统从零到一讲透。1. 项目整体定位与技术选型思路1.1 这个题目到底在考什么个人博客系统说白了就是一个内容发布和管理平台核心就三件事写文章、存文章、展示文章。但别小看这三件事往里一拆它涵盖了用户认证、权限控制、数据持久化、富文本处理、搜索检索、缓存设计、前后端交互再到服务器部署每一个环节都是毕业设计和实际项目里躲不开的硬功夫。我看过很多同学选这个题一开始觉得“博客嘛太简单了”结果做着做着发现用户登录怎么记住登录态文章里的图片怎么上传标题搜索和标签筛选怎么做评论被刷屏怎么防这些细节任何一个没有处理好系统就只能算个demo达不到“系统”的标准。所以说SpringBoot个人博客系统这个题不是为了让你写一个能跑的程序而是要你通过它展示你对Java后端开发的整体理解、对数据表设计的合理性、对常见业务场景的处理能力以及最后的项目部署和文档编写能力。答辩时老师看的不只是代码跑没跑起来更重要的是你能不能讲清楚“为什么这么设计”。1.2 为什么偏偏是SpringBoot这个必须得说清楚。很多人只知道SpringBoot好用但不知道它“为什么”成了个人博客系统乃至整个Java后端的默认选择。倒回七八年那时候做Java Web项目还是Spring SpringMVC MyBatis的SSM组合光是整合配置文件就能写几大页什么applicationContext.xml、spring-mvc.xml、mybatis-config.xml每一个都要手动配数据源、配事务管理器、配扫描路径稍微配错一个项目启动直接报错排查半天发现就是少写了一个空格。SpringBoot最大的贡献就是把“配置”这件破事大幅简化了。通过自动配置和起步依赖你只要在pom里加上spring-boot-starter-web一个内嵌的Tomcat、一套SpringMVC环境就齐了真正做到了“开箱即用”。对于博客系统这种业务复杂度没有那么高、但涉及组件不少的项目来说SpringBoot的优势非常明显快速搭建不用处理一堆XML配置注意力放在业务代码上。生态成熟整合MyBatis-Plus、Redis、JWT这些常用组件都有现成的starter接入成本极低。易于部署内置Tomcat打包成jar直接运行不需要额外装服务器环境。社区资料多遇到问题一搜一大把适合新手自学排查。我经常跟人说一个比喻SSM像手动挡汽车起步慢但你能看清每个部件怎么协同工作SpringBoot像自动挡你不需要一遍遍踩离合换挡踩油门就走等你开熟了再回来研究原理反而更容易理解。做毕业设计时间紧任务重自动挡才是正道。1.3 关键组件选型对比一个SpringBoot博客系统除了基础web框架之外还会用到ORM框架、数据库、缓存、权限方案、前端模板等。我这边整理了一个选型对照表你可以根据自己的基础和目标灵活挑选。技术点方案A方案B我的建议ORM框架MyBatis-PlusSpring Data JPA优先MyBatis-PlusSQL可控性好上手门槛低JPA虽然自动建表方便但复杂查询时你会很痛苦数据库MySQL 5.7PostgreSQL / H2用MySQL资料最多安装最省事H2适合演示用但生产不推荐权限认证JWT无状态Spring Security Session博客系统用JWT更轻量前后端分离也自然SpringSecurity杀鸡用牛刀配置起来烦前端方案服务端渲染 Thymeleaf前后端分离 Vue3 axios从毕设功利角度看前后端分离更出彩但不会前端的可以用Thymeleaf稳妥拿下富文本编辑Markdown编辑器传统富文本编辑器Markdown是加分项程序员博客天然适配富文本更像后台管理系统个人博客用Markdown更有味道缓存RedisCaffeine本地缓存如果你机器上装Redis没压力就上Redis实在不行Caffeine也能用但答辩容易被追问最后我再说一下项目结构的事。如果是前后端分离建议后端项目用标准的Maven多模块或单模块分层结构controller、service、mapper、entity、config、common各司其职。别把代码全堆在controller里这种代码我看过太多连自己都懒得看第二遍。一个清晰的分层结构不仅写着顺手答辩时也更好讲。2. 系统功能设计与数据表规划2.1 功能模块边界划分个人博客系统的用户分两类普通访客和管理员。这里我建议你直接砍掉复杂的注册功能系统内置一个管理员账号就够用了。有同学非要做用户注册、多角色权限最后把自己坑在里面答辩还被老师问“你这博客平台需要哪些角色为什么普通用户也能访问后台”——回答不上来这是典型的画蛇添足。我梳理一下最适合毕业设计展示的功能集合博客前台展示文章列表、文章详情、分类筛选、标签检索、按时间归档、关于我页面、友链页面。管理员后台登录认证、文章发布/编辑/删除、文章草稿箱、分类管理、标签管理、评论审核、基础资料配置。扩展亮点加分文章搜索关键词高亮、阅读量统计、Redis缓存热点文章、Markdown实时预览。把边界划清楚一是避免开发失控二是答辩时能清楚说出“每一个功能是为了解决什么需求”。比如“为什么做评论审核”——因为个人博客是公开站点不做审核容易被垃圾广告覆盖这是真实场景中一定存在的问题。2.2 数据库表设计与核心字段说明数据库设计是很多人的薄弱点但恰恰是毕业答辩的高频考察区。我不把表给你全部列出来只挑最核心的几张表讲清楚设计思路。第一张是文章表字段至少有字段名类型说明idbigint主键titlevarchar(100)文章标题summaryvarchar(255)摘要列表页展示用避免全文加载contentlongtext文章正文使用Markdown原始内容content_htmllongtext渲染后的HTML内容访问时直接返回减少实时转换开销cover_imagevarchar(255)封面图URLstatustinyint0草稿 1已发布 2回收站category_idbigint所属分类view_countint阅读数create_timedatetime发布时间update_timedatetime更新时间注意我把content和content_html拆成了两个字段。这个设计在博客系统里非常实用Markdown源文本用来满足“编辑”场景HTML用来满足“展示”场景。如果不拆每次请求都要做一次Markdown转HTML白费性能。拆了以后编辑时取原始文本展示时直接用现成的HTML开销小很多。第二张是分类表和标签表。很多同学上来就设计一个多对多关联表文章分类表、文章标签表、文章与标签关联表。这里我的建议是分类就用article表上的category_id一个外键就够了标签才需要一张独立的关联表因为一篇文章通常有多个标签一个标签也对应多篇文章。分类是一篇文章只有一个归属标签是一篇文章可能对应多个这两种关系要区分开。第三张是评论表字段核心是评论内容、评论人昵称、邮箱、父评论ID、文章ID、审核状态、发布时间。父评论ID用来支撑楼中楼的回复结构这条字段很多系统都没做导致评论只能一层楼体验很差。注意做评论之前先想清楚个人博客的评论区要不要登录才能评论我的建议是免登录评论但必须填昵称和邮箱这样用户体验轻快同时评论区内容全部走后端审核安全可控。2.3 MySQL建表时的几个关键点建表时的字符集一定要在数据库初始化时就确认好。MySQL里如果默认字符集不是utf8mb4一旦遇到Emoji表情或者生僻字存储就会报错或乱码。创建数据库时直接用CREATE DATABASE blog_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;另一个关键是时间字段。我强烈建议你使用datetime而不是varchar去存时间虽然用varchar存“2024-07-01 12:00:00”也能实现但你后续做归档查询、按月统计、排序的时候varchar对比字符串的性能和正确性都远不如datetime。如果项目里有自动填充时间的需要也可以直接用MyBatis-Plus的MetaObjectHandler来实现创建时间和更新时间的自动填充省去每次insert、update都要手动set的麻烦。3. 核心功能模块实现拆解3.1 用户登录认证从Session到JWT博客系统最基础的受保护资源是后台管理接口。如果直接用Session浏览器会自动维护Cookie服务端的SessionId需要保存起来而用JWT方案用户登录成功后后端生成一个带签名和过期的Token返回给前端前端存起来每次请求放进请求头Authorization字段后端通过拦截器校验Token是否合法。JWT方案在前后端分离项目里几乎是标配。我在项目里是这样落地的登录接口接收用户名和密码密码通过BCrypt加密后与数据库比对成功后生成JWT字符串返回。拦截器定义一个HandlerInterceptor对/admin/**路径做拦截从请求头取出Token调用工具类解析解析失败或过期直接返回401。前端配合axios统一在请求拦截器里携带Token收到401时跳转登录页。有一点你可能想不到JWT虽好但要注意Token过期时间的设置。如果你设置成7天过期管理员登录后就一直不用重新登录这很省事但如果Token被盗用7天内都有风险。个人博客系统风险不高可以设置成12小时或24小时过期了重新登录一次就好。实操上我建议把过期时间放到配置文件里别写死jwt.secretyour-secret-key-change-me jwt.expire864000003.2 文章发布Markdown编辑与内容存储个人博客系统区别于普通CMS的最大特征就是内容创作体验。我推荐接入一个开源的Markdown编辑器前端负责把文本域变成实时预览的编辑界面后端负责接收Markdown源文并转换成HTML存储。转换的过程中有个细节很多人容易忽略XSS注入。如果用户编辑的文章里写了scriptalert(垃圾广告)/script后端不做处理直接存进数据库每次有人打开文章详情就执行这个脚本这就是存储型XSS攻击。个人博客虽然只是你自己写作但如果你开放了登录注册假如你做了那这个漏洞就是致命的。安全做法是后端渲染HTML时做一个白名单过滤只保留标题、段落、代码块、图片、链接等安全标签。文章发布的流程是编辑Markdown源文 - 预览效果 - 点击发布 - 后端把源文和渲染后的HTML分别存入article表的content和content_html两个字段 - 更新文章的更新时间。如果状态是草稿就把status设成0前端列表不展示后台草稿箱里可以继续编辑。3.3 分类与标签的数据查询优化分类和标签最常见的使用场景有两个点击某个分类或标签展示对应文章列表。这里我的实现方法是分类查询直接按category_id匹配article表分页查询即可分类表本身只需要保存分类名和分类别名。标签查询标签和文章通过关联表article_tag关联点击某个标签时先查关联表拿到文章ID集合再根据文章ID查文章列表。这里有一个性能小坑如果标签下关联的文章很多一次查出来的ID集合可能很大再二次查询时用where id in (...)可能因为参数过多引发SQL语句过长。解决方案有两个要么在分页场景下先limit一批ID再查询关联文章要么直接用一条JOIN语句完成SELECT a.* FROM article a INNER JOIN article_tag_rel r ON a.id r.article_id WHERE r.tag_id #{tagId} ORDER BY a.create_time DESC LIMIT #{offset}, #{pageSize}这条SQL在标签场景下效率更好也更简洁。实际项目中我一般直接用MyBatis-Plus的LambdaQueryWrapper配合join插件或者干脆写XML里的自定义SQL这都属于可接受的方案。3.4 全文搜索like还是全文索引访客在博客站内搜关键词这是看起来简单但容易敷衍的功能。很多同学直接SELECT * FROM article WHERE title LIKE CONCAT(%, #{keyword}, %)结果文章多了之后慢查询会拖垮整个接口更尴尬的是搜索“SpringBoot”还能匹配搜索“spring boot”就搜不到带空格或大小写不同的内容。毕设阶段我建议至少做到两点第一搜索范围扩展。标题和摘要里都做模糊匹配提高命中率。如果你觉得摘要信息不够就把正文前几百个字符截取出来用于索引。第二如果不引入Elasticsearch这样的重型搜索引擎MySQL自带的全文索引是更聪明的选择。在title和content字段上建立全文索引再配合自然语言模式进行检索虽然中文分词效果不如专业搜索引擎但性能远超like扫全表。这里提醒一下全文索引对中文支持一般你需要确认MySQL的ngram全文解析器已经配置好不然查出来一堆无关结果。如果你不想折腾全文索引那至少把like搜索限制在已发布状态的文章上配合分页也能保证压测结果不会太难看。3.5 Redis缓存实打实的性能加分项个人博客的访问模式有一个很大的特点读多写少。文章一旦发布很长一段时间内容不会变化但会持续被访问。这种场景天然适合做缓存。我在系统里用Redis做了两件事缓存文章详情文章发布时写入Redis一份访问时先查缓存命中直接返回不命中再查数据库回填。缓存分类和标签列表侧边栏的分类列表和热门标签基本不变可以设置一小时过期省掉频繁查询数据库的压力。但要看清楚加了Redis之后你的系统就多了一个“缓存一致性”的坑。比如管理员在后台修改文章内容并重新发布此时Redis里存的还是旧数据前台展示就会是旧内容。解决办法不复杂更新文章时同步删除对应的缓存键即可下次访问再回填最新数据。这种“先删缓存再更新数据库等下次请求重建缓存”的策略对于博客场景是够用的。答辩如果被追问“缓存穿透怎么办”你只需要回答“对不存在的文章ID也做空值缓存设置较短的过期时间”就足够体现思考深度了。4. 系统架构搭建与部署上线4.1 前端方案选择与项目结构如果你走前后端分离路线Vue3 Vite Element Plus的组合现在最主流。博客展示页自己写一套干净清爽的样式后台管理直接用现成组件库搭就可以了。我见过很多同学把大量精力花在后台UI上其实毕设答辩更看重的是业务逻辑是否完整、技术点是否有深度后台界面干净能用就行。如果是单体应用用Thymeleaf模板引擎做服务端渲染也没问题。你只需要把静态资源扔到resources/static目录模板页面放到templates目录Controller里返回视图名SpringBoot自动解析模板。省事的程度是真的高不用处理跨域问题不用联调接口但缺点也很明显前端不够“现代”动态交互体验稍弱。做选择之前先问自己三个问题你的前端基础如何能不能独立写Vue页面并处理好跨域答辩时间还剩多少如果只有一个多月老老实实上Thymeleaf。你更想突出后端技术还是想展示前后端分离的能力我自己带过的模拟项目X里有学生前端零基础硬着头皮上Vue最后光配置Vite代理和跨域就卡了三天差点没赶上汇报节点。量力而行别拿毕业设计赌自己不熟悉的方向。4.2 后端接口设计规范做前后端分离时接口设计直接影响前端开发的效率和联调体验。这里有几个我强烈建议遵守的规范第一统一响应结构。后端接口不要有的返回对象、有的返回字符串、有的返回空值给前端造成巨大困扰。可以定义一个Result类统一结构是{ code: 200, message: success, data: { ... } }这样前端在axios的响应拦截器里只需要根据code判断接口是否成功如果失败统一弹提示逻辑简单清晰。第二接口路径要语义化。比如获取文章详情就是GET /api/article/{id}发布文章就是POST /api/admin/article修改文章就是PUT /api/admin/article/{id}。不要出现那种一看就猜不到含义的路径也不要把增删改查全怼到一个接口里去用参数区分。第三参数校验不能省。发布文章时title不能为空、content不能为空这些在Controller入口处就可以用注解完成校验。别把校验逻辑散落在Service各处用validation框架统一注解代码干净又能防止异常数据入库。4.3 后端接口设计规范选云服务器时学生机或者轻量应用服务器就够了。博客系统的访问量不会太高1核2G的配置已经能顺畅跑一个SpringBoot应用加MySQL。我建议你在服务器上装的东西有这些JDK 1.8或11MySQL 5.7以上NginxRedis可选部署的步骤基本是一路回车mvn clean package -DskipTests java -jar blog.jar --spring.profiles.activeprod不过相比“跑起来”更关键的是让系统“稳定地跑”。我做过的小优化如下第一用Nginx反向代理后端接口同时托管前端静态资源。后端只监听内网端口外部请求全部走Nginx这样既能隐藏后端真实端口又方便配置HTTPS。第二配置JVM参数时留出余地。比如服务器内存2GJVM堆内存设置成512M到1G之间别一上来就-Xmx2G否则操作系统连基本运行都卡顿。第三开启SpringBoot的actuator方便通过/actuator/health快速检查系统健康状态。作为毕业设计亮点这个细节很加分。4.4 HTTPS证书与访问安全如果你的博客绑定了域名最好把HTTPS配置上。现在申请免费证书非常方便比如在主流云服务商的证书服务里验证域名所有权就能拿到有效期为90天的证书。Nginx配置HTTPS只需要证书文件路径加几个配置项不算复杂。配置好HTTPS之后有一个好处搜索引擎对HTTPS站点更友好博客的访问链接也显得更正规。同时前端页面里的图片资源如果还是HTTP地址浏览器会提示“不安全内容”给访客的体验很差。所以如果做了HTTPS记得把站内所有资源链接也统一改成HTTPS或协议相对路径。5. 常见问题排查与避坑指南5.1 启动类扫描不到Mapper这是新手最常见的问题。SpringBoot启动类写了SpringBootApplicationMapper接口也建了但一启动就报Invalid bound statement网上查半天资料其实解决方案很简单启动类上加上MapperScan(com.example.blog.mapper)或者每个Mapper接口上单独加Mapper注解。但为什么加了扫不到很多人没搞明白。SpringBootApplication默认只扫描启动类所在包及其子包下的组件如果Mapper接口放在启动类包外面了自然扫不到。这个问题的本质不是你没加注解而是包结构层次乱了。规范的做法是启动类放在根包位置比如com.example.blog然后controller、service、mapper都放在它下面一层层放好。5.2 前端页面中文乱码写好的中文内容在页面上显示成乱码这问题一搜一大把但原因各不相同。最常见的是两种一种是因为文件编码不对比如Spring Boot里默认读取properties文件用的是ISO-8859-1你在properties里写了中文注释启动后后台日志全是乱码。解决方案是把配置文件统一用UTF-8保存或者改用yml文件yml对中文支持好得多。另一种是HTTP响应头里的charset没指定或指定错了。用SpringBoot时一般不会出这个问题但如果你手动写了Response返回流一定记得设置response.setContentType(application/json;charsetUTF-8)。5.3 上传图片失败博客文章里免不了传图片如果你是自己写上传接口最容易踩的坑是Nginx的client_max_body_size默认只有1M图片稍微大一点就报413错误。解决方法是client_max_body_size 10m;另外一个坑是上传目录的权限。如果项目跑在Linux服务器上上传目录可能没有写权限导致明明接口返回成功但目录里没有文件。排查时报错信息往往还不明显看看Tomcat运行用户对上传目录的写权限chmod 755一下大概率解决问题。5.4 Markdown内容换行丢失如果你在后台发布文章时感觉段落没问题但前台展示时所有换行都不见了那么核心问题是Markdown换行规范和HTML换行的差异。Markdown中换行需要行尾加两个空格或输入空行而你在前端编辑器里按了回车但没遵守这个规范后端转出来的HTML自然没有p标签。这个问题有几种解决路径最直接的是使用成熟的开源Markdown解析库它能正确处理常见的新增行。另外在textarea输入时可以考虑捕获用户的换行行为自动补全语法但复杂度过高。如果你发现预览和发布后展示效果不一致先检查是不是解析库的处理逻辑和自己拼接字符串的方式冲突了。5.5 跨域请求把前端坑惨了前后端分离开发的经典坑位。你前端跑在8080端口后端跑在9090端口浏览器在请求接口时报跨域错误但后端日志里明明能看到请求到达了。其实这时请求确实到了后端但响应被浏览器拦截了前端拿不到数据。解决方式不复杂后端配置一个全局CORS配置类即可允许指定来源和请求头。Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOrigins(http://localhost:8080) .allowedMethods(GET, POST, PUT, DELETE); } }不过前后端分离仅靠这条配置还不行部署上线之后如果你把前端静态文件放在Nginx上后端接口放在另一个域仍然会跨域。最简单的解决思路是用Nginx把/api/路径反向代理到后端服务让前端访问的始终是同一个域名跨域问题彻底消除。5.6 慢SQL拖垮首页博客首页要同时展示文章列表、分类、标签、最新评论、热门文章如果这些数据全都是同步查询数据库页面的响应时间一定会随数据量增长而肉眼可见地变慢。某次我给一个模拟项目做压测文章数量到了几千条之后首页接口从原来的几十毫秒涨到了三秒多问题就出在一个统计标签的SQL用了临时表排序。个人的解决经验是两个方向把首页数据做聚合缓存用Redis存一份首页数据的JSON序列化结果过期时间30分钟到1小时。对文章列表分页查询每次只查当前页的数据不要一上来就把所有文章查出来然后在应用层做筛选。慢SQL的排查工具也分享一下MySQL开启慢查询日志看看到底是哪些SQL耗时超过1秒然后针对性地加索引。文章表的create_time加索引、category_id加索引基本能解决大多数慢查询问题。6. 项目功能优化与答辩加分点6.1 为项目加哪些功能能脱颖而出很多毕设博客系统撞车大家都长得差不多。想拿高分的同学需要在基础功能上给自己加一点差异化的“技术纵深”。我列几个性价比比较高的扩展方向阅读量统计与热门文章排行。不依赖数据库实时统计用Redis的ZSET按阅读量排序这种方式既高效又能体现对数据结构的理解。文章定时发布。后台发布文章时可以选择定时发布时间通过SpringBoot的Scheduled定时任务扫描并更新文章状态展示了你对任务调度模块的掌握。多级评论回复。做成类似楼中楼的评论结构用parent_id实现两级或三级回复或者用一套更泛化的折叠回复策略体验上会好很多。站点地图功能。生成sitemap.xml提交给搜索引擎收录给自己的个人博客做点SEO优化这在真实场景中是合理需求。6.2 写文档和答辩时的注意事项毕业设计除了代码还有开题报告、中期检查、毕业论文、答辩PPT这些东西占了相当大的比重。很多人代码写完了但文档不会写最后分数反而不如代码一般但文档写得清楚的同学。我的建议是写项目文档时不要堆砌功能列表而是按照“需求分析-系统设计-数据库设计-核心实现-测试与部署”的线索去写每一章都要回答“为什么”为什么用这个技术选型、为什么这张表这么设计、为什么这个接口这么定义。答辩时老师最喜欢问的就是“为什么”你只要能把选型逻辑和实现细节讲清楚即使项目本身功能没那么花哨分也不会低。答辩演示的时候注意准备一条“备选演示路径”。最常见的情况是你现场访问项目页面加载不出来或接口报错这时候不要慌先把错误页面截图或日志信息调出来再讲你怎么排查、怎么修复的。老师看到你有完整的排错能力印象分反而会往上走。6.3 持续维护与后续演进博客系统不是一个做完就扔掉的毕设你完全可以在毕业后继续用它写自己的技术笔记。后续能优化的方向也很清楚接入图床或对象存储减轻服务器存储压力。接入第三方登录比如GitHub登录提升评论互动率。把搜索引擎优化做深一点对你的博客流量提升有明显帮助。迁移到Docker容器部署以后换服务器的时候会很感激自己。我个人在实际操作中的体会是博客系统最大的价值不是“毕业设计拿了多少分”而是它迫使你在一个完整的项目里从需求到上线跑通了一遍所有流程。很多技术点你单独学觉得都会了但合在一起做项目时才会发现真正的复杂度都在接口之间的衔接和异常边界的处理上。如果你正在纠结选题这个题目完全可以放心选但前提是别只做一个能跑的demo把它当成一个真正要上线使用的产品去做收获会完全不同。最后再分享一个小技巧写代码的时候顺手把启动日志里出现过的异常信息都截图留档。这个习惯帮你写论文时补充“测试与分析”章节非常有价值。往往你项目做完之后根本想不起来当时遇到过哪些问题等写文档需要凑“问题与解决”时再回去复现就非常浪费时间了。
阅读完成 · 觉得有帮助?