毕业设计选了个 Spring Boot 个人博客,其实是个挺聪明的决定。个人博客这个题目看起来简单,但里面涉及的技术栈一点都不缺:后端框架、数据库设计、缓存、全文检索、前端模板、部署上线,甚至 Markdown 解析、RSS 订阅这些小功能全都能沾上边。你把这一套做完整了,Spring Boot 的知识体系基本就捋通了一半,更重要的是,这题目好讲清楚、好做演示,论文也好写。尤其像这种以原创毕设选题推荐的形式流出来的 Spring Boot 个人博客设计与实现项目(编号一般在 30981 附近),通常配套了完整的源码和数据库脚本,对时间紧、又想踏实学点东西的同学来说,是一个非常好的起步依托。
这篇文章我把自己做这类项目时的完整思路理一遍,从技术选型、数据库设计、功能拆解到最终的论文框架,全部掰开揉碎了讲。不是那种只能看不能跑的代码粘贴,而是把为什么这么设计、有哪些坑、答辩时会被人问什么,都给你指出来。不管你是想直接照着项目源码做二次开发,还是想完全自己从零搭一个,这篇都能派上用场。
1. 为什么 Spring Boot 个人博客是毕设的“最优解”之一
1.1 选题难度适中,充分体现工作量与个人能力
做毕设最怕什么?怕题目太虚,或者分不清到底要做什么。个人博客系统的需求非常明确,角色就两类:游客和管理员。游客能看到文章列表、文章详情、按分类搜索、按标签筛选;管理员能写文章、发文章、传图片、删除垃圾评论。就这么一条链,一年即是零基础,把 Spring Boot 的基本流程跑通后,两到三周就能完成主体功能。进一步可以做个性化推荐、社交登录、数据统计图表、定时发布、访问日志等,完全可以把工作量拉到“优秀”档位。
对导师来说,这种题目一看就知道学生的水平:实体类关系合理、MVC 分层清晰、权限控制到位、异常处理完善,这些都能一眼看出基本功。你要是做那种需求模糊的“智能系统”或“平台设计”,反而容易因为项目边界不清导致答辩被深挖漏洞。
1.2 Spring Boot 技术栈的“正统性”加“实用性”
当前 Java 教学体系中无论如何绕不开 Spring Boot,企业招聘基本默认应届生会 Spring Boot 基础。用 Spring Boot 做毕设,既能回扣课程内容,又能写进简历。个人博客项目涉及的 Spring Boot 知识点覆盖面特别广,每一项都可以作为回答面试官问题的真实案例:
- Spring MVC 的请求映射与参数绑定、RESTful 接口设计;
- Spring Security 或 Shiro 做登录鉴权、密码加密;
- MyBatis-Plus / Spring Data JPA 做数据访问;
- Redis 做缓存;Spring Cache 的注解用法;
- 定时任务、文件上传、邮件发送、全文搜索整合 OpenSearch / Elasticsearch 等进阶玩法。
一套博客项目下来,你在简历上能够写的技术点能列一长串,而且全部是有真实项目兜底的,不是“学过”而是“用过”。
1.3 免费领源码只是起点,不是终点
很多同学看到“免费领源码”就先松了一口气,觉得任务完成了。这里提醒一句:直接交源码通常过不了答辩。很多源码项目里的配置是基于其他环境写死的,拿到手后你得改数据库连接、改文件路径、可能要换 Redis 版本,光是把项目跑起来就已经能学到不少东西。更关键的是,你要能回答出“为什么这段代码这么写”,否则答辩老师一句“这个功能你怎么实现的”就能把你问住。所以我把这篇的重点放在原理和设计点上,源码到手之后对着这篇做复盘,思路会清晰非常多。
2. 从零到一:技术选型与整体架构设计
2.1 后端框架与关联组件选型
我做过好几个博客系统项目,反复对比之下,默认推荐这组方案:
| 层级 | 选型 | 理由 |
|---|---|---|
| 核心框架 | Spring Boot 2.7.x | 稳定、教程多,与 Spring Cloud 生态兼容,JDK8 友好 |
| 持久层 | MyBatis-Plus | 单表 CRUD 几乎零 SQL,分页可直接用,适合毕设快速开发 |
| 权限认证 | Sa-Token 或 Spring Security + JWT | Sa-Token 上手门槛低,代码量少,答辩好解释 |
| 缓存 | Redis + Spring Cache | 热点文章和分类列表缓存,性能提升明显 |
| 数据库 | MySQL 8.0 | 稳定主流,支持 JSON 数据类型,适合存标签与文章扩展字段 |
| 富文本 / Markdown | editor.md 编辑器 + commonmark-java | 编辑器体验好,解析服务端化,避免前端 XSS |
| 前端模板 | Thymeleaf(服务端渲染)或 Vue 3 + Element Plus | Thymeleaf 更简单,Vue 更现代,取决于你前端水平 |
| 部署 | Linux + Nginx + Jar 包 / Docker Compose | Docker 是加分项,但 Nginx 反向代理一定要会 |
Spring Boot 3.x 已经出来了,但如果你拿到的源码是基于 2.x 写的,别急着升级。升级到 Spring Boot 3 意味着 javax 要换 jakarta、部分自动配置类有调整,折腾一圈对毕设来说不值。除非你精力非常充足、想在简历上写“适配 Spring Boot 3”,否则就固定在 2.7.x,资料最多、坑最少。
2.2 单体架构、分层结构一目了然
个人博客系统根本不需要上微服务,一个单体应用搞定一切。核心是分层架构:
com.example.blog ├── controller // 控制层,负责接收请求、参数校验、转发 ├── service // 业务层,处理业务逻辑,事务边界 ├── mapper // MyBatis-Plus 数据访问接口 ├── entity // 数据库实体对象 ├── dto // 数据传输对象:前端参数接收和返回体封装 ├── vo // 视图对象:给前端展示的组装数据 ├── config // 全局配置:拦截器、Redis、跨域、MyBatis-Plus分页插件 ├── common // 统一返回体、异常处理、常量 ├── utils // 工具类,如 Markdown 转换、JWT 工具 └── exception // 自定义异常体系这一层做清楚,论文的系统设计章节就好写了。Controller 必须薄、Service 必须厚,Controller 里只做参数校验然后调 Service,ServiceImpl 里才写真正的业务逻辑。别把 SQL 写在 Controller 里,也别在 Service 里直接操作 HttpServletRequest,这是答辩老师最反感的写法。
2.3 统一返回结构和全局异常处理,一上来就做对
不要在每个接口直接返回 ModelAndView 或裸 Map,建议全局定义:
@Data public class Result<T> { private Integer code; private String message; private T data; // 静态方法 success(), success(data), error(code, message) }配合@RestControllerAdvice做全局异常拦截,这样不管业务成功、参数错误、还是系统内部异常,返回格式都是统一的 JSON 结构。即便你做的部分页面是服务端渲染,管理后台的接口返回统一结构,前端联调会顺畅非常多。这是我踩过的一个坑:前期图省事,到处返回 Map,后期前端拿数据时天天对字段名,后来统一封装了 Result 才省下心来。
3. 数据库设计:个人博客的表结构到底要几张表
3.1 核心表拆解与字段设计思路
个人博客系统的核心表通常是五张起步,按需扩展:
| 表名 | 用途 | 关键字段 |
|---|---|---|
| t_user | 用户(管理员) | id, username, password(BCrypt), nickname, avatar, role |
| t_article | 文章 | id, title, summary, content(Markdown原文), content_html, cover_image, status, view_count, create_time, update_time |
| t_category | 分类 | id, name, sort, create_time |
| t_tag | 标签 | id, name, create_time |
| t_article_tag | 文章标签关系表 | article_id, tag_id |
| t_comment | 评论 | id, article_id, nickname, email, content, audit_status, create_time |
这里有两个容易被忽视的点。第一是文章表里同时存content和content_html。content是 Markdown 原文,编辑时用;content_html是解析后的 HTML,展示时直接输出。如果不加content_html,每次请求都重新解析 Markdown,白白消耗 CPU,而且不好做全文索引。
第二是status字段。文章状态建议用 0=草稿、1=已发布、2=回收站,不要只有一个“发布/未发布”。草稿箱功能在答辩演示时非常有用——你可以现场写一篇草稿,再点发布,老师立刻看到你的功能完整度。很多项目源码里没有草稿概念,拿到后建议自己补上这个字段。
3.2 多对多关系用中间表,别把标签存成字段
不少新手会把文章标签设计成tags字段,直接存一个逗号分隔的字符串“Java,Spring Boot,MySQL”。这看起来很省事,但后面做标签筛选时你要写LIKE '%Java%',容易误匹配,数据量大一点性能就掉得厉害。正确做法是多对多中间表,文章和标签通过article_id和tag_id关联。标签云功能、按标签筛选文章的 SQL 都是简单的 JOIN,也不怕标签改名。
关联表记得建联合索引:(article_id, tag_id)和(tag_id, article_id)都建立。别只建一个,因为你既会从文章查标签(前台详情页展示标签),也会从标签查文章(点标签跳转列表页),两种查询方向都要走索引。
3.3 索引设计与性能预留
文章列表页要按status和create_time查询,复合索引建议(status, create_time)。评论表按文章 ID 查,记得给article_id建索引。访问量字段view_count直接放在文章表里,每次请求加一,用UPDATE article SET view_count = view_count + 1 WHERE id = ?,不要先查出来 Java 里加一再写回去,会有并发覆盖问题。
这一点答辩时你可以主动讲出来,老师会觉得你有并发意识。毕设项目一般不会有真实的高并发,但“有意识”和“没意识”在答辩中是两回事。
4. 核心功能实现拆解:从登录、发表到全文搜索的完整链路
4.1 登录鉴权:BCrypt 加密 + 拦截器,别用 MD5 裸存密码
用户表里密码不要明文,也不要只做简单的 MD5。用 Spring Security 自带的BCryptPasswordEncoder,或者 Shiro 的Md5Hash加盐,推荐前者,因为 BCrypt 每次生成的哈希值都不同、自带随机盐,安全性远超固定盐 MD5。我甚至可以给你看一段常见的注册逻辑:
@Transactional public boolean register(RegisterDTO dto) { if (userMapper.selectByUsername(dto.getUsername()) != null) { throw new BizException("用户名已存在"); } User user = new User(); user.setUsername(dto.getUsername()); user.setPassword(passwordEncoder.encode(dto.getPassword())); user.setRole("ADMIN"); user.setStatus(1); return userMapper.insert(user) > 0; }登录态用 Token 方案:管理员登录成功后签发 JWT,前端保存到本地;每次请求带在 Header 的Authorization里。后端用一个拦截器解析 Token,把它存到ThreadLocal或者RequestContextHolder,供 Controller 层获取当前登录用户。用拦截器而不是在每个接口里写解析代码,至少省几百行重复逻辑。
如果是 SSM 时代的 JSP 项目,用 Session 也说得过去。但既然主打 Spring Boot,用 JWT 更能体现你对前后端分离的理解。哪怕模板是 Thymeleaf,管理端页面也可以是一个独立的 Vue 或 HTML 工程,走动 JWT 这条路一点不亏。
4.2 Markdown 的解析与渲染:服务端清洗,防 XSS
Markdown 编辑器我习惯用 editor.md,它自带上传图片、实时预览,也比较适合毕设演示。前端保存的是 Markdown 原文,到后端统一用 commonmark-java 解析成 HTML。解析完直接存到content_html。
这里有一个重要的安全点。如果你引入了代码高亮、Markdown 里的 HTML 标签,默认情况下 commonmark-java 对原始 HTML 是直接输出的,这就意味着任何人写文章时可以嵌入<script>标签,存储型 XSS。解决办法是解析前先做 HTML 清洗,用Jsoup.clean()白名单过滤:
String unsafeHtml = CommonMarkParser.parser().parseToHtml(content); String safeHtml = Jsoup.clean(unsafeHtml, Safelist.relaxed());Safelist.relaxed()允许图片、链接和基础排版标签,又去掉脚本和事件属性。答辩时你说出这句话,老师就知道你考虑过安全问题。
4.3 文章接口链路:发布、编辑、浏览计数、预览
文章发布的核心逻辑是:先保存/更新文章基本信息,再关联分类和标签。事务一定要加在 Service 方法上:
@Transactional(rollbackFor = Exception.class) public Long saveArticle(ArticleDTO dto) { Article article = new Article(); BeanUtils.copyProperties(dto, article); article.setContentHtml(markdownService.render(dto.getContent())); if (article.getId() == null) { article.setViewCount(0); articleMapper.insert(article); } else { articleMapper.updateById(article); } // 处理标签关联:先删除旧关联再插入新关联 articleTagMapper.deleteByArticleId(article.getId()); if (dto.getTagIds() != null) { for (Long tagId : dto.getTagIds()) { articleTagMapper.insert(...); } } return article.getId(); }为什么不直接在 Controller 里调用多个 Mapper?因为事务生效需要走 Spring 代理。方法内部自调用会导致事务失效。这是 Spring 事务一个著名的坑,答辩时如果被问“事务不生效”的场景,能答出来就是加分项。
浏览计数我这里提供一个经验:前台文章详情页不要直接viewCount++,因为每次访问都会触发 DB 写操作。简单做法是加一层 Redis 缓存:先读 Redis,若没有从 DB 加载并回填,命中后increment,然后定时(比如 5 分钟一次)把 Redis 里的增量批量写回 DB。个人博客流量不大,但实现这一点能让面试时多聊两分钟。
4.4 搜索功能:从数据库 LIKE 到全文检索的进阶路线
个人博客的搜索功能,最低要求是LIKE '%keyword%'。但中文分词是个问题,LIKE 查询会把“SpringBoot”和“spring boot”看成完全不同,也搜不到“Spring”+“Boot”的切词组合。如果要体现加分项,可以在项目里引入 HanLP 分词配合倒排索引思路(也就是把文章存 Redis 的 ZSet 按关键词做映射),或者直接接入 OpenSearch、Elasticsearch。考虑到毕设部署环境的资源限制,我不建议为此单独装一个 ES 集群。稳妥的方案是做得好看一点:用 HanLP 给标题和正文内容做分词,然后把分词结果和文章 ID 存到一张t_search_index表里,搜索时先查索引表再回表查文章。这个方案代码量不大,但能体现你对“中文检索痛点”的真正理解。
另外讲一个小技巧:每篇文章的content_html存下来之后,如果你还在用 MySQL 8,可以使用CREATE FULLTEXT INDEX配合ngram全文解析器,MySQL 自身就能支持中文全文索引。个人博客体量下,直接给title和summary建 FULLTEXT 索引,比接 ES 省事得多:
ALTER TABLE t_article ADD FULLTEXT INDEX ft_title_summary (title, summary) WITH PARSER ngram;然后搜索:
SELECT * FROM t_article WHERE MATCH(title, summary) AGAINST ('${keyword}' IN NATURAL LANGUAGE MODE) AND status = 1;这个方案在毕设答辩中是可以讲清楚原由的:短语失配、中文分词依赖 ngram 机制、覆盖率等等。别盲目上 ES,除非你想让自己陷入装系统依赖、调内存参数的泥潭里。
4.5 前台展示与模板渲染方案
前台我强烈推荐用 Thymeleaf 直接服务端渲染。理由很简单:SEO 友好、代码量少、部署简单。如果你非要用 Vue 3 做前后端分离,那么前台页面一定要做预渲染或 SSR,否则搜索引擎爬不到内容,你写博客系统却搜不到自己的文章,是一件很尴尬的事。
Thymeleaf 的几个关键点:
- 用
th:each循环文章列表,用th:href="@{/article/{id}(id=${article.id})}"生成带路径参数的链接; - 用
th:if="${article.status == 'PUBLISHED'}"控制元素显示; - 因为
content_html是富文本,不要用th:text输出,要用th:utext,否则标签会全部显示成源码。
发布时间建议格式化后在实体里输出yyyy-MM-dd HH:mm,不要直接在页面里操作 Date 对象。我见过很多同学在模板里用#temporals.format(...)然后踩到 Thymeleaf 版本差异的坑,直接把格式好的字符串放到 VO 字段里最省心。
5. 部署上线与“毕设级”源码改造方案
5.1 Linux 服务器部署:Nginx + Jar 包运行
拿到源码后最大的坎是部署。我习惯的做法:打包成 Jar 放到 Linux 服务器上,配合 Nginx 做反向代理。先看application.yml,把端口固定成 8080,数据库连接改成本机 MySQL,Redis 如果用了也要改连接地址。然后运行:
mvn clean package -DskipTests java -jar blog.jar --spring.profiles.active=prod如果内存比较紧张,可以加 JVM 参数:
java -Xms256m -Xmx512m -jar blog.jar结合 Nginx 配置:
server { listen 80; server_name yourdomain.com; location / { 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/ { alias /opt/blog/upload/; } }静态上传资源(图片、头像)不要打进 Jar 包。文章封面和编辑器上传的图片,统一放到服务器的/opt/blog/upload/目录,Nginx 用alias直接映射。如果你一开始把图片上传到项目运行目录upload/下,一旦重新部署换目录,图片全没了,这是很多源码跑起来之后才发现的坑。
5.2 把免费源码变成“自己的项目”的三个修改点
拿到源码第一件事不是跑起来,而是把标识信息全部改掉。项目里可能带有作者名、网站标题、备案信息、Logo 之类。全局替换以下内容:
- 网站标题和版权信息改为你自己的名字和学校;
- 项目包名结构、
artifactId可以保留,但banner.txt里的欢迎语改成你自己的 Motivation; - 数据库初始化脚本里的初始管理员密码修改,并对
/sys/**接口加上一分简单操作日志。
千万别觉得这些是小事。答辩时老师最反感看到一个陌生马甲的项目截图,首页标题还是别人的网名。同名项目很多,事先改一遍不花多少时间,却直接决定了第一印象。
5.3 使用 Docker Compose 一键部署(加分项)
如果你希望简历多一个“容器化部署”的亮点,可以写一个简单的docker-compose.yml,把 MySQL、Redis、博客应用三个服务统一管理:
version: '3.8' services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: blog ports: - "3306:3306" volumes: - ./mysql_data:/var/lib/mysql redis: image: redis:6.2-alpine ports: - "6379:6379" blog: build: . ports: - "8080:8080" depends_on: - mysql - redis environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/blog?useUnicode=true&characterEncoding=utf8这个 compose 文件是能直接跑通的基础模版,具体到你的项目可能需要调用户名密码和数据库名。用 Docker 部署可以省去服务器上逐一安装依赖的时间。但也提醒一句:如果学校答辩机房网络环境差,Docker Hub 拉镜像会很慢,最好提前把镜像save下来,否则现场出糗。
6. 毕设论文框架与答辩避坑指南
6.1 论文提纲建议:不要写成“用户手册”
很多毕设论文被老师打回是因为全部在写“鼠标点击之后系统干什么”,缺少设计依据。我建议提纲这样排:
- 绪论:背景与意义,现状分析,本文主要工作(不要长篇大论抄百度百科)
- 相关技术介绍:Spring Boot 核心特性,MyBatis-Plus,MySQL,Thymeleaf,Markdown 解析,按需展开安全技术与缓存
- 系统分析:可行性分析、需求分析(功能需求用表格列),用例图,非功能需求
- 系统设计:总体架构图、功能模块设计、数据库表设计(每张表字段列表)、接口设计
- 系统实现:按功能模块分小节,每个功能贴关键代码不超过 20 行 + 截图 2 张左右
- 系统测试:测试环境、功能测试用例表格,性能测试如果有 Jmeter 记录
里面最关键的是数据库设计和接口设计,导师快速翻论文看的就是这两部分。如果你的论文里数据库表只有字段没有说明,接口只有 URL 没有参数和返回结构,基本过不了关。
6.2 答辩被问频率最高的 8 个问题
我汇总了历年来学生答辩被问得最多的问题,提前背下来,到时不慌:
- 为什么选择 Spring Boot 而不是 SSM?答:内置 Tomcat、自动配置、生态成熟,本质上同属 Spring 体系。
- 密码加密是怎么做的?答:BCrypt 加盐哈希,不用 MD5,因为固定哈希容易被彩虹表击穿。
- 文章搜索为什么用 MySQL 全文索引而不是 LIKE?答:LIKE 无法利用索引且不支持中文分词,MySQL 8 的 ngram 可以做到合理切词。
- 首页访问量大的时候系统会怎样?答:Redis 缓存分类列表和热门文章,DB 计数走异步批量写,降低热点行竞争。
- 系统的安全性做了哪些工作?答:XSS 清洗、密码加密、参数校验、登录拦截器,按需提防 SQL 注入(MyBatis 预编译)。
- 数据库为什么建中间表?答:文章和标签是多对多关系,冗余字段会造成更新异常和查询歧义。
- 如果用户同时访问同一篇文章,viewCount 会不会出错?答:不会,用的是数据库自增更新,是原子操作。
- 部署在什么环境,性能如何?答:最低 1核2G 云服务器即可,几十篇文章在 100 并发下 QPS 至少能到 1000+(可以用压测随便演示)。
回答问题的核心是用“项目经历”答,不要背“八股文”。比如问事务,你就说“我在发布文章时因为要同时写文章表和标签关联表,所以加了 @Transactional,如果中间出错全部回滚”。
6.3 答辩演示的“标准剧本”
演示环节千万不要一上来就发文章。步骤如下:首页展示博客列表与分类菜单 → 点开一篇文章看排版与评论区 → 搜索一个关键词看候搜索结果 → 进登录页,输入管理员账号 → 进入后台仪表盘(有统计图表最好) → 新建文章,插入图片 → 回到首页验证文章已发布 → 修改分类与标签 → 演示评论区留言显示待审核。这套流程两分钟左右,完整覆盖了主要功能点。现场演示最怕断网。把你所有的接口先本地调通,截图准备好,浏览器页面本地跑稳定了再开麦。
7. 常见部署与开发问题排查实录
7.1 数据库连不上、时区报错、中文乱码
拿到源码最常见的问题是 MySQL 版本和驱动差导致的连接失败。如果你用的 MySQL 8,JDBC URL 一定要带时区和编码参数:
spring.datasource.url=jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai如果不带serverTimezone,会报The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized。这个问题几乎 10 个跑源码的人 9 个会碰到。字符集乱码则是建库语句的问题,初始化脚本里尽量用utf8mb4_create table时指明:
CREATE DATABASE blog DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;7.2 Spring Boot 版本太高导致无法运行
Spring Boot 3.x 把javax.servlet迁移到了jakarta.servlet,老源码里导的javax.validation、javax.annotation在 3.x 下会直接编译失败。解决办法有两个:一个是把版本降回 2.7.x,或者全局搜索替换javax为jakarta。后者改动太大,不适合新手。从 GitHub 上拉下来的老项目大概率是 2.x 写的,直接用相同版本跑最省心。
7.3 前端打包放进 Spring Boot 的静态资源路径,刷新 404
如果你用 Vue 构建完的dist目录放到src/main/resources/static下,注意前端路由是 history 模式时,刷新/#/之外的具体路径会返回 404。这个需要在后端做一层转发:
@Controller public class ForwardController { @RequestMapping(value = {"/admin/{path:[^\\.]*}", "/admin/**/{path:[^\\.]*}"}) public String forwardAdmin() { return "forward:/index.html"; } }核心思想是:所有不带扩展名的路径,让前端路由自己处理。如果你是纯 Thymeleaf 页面,没有这个问题。我遇到过一个同学的毕设就是把 Vue 的 dist 直接丢进 static 后,在管理后台点刷新直接白屏,最后加了这层 forward 才解决。
7.4 图片上传报文件过大或上传目录不存在
Spring Boot 默认单个文件最大 1MB。图片上传动不动失败,就需要在配置中调大:
spring.servlet.multipart.max-file-size=20MB spring.servlet.multipart.max-request-size=50MB同时,如果你做了本地存储,一定要在启动时检查上传目录是否存在:
@Component public class FileInitRunner implements CommandLineRunner { @Override public void run(String... args) { File dir = new File(fileProperties.getUploadPath()); if (!dir.exists()) { dir.mkdirs(); } } }又一个小细节:上传时别直接用file.getOriginalFilename(),这既可能包含路径字符,又可能重名,统一用 UUID 重命名文件:
String ext = originalFilename.substring(originalFilename.lastIndexOf(".")); String filename = UUID.randomUUID().toString().replace("-", "") + ext;8. 如果时间充足,还可以怎么把项目做厚
个人博客系统做到 80 分容易,做到 95 分需要加这几个方向。第一个是引入 AdminLTE 或 Vue 3 后台模板,把管理界面做成现代一点的单页应用,日志和仪表盘图表会非常加分。第二个是做文章自动定时发布,用@Scheduled(fixedDelay = 60000)每分钟扫描一次文章表,把到达发布时间且状态为“定时发布”的文章置为已发布。第三个是增加简单的访问统计,不用接第三方。把每次访问记录按天聚簇写入一张计数表,配合 ECharts 画折线图,答辩演示效果非常好。
还有一个轻量级但很亮眼的扩展:RSS 订阅。博客系统天然适合输出 RSS,Thymeleaf 就能生成 XML 视图,或者用 Rome 工具类生成。写一个/feed接口输出全部文章摘要,评审老师如果自己写博客,会对你这个点有天然的亲切感,而且实现难度低、展示效果好。
以上这些不是必要项,但每做一个,你的项目就能多聊一分钟,简历就能多一行。尤其 ECharts 统计图和定时发布,两者加起来一天就能完成,是性价比最高的两个加分项。
最后说一句个人体会。毕设选题最怕眼高手低,选了个人博客这种“看起来普通”的题目,容易被认为没难度,其实恰恰相反,它非常考验你对一个完整项目全生命周期的把控。尤其是 Spring Boot 项目,你能否把一个博客从需求、设计、编码、部署到论文讲清楚,决定了你从“会写代码的学生”到“能交付项目的开发者”这个转变是否完成。源码领到手之后,先跑通,再改一版,加入自己的功能点,最后写进论文里。这个过程走完之后,你会发现自己对 Spring Boot 的把握已经上了一个台阶。