ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringBoot个人博客毕设全攻略:从表设计到部署答辩

SpringBoot个人博客毕设全攻略:从表设计到部署答辩 每年毕设选题的名单发下来“基于SpringBoot的个人博客系统的设计与实现”这个题目几乎雷打不动地出现在好几个班里。不少同学一看就觉得“这题太简单了不就是个写文章看文章的东西吗”但等真开工才发现光是技术选型、表结构设计、Markdown渲染、部署上线这几个环节就够折腾几个星期的。我带过的几个学弟学妹选这个题有人踩了SpringBoot版本过高的坑有人被MyBatis Plus分页插件坑了一整天也有人论文写得干巴巴、答辩被问得下不来台。这篇文章我把从选题、定技术栈、建表、写核心功能到部署排错、写论文、准备答辩的完整链路梳理一遍。内容全部按我实际做过的版本和帮别人改过的代码来写该给配置给配置该给代码给代码遇到过的坑也直接摊开讲。如果你正准备选这个题或者已经做到一半卡住了这篇可以作为一条主线参考。1. 选题逻辑与技术栈定版为什么“博客系统”并不好糊弄1.1 博客系统的功能边界其实比想象中宽先聊选题。很多人觉得博客系统简单是因为只看到了前台展示文章和后台发布文章这两个页面。实际上一个完整的个人博客系统至少要覆盖四条业务链路内容生产链路后台登录、写Markdown、传封面图、发布或存草稿、编辑和删除文章。内容消费链路前台首页分页展示、文章详情、按分类筛选、按标签聚合、按时间归档、关键词搜索。用户互动链路注册、登录、评论、回复评论、评论审核或删除。系统治理链路分类和标签管理、个人信息维护、访问统计、异常处理和日志记录。把这几条链路全做完你会发现它其实是一个“内容管理系统CMS”的完整缩影。毕设导师看重的是你有没有完整的软件工程思维而不是功能列表有多长。所以这个题目真正考察的点是你是否能把一个Web项目从零设计到落地并且在论文里讲清楚每一个设计决策的理由。1.2 SpringBoot版本、配套组件与项目结构定版技术选型上SpringBoot是绝对的主流但版本选择很容易踩坑。这两年最大的坑就是SpringBoot 3.x和2.x的差异3.x要求JDK 17起步而且把包名从javax.*换成了jakarta.*。如果你照着网上大量基于2.x的教程写代码在3.x下编译会直接报找不到包。我当时做这套系统时用的是SpringBoot 2.7.x JDK 8原因很简单毕业设计阶段稳定和资料好查比版本新更重要。如果你现在新开项目我建议直接选SpringBoot 2.7.18这种2.x的最终维护版本网上教程、博客、开源项目几乎全部兼容遇到问题搜起来最快。配套组件我推荐这样定MyBatis Plus大幅减少单表CRUD代码分页查询、条件构造器这些直接省掉很多样板代码。MySQL 8.0主流、稳定毕业设计用完全够。Redis我建议做成可选项。如果做用户登录Token缓存、文章访问计数可以加如果担心部署复杂度就不加。我最后是加了Redis做Token黑名单和阅读量统计的答辩的时候这也算一个亮点。前端两种方案一种是用Thymeleaf服务端渲染简单直接另一种是前后端分离前端用Vue3 Element Plus。大多数学校毕业设计更接受前后端分离因为工作量更大、结构更清晰。我当时选的是SpringBoot提供纯RESTful API Vue3前端正好贴合现在主流开发模式。项目结构上我建议按功能分包而不是按层分包。很多同学喜欢建controller、service、mapper三个大包然后把所有类堆进去前期还行后期找代码非常痛苦。按功能分包的意思是一个模块一个包比如user包里面放UserController、UserService、UserMapper、UserEntity这样别人看你项目结构一眼就能看懂这个系统的模块划分。我的实际目录结构大致是src/main/java/com/example/blog/ ├── BlogApplication.java ├── common/ # 统一返回结果、异常处理、常量 ├── config/ # MyBatis Plus、Redis、跨域、拦截器配置 ├── security/ # JWT工具、拦截器 ├── module/ │ ├── user/ # 用户模块 │ ├── article/ # 文章模块 │ ├── category/ # 分类模块 │ ├── tag/ # 标签模块 │ ├── comment/ # 评论模块 │ └── statistics/ # 访问统计模块1.3 把功能清单分成“必做项”和“加分项”毕业设计最怕的是需求失控。我见过一个学弟一开始想做博客然后想加上在线聊天又想加上音乐播放器最后还打算做App端结果两个月过去核心功能都没写完。我的建议是把功能清单严格分成两层必做项这些缺了系统就不完整用户注册、登录、退出登录。文章的发布、编辑、删除、草稿管理。前台的文章列表展示和详情页。评论发表和列表展示。分类、标签的维护和展示。加分项这些用来拉开差距文章搜索可以先做MySQL的LIKE查询后面有余力再考虑全文索引。按月归档前台按时间轴展示文章。阅读量统计用Redis自增实现。个人简介、友链页面、站点公告。管理员对评论的删除功能。功能清单确定后第一件事不是写代码而是建数据模型。2. 数据模型先行五张表加一张中间表的建模过程2.1 从页面反推实体先列功能再画ER图我建模的习惯是“从页面反推”。先把需要做的页面列出来比如注册登录页、文章列表页、文章详情页、后台文章编辑页、后台分类管理页然后从每个页面里抽出数据字段。博客系统最核心的实体是文章Article。围绕文章用户发表文章文章属于一个分类文章可以有多个标签用户可以评论文章。这样就得到5张核心表user、article、category、tag、comment。因为一篇文章可以打多个标签一个标签也对应多篇文章所以文章和标签是多对多关系需要一张中间表article_tag。数据模型是后面一切功能的骨架如果这一步歪了后面每个功能都会别扭。比如有人图省事把分类直接设计成文章表里的一个category_name字符串字段结果后来想把分类改名必须写一条UPDATE article SET category_name 新名字 WHERE category_name 旧名字还要担心改漏。用独立的分类表加外键关联才是正常的做法。2.2 核心表结构与索引设计下面是我实际用的建表语句字段不多但每个都是必须的。先看文章表CREATE TABLE article ( id bigint NOT NULL AUTO_INCREMENT, user_id bigint NOT NULL COMMENT 作者ID, category_id bigint DEFAULT NULL COMMENT 分类ID, title varchar(200) NOT NULL COMMENT 标题, summary varchar(500) DEFAULT NULL COMMENT 摘要, content longtext NOT NULL COMMENT Markdown原文, cover_image varchar(500) DEFAULT NULL COMMENT 封面图URL, status tinyint NOT NULL DEFAULT 0 COMMENT 0-草稿 1-已发布, create_time datetime NOT NULL, update_time datetime DEFAULT NULL, PRIMARY KEY (id), KEY idx_status_time (status, create_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里有两个细节值得说。第一content字段我推荐存Markdown原文而不是存渲染好的HTML。原因是前端编辑时需要用原文来回显如果只存HTML后续想改内容很麻烦如果只存原文展示时再渲染就可以。HTML可以下前端渲染也可以后端渲染后临时生成不需要落库。第二索引idx_status_time是前台列表页最常用的查询条件只查已发布文章按时间倒序。没有这个联合索引数据量到几千篇的时候列表页就会开始变慢。用户表CREATE TABLE user ( id bigint NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL COMMENT 用户名, password varchar(100) NOT NULL COMMENT BCrypt加密后的密码, nickname varchar(50) DEFAULT NULL, avatar varchar(500) DEFAULT NULL, email varchar(100) DEFAULT NULL, role tinyint NOT NULL DEFAULT 1 COMMENT 1-普通用户 2-管理员, create_time datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;密码必须加密存储明文是绝对不能接受的。我用的是Spring Security里的BCryptPasswordEncoder即使两张表数据泄露密码也无法直接还原。分类和标签表都很简单id、name、create_time顶多加一个sort_order排序字段。分类和文章是一对多文章表里存category_id标签表通过中间表关联CREATE TABLE article_tag ( article_id bigint NOT NULL, tag_id bigint NOT NULL, PRIMARY KEY (article_id, tag_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;联合主键直接把数据重复问题堵死了同一篇文章不能重复打同一个标签。很多新手用自增id做中间表主键其实完全没有必要联合主键就够了。评论表相对复杂一点要考虑层级CREATE TABLE comment ( id bigint NOT NULL AUTO_INCREMENT, article_id bigint NOT NULL COMMENT 所属文章ID, user_id bigint NOT NULL COMMENT 评论用户ID, parent_id bigint NOT NULL DEFAULT 0 COMMENT 父评论ID0表示根评论, content varchar(1000) NOT NULL, create_time datetime NOT NULL, PRIMARY KEY (id), KEY idx_article_time (article_id, create_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;parent_id用于实现“楼中楼”回复效果为0时表示一级评论。有了这个字段前端可以递归渲染嵌套评论结构上比平铺评论灵活得多。2.3 两个我踩过的字段设计坑第一个坑软删除和唯一索引冲突。我一开始给用户表加了deleted字段做逻辑删除又给username加了唯一索引。结果用户注销后再注册同名账号插入直接报唯一索引冲突因为老记录还在表里。后来我改成了两个方案要么所有表都统一带deleted并且在唯一索引里把这个字段加上要么干脆不用通用软删除只有需要审计的记录用专门的逻辑删除字段。毕设系统我最后选择了物理删除因为这个系统数据量不大不存在大数据场景下的误删恢复需求简即是优。第二个坑评论内容长度。我一开始把评论内容设计成varchar(255)觉得够用。后来有人测试时复制了一段稍微长一点的文字直接报Data too long for column前端弹出一大串异常信息特别难看。后来改成varchar(1000)阈值高了很多同时前端也加了500字符的长度限制。这个经历给我的教训是字段长度一定要结合业务预估宁宽勿窄因为改表结构成本远比改一个字段长度要高。3. 功能落地的四条主线登录、发文章、看文章、评论数据模型确定后代码实现阶段我建议按“登录鉴权→文章管理→前台展示→评论互动”四条主线推进。每完成一条主线系统都是可以运行验证的不会等到最后一天才把所有代码拼在一起结果一堆冲突。3.1 登录鉴权用JWT加拦截器理由和写法登录方案现在主流是JWT而不是传统的Session。毕业设计里用JWT有个明显的好处论文和答辩时有东西可讲比如无状态、鉴权流程、Token过期策略。我用的流程是用户登录成功后后端生成一个Token返回给前端前端存在LocalStorage里每次请求在Header里带上Authorization: Bearer token后端写一个拦截器拦截除登录、注册、文章列表、文章详情、评论列表以外的接口校验Token有效性。拦截器的核心代码大概是这样的public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 放行预检请求 if (OPTIONS.equalsIgnoreCase(request.getMethod())) { return true; } String token request.getHeader(Authorization); if (StringUtils.hasText(token) token.startsWith(Bearer )) { String realToken token.substring(7); // 校验签名和过期时间解析出用户ID放入request Long userId JwtUtil.parseUserId(realToken); if (userId ! null) { request.setAttribute(userId, userId); return true; } } response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return false; } }写这个拦截器时有三个细节需要特别注意。第一跨域预检请求OPTIONS必须先放行否则前端调用接口时会被CORS拦截排查起来非常头疼。第二JWT的密钥不能用默认值至少从配置文件里读取长度不要少于32个字符。第三给Token加过期时间我一般设置24小时前端在收到401响应后自动跳转登录页。3.2 文章发布的Markdown链路编辑、存储、渲染、防XSS编辑器的选择上我尝试过两种方案前端集成一个开源的Markdown编辑器比如Editor.md或者Vditor直接编辑和预览后端只接文章内容和标题的保存接口。另一个方案是后端引入Markdown解析库前端提交原文后端渲染成HTML再返回给前端展示。我最终用的是前端编辑、前端渲染混合的方式。编辑时用Vditor它自带预览、代码高亮、图片上传体验很完整。详情页展示时如果前端有现成的Markdown渲染库就直接在浏览器里渲染如果是Thymeleaf服务端渲染就需要后端引入commonmark-java这类解析库把Markdown转成HTML再和页面一起返回。两种都可以只要记住一条硬原则用户输入的Markdown原文里可能包含JavaScript代码渲染前必须做HTML转义和脚本过滤否则就是存储型XSS漏洞任何人发一篇文章就能在别人浏览器里执行任意脚本。我在项目里的做法是定义一个MarkdownUtil工具类渲染时先把代码块里的内容原样保留再把其他部分的HTML标签做白名单过滤只允许p、code、pre、blockquote、a、ul、ol、li、h1到h6、img这些常规标签。编译HTML时所有script、iframe、on*事件属性一律剔除。这样虽然偶尔会让某些嵌入内容失效但安全性优先这是毕设系统可以接受的代价。3.3 前台展示分页、标签云与按月归档前台首页的列表接口用MyBatis Plus的分页功能就够了。先配置分页插件拦截器Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); PaginationInnerInterceptor paginationInterceptor new PaginationInnerInterceptor(DbType.MYSQL); // 单页最多50条防止有人恶意调大页码参数拖垮数据库 paginationInterceptor.setMaxLimit(50L); interceptor.addInnerInterceptor(paginationInterceptor); return interceptor; } }然后在Service里用LambdaQueryWrapper写查询条件PageArticle page new Page(current, size); LambdaQueryWrapperArticle wrapper new LambdaQueryWrapper(); wrapper.eq(Article::getStatus, 1) .eq(categoryId ! null, Article::getCategoryId, categoryId) .orderByDesc(Article::getCreateTime);这段代码看起来简单但有几个点容易出错。eq(condition, column, value)三个参数的重载第一个参数是布尔条件只有传入true时才拼接SQL这样“分类筛选”在不传分类时不会生成多余的WHERE条件。这是MyBatis Plus用得好的关键技巧。标签云的数据聚合其实很简单就是把关联文章数量统计出来SELECT t.id, t.name, COUNT(at.article_id) AS article_count FROM tag t LEFT JOIN article_tag at ON t.id at.tag_id GROUP BY t.id, t.name按月归档则是另一句常用SQLSELECT DATE_FORMAT(create_time, %Y-%m) AS month, COUNT(*) AS count FROM article WHERE status 1 GROUP BY DATE_FORMAT(create_time, %Y-%m) ORDER BY month DESC这两条SQL建议直接写进Mapper的XML里而不是用MyBatis Plus的封装方法因为涉及聚合和别名用封装方法反而绕。3.4 评论模块的隐藏需求嵌套、防刷、可控制评论模块看起来简单实际在测试阶段最容易出问题。我遇到过的场景按频次排序是乱码、XSS、重复提交、被刷评论。乱码问题主要靠全链路UTF-8解决数据库表utf8mb4、数据库连接URL加characterEncodingutf8、前端页面meta charsetutf-8、后端接收参数时确保SpringBoot的server.servlet.encoding.forcetrue。这四层缺一就可能出现中文变问号的情况。XSS问题还是在渲染层过滤评论内容和文章内容一视同仁。重复提交问题我用的方案是前端提交后按钮置灰后端再对同一用户同一文章的评论做短时间频率限制比如同一个IP一分钟内最多评论5次。这块可以用一个简单的内存Map记录请求时间戳也可以引入Redis的INCR加过期时间。毕设环节用内存Map就够演示了但如果想体现技术水平用Redis做限流更值得写进论文。评论的嵌套展示后端返回的列表需要带parentId前端递归渲染。这里有一个小坑评论列表接口不要一次性把整篇文章所有评论全部返回数据量大时会很卡。我采用的方式是前端分页加载默认加载20条点“加载更多”再取20条。如果一个评论下面有嵌套回复回复也走分页。4. 部署和运行阶段翻车复盘四个细节结束了我的“本地能跑”前面功能写完了项目在本地跑得很欢但到了部署到云服务器或者换一台电脑运行时问题一个一个蹦出来。这一节我把自己实际排查过的四个问题复盘一遍每个都给出现象、排查链路和最终修复方案。4.1 时间凭空少了8小时时区问题的排查全过程现象很经典本地Windows上运行接口返回的文章发布时间是正确的2025-06-18 10:30:00部署到Linux服务器后同一个接口返回的时间变成了2025-06-18 02:30:00整整少了8小时。排查过程是这样先怀疑数据库存储的时间不对直接在服务器上执行SELECT create_time FROM article发现数据库里存的就是10:30:00说明插入时没问题。再用Postman调接口看返回JSON发现返回的是02:30:00问题出现在Java程序读取数据库到JSON输出的环节。后来发现是MySQL驱动连接URL里没有指定时区服务器系统默认时区是UTCMySQL驱动按UTC解析日期再转成默认时区输出就产生了8小时偏移。修复方式是在数据库连接URL里显式指定时区spring: datasource: url: jdbc:mysql://localhost:3306/blog?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8同时Jackson的time-zone也写成GMT8保证JSON序列化时时间格式统一。这里建议任何环境都显式配置不要依赖服务器默认时区否则换一台服务器就出一次事。4.2 MyBatis Plus分页不生效插件配置被忽略另一个高频问题写好了Page查询控制台打了SQL日志发现SQL里竟然没有LIMIT而且page.getRecords()返回了全部数据total值也不对。一开始我以为是分页代码写错了反复检查Page参数都没问题。后来翻官方文档才想起来MyBatis Plus的分页功能不是内置的必须显式注册PaginationInnerInterceptor。如果漏了这段配置所有分页查询都会变成全表查询。更隐蔽的是如果项目中同时配置了多个MybatisPlusInterceptor的Bean或者有人手动在XML里写了Interceptor插件也可能被覆盖导致分页失效。我的排查建议是先看启动日志里有没有PaginationInnerInterceptor相关初始化信息再看控制台打印的SQL末尾有没有LIMIT关键词最后确认MyBatis Plus的版本和SpringBoot版本是否兼容。特别提醒一下网上很多旧教程用的是3.4.0以前的写法比如PaginationInterceptor这个类在新版本已经被移除改用MybatisPlusInterceptor加PaginationInnerInterceptor的组合版本不匹配也会出现分页失效。4.3 上线后刷新404前端路由与静态资源映射前端用的是Vue3的vue-router默认是HTML5 History模式。本地开发时一切正常前端打包成dist后放进SpringBoot的static目录结果首页能打开点击进入/article/1后按F5刷新直接404。排查逻辑是这样的SpringBoot处理请求时如果没有匹配的Controller接口就会返回404而Vue Router的History模式依赖服务器把所有未知路径重新指向index.html由前端路由接管。所以问题根源是SpringBoot没有做这个“回落”配置。修复方法是在SpringBoot里加一个路由映射把所有非API路径转发到index.htmlController public class PageForwardController { RequestMapping(value /{path:[^\\.]*}) public String forward() { return forward:/index.html; } }注意[^\\.]*这个正则它的意思是路径中不包含点号的请求全部转发到index.html这样/article/1会转过去而/js/app.js这类静态资源路径不会被误处理。4.4 数据库字段名消失Linux下MySQL的大小写敏感这是最诡异的一次本地Windows上项目跑得好好的部署到Linux服务器后一个查询接口直接报“Unknown column create_time in where clause”。我先检查了实体类字段名和数据库列名完全对得上。然后到服务器上执行SHOW CREATE TABLE article发现数据库表里的列名居然也叫create_time没问题。再检查Mapper XML里的SQL也没问题。最后才反应过来问题可能出在MyBatis Plus自动生成的SQL上我在实体类里用TableField(create_time)和TableName(article)做映射本地MySQL在Windows上表名和列名的大小写不敏感而Linux上的MySQL默认是大小写敏感如果建表时表名是大写或者实体类注解的表名和实际表名差一个字母的大小写就找不到了。解决方案是统一规范数据库表名、列名全部用snake_case小写实体类字段用camelCase注解里明确写TableName(article)。同时服务器上的MySQL配置lower_case_table_names1让表名强制小写。这一步做完问题就再也没有出现过。这个问题给我的教训很实在“本地能跑”和“部署能跑”是两回事所有路径、时区、大小写、编码问题只在Linux环境或换一台机器时才会暴露。5. 论文和答辩怎么准备把“常规系统”讲出差异点代码写完了系统跑起来了但对毕业设计来说论文和答辩往往才是决定成绩的关键一步。很多学生代码做得不错却栽在论文写得像产品说明书或者答辩时只会演示页面不会讲设计思路。5.1 论文里最能体现工作量的是这三章论文的摘要和绪论部分容易写成空话比如“随着互联网的发展博客已经成为人们分享知识的重要平台”。这种话可以写但不能整章都是。导师最关注的其实是三块内容第一需求分析。不要只罗列功能需求要写清楚每类用户的典型使用场景。比如普通游客浏览文章、注册用户评论、管理员管理所有内容。每一类场景对应哪些用例用例之间怎么关联。第二系统设计。包括架构设计、功能模块设计、数据库设计。数据库设计部分不要只贴建表语句要解释为什么这样设计哪些表是一对多哪些是多对多为什么要用中间表为什么给某个字段加索引索引解决了什么问题。第三系统测试。这一章最容易被当成凑字数但其实写好了是最有说服力的。建议做两层测试一层是功能测试用表格列出测试用例包含正常输入、边界输入、异常输入三类写明预期结果和实际结果另一层是接口测试可以用Postman或Apifox跑一遍核心接口把响应状态码和返回结构贴进去。有真实验证结果做支撑论文的严谨性会明显提升。5.2 系统测试部分用功能用例表和边界用例征服老师功能用例表不用面面俱到挑十几个核心用例就够了。我建议的表格结构是这样用例编号测试模块操作步骤输入数据预期结果实际结果TC-01用户注册打开注册页填写表单后提交新用户名、合法邮箱注册成功并跳转登录页与预期一致TC-02用户注册填写已存在的用户名提交已占用用户名提示“用户名已存在”与预期一致TC-03文章发布后台填写标题正文后保存草稿标题为空、正文有内容提示“标题不能为空”与预期一致TC-04评论对已发布文章发表评论评论内容500字评论成功并显示在列表与预期一致我实践下来老师对这个表格的容忍度很高只要格式清晰、结果真实他们不会追问太多。怕就怕为了凑表数把明显没测过的用例也写上去一问就露馅得不偿失。5.3 答辩高概率追问的四个问题与应对话术根据我和学弟学妹们的经验答辩现场提问集中在四个方向第一“你这个系统跟现有的开源博客系统有什么本质区别”这个问题的正确回答思路不是强调功能差异而是强调技术实践。你可以说“区别不在功能而在实现方式。开源博客系统大多是部署即用的产品而我在这个项目里完整走了一遍需求分析、数据库设计、接口设计、前后端开发和部署的流程重点是自己实现了JWT鉴权、Markdown内容处理和全链路的异常处理。”这些是你在项目里真实做的事情。第二“并发量大了怎么办”千万不要说“我的系统高性能高并发”。你得先承认当前系统以功能完整性为目标然后说清楚如果要做升级应该怎么做数据库加索引、引入Redis做缓存、把静态资源放到CDN、前端做懒加载、按需引入消息队列。能说出这几个方向说明你是理解瓶颈在哪里的。第三“这个SQL为什么这样写”只要你把数据库设计章节讲清楚这个一般不难。关键是答辩前把项目里自己写的复杂SQL都原文讲一遍把每个字段的作用说清楚。第四“部署方案是什么”要能讲清楚用了哪台服务器、用的什么系统、Java环境怎么装的、MySQL版本是多少、用不用Nginx、域名和端口怎么配的。哪怕你只是在本机跑通也要清楚这些环节。答辩还有个实用技巧提前准备两套账号。一套管理员账号一套普通用户账号用户名密码写在一张小纸条上放在电脑旁边。演示的时候不要临场注册、临场登录那些流程容易出意外。直接进系统按“首页展示→文章详情→评论→登录后台→发一篇文章→前台看到文章”的路径走一遍这条路你自己先跑十遍保证每个点击都顺畅比准备任何漂亮话都有用。说回到题目本身“基于SpringBoot的个人博客系统的设计与实现”能做的深度和广度都超出很多人预期。把基础功能做扎实把部署踩过的坑记录成测试章节把版本选择和数据表设计背后的理由想清楚这套系统就不仅仅是“又一个博客”而是你对SpringBoot整体理解的一份完整交付物。希望这份流程能帮你少走一些我走过的弯路。
返回列表