ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于Java的个人博客系统毕设:Spring Boot+MyBatis架构与部署答辩全攻略

基于Java的个人博客系统毕设:Spring Boot+MyBatis架构与部署答辩全攻略

简介:一份基于Java的个人博客系统毕业设计全套资料包,面向计算机相关专业毕业生与Java Web初学者,可覆盖选题、开发、文档整理与答辩展示的完整需求,尤其适合需要从零搭建完整项目的学习者。压缩包大小178.52MB,内含项目报告、答辩PPT、源代码、数据库文件与部署教程视频,对应需求分析、系统设计、模块划分、接口定义、数据表结构及核心编码实现等核心资料。技术栈涉及Servlet、JSP、JavaBean、MySQL等后端与数据库技术,以及HTML、CSS、JavaScript、Bootstrap等前端技术,代码分层清晰,便于理解MVC架构下的控制层、业务层与持久层。目前已有1347人浏览学习,适合作为毕业设计参考和Java Web实战练习。通过部署视频可快速完成环境配置、数据库导入与项目启动,配合答辩PPT和项目报告,能直观呈现系统功能与设计思路,帮助学习者少走弯路并提升工程实践能力,尤其对系统测试与部署环节可提供直接参照。

1. 基于 Java 的个人博客系统毕业设计:这份资源能帮你省掉哪一段路

每年毕设季,问得最多的就是「有没有一个能直接跑的 Java 项目」,这套基于 Java 的个人博客系统毕业设计资源包——项目报告 + 答辩 PPT + 源代码 + 数据库 + 部署视频——就是冲着这个需求来的。它的价值不是让你什么都不干,而是把搭框架、建库、配环境的几周时间压缩成几天,把精力留给真正要命的事:看懂表结构、改出自己讲得明白的代码、练到敢现场演示。适合 Java 方向学生、想快速交差的初级开发者,以及用博客练 Spring Boot 的入门选手。下面我按「架构立住 → 跑起来 → 改得动 → 扛住答辩」的顺序把这套资源吃透。

2. 把博客毕设拆开看:技术选型、表结构与文档框架先立住

2.1 为什么是 Spring Boot + MyBatis:选型理由要能扛住答辩提问

拿到源码第一步不是跑,而是先搞清楚它为什么长这样。常见的 Java 个人博客模板有两类:老一点的是 SSM(Spring + Spring MVC + MyBatis),新一点的是 Spring Boot + MyBatis 或 Spring Boot + JPA。现在的主流是 Spring Boot 2.x + MyBatis,理由很实际:Spring Boot 内嵌 Tomcat、自动配置数据源、打 jar 直接跑,省去 SSM 那一大堆 XML 配置;MyBatis 的 SQL 是自己写的,映射关系直观,答辩时随便问一句「你的查询怎么写」,你能当场说出 SQL 而不是解释一个黑匣子。

为什么不用 JPA?毕设规模下 JPA 的自动建表和懒加载反而是负担,尤其是多表关联时 Hibernate 的 N+1 查询问题讲不清楚容易翻车。MyBatis 加一个 MyBatis-Plus 的 BaseMapper,单表增删改查几乎不用写 SQL,代码量砍一半。模板引擎这边,老项目用 JSP 的不少,但现在答辩老师普遍反感 JSP 的部署方式——改一个页面要重新编译。我一般建议认准 Thymeleaf:后端渲染、天然支持 Spring Boot、改页面只要改模板文件,刷新浏览器就能看到效果。前后端分离的 Vue + REST 方案在工程上是更现代的,但对毕设来说要额外处理跨域、Token、前端打包,演示环境一多,踩坑成本翻倍。

2.2 五张核心表:文章、分类、标签、评论、用户的关系一次理清

数据库是整个项目里最值得花时间搞懂的部分。一个标准的 Java 个人博客系统,表结构逃不出这五张:用户表、文章表、分类表、标签表、评论表,加上一张文章和标签的多对多关联表。先建库,再建表。下面是完整可执行的 MySQL 脚本,我按通常的模板写法给你拆开。

-- 用户表 CREATE TABLE `t_user` ( `id` INT NOT NULL AUTO_INCREMENT COMMENT '用户ID', `username` VARCHAR(50) NOT NULL COMMENT '登录名', `password` VARCHAR(100) NOT NULL COMMENT '密码,推荐BCrypt密文', `nickname` VARCHAR(50) DEFAULT NULL COMMENT '显示昵称', `role` TINYINT NOT NULL DEFAULT 1 COMMENT '权限:1管理员 0普通用户', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- 文章表 CREATE TABLE `t_article` ( `id` INT NOT NULL AUTO_INCREMENT COMMENT '文章ID', `title` VARCHAR(200) NOT NULL COMMENT '标题', `summary` VARCHAR(500) DEFAULT NULL COMMENT '摘要', `content` LONGTEXT NOT NULL COMMENT '正文,存HTML或Markdown', `category_id` INT DEFAULT NULL COMMENT '所属分类ID', `user_id` INT NOT NULL COMMENT '作者ID', `view_count` INT NOT NULL DEFAULT 0 COMMENT '浏览量', `status` TINYINT NOT NULL DEFAULT 0 COMMENT '0草稿 1已发布', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_category` (`category_id`), KEY `idx_user` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章表';
-- 分类表 / 标签表 / 评论表 CREATE TABLE `t_category` ( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) NOT NULL, `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分类表'; CREATE TABLE `t_tag` ( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='标签表'; CREATE TABLE `t_comment` ( `id` INT NOT NULL AUTO_INCREMENT, `article_id` INT NOT NULL COMMENT '文章ID', `user_id` INT DEFAULT NULL COMMENT '评论人ID,游客为NULL', `content` VARCHAR(1000) NOT NULL, `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_article` (`article_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评论表';
-- 文章-标签关联表 CREATE TABLE `t_article_tag` ( `article_id` INT NOT NULL, `tag_id` INT NOT NULL, PRIMARY KEY (`article_id`, `tag_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章标签关联表';

几个参数你答辩时最好能主动讲出来。第一,engine=InnoDB支持事务和行级锁,博客这种读写混合的小项目足够;第二,charset=utf8mb4而不是utf8,因为表情符号也要入库,utf8 存不下 emoji 会直接报错;第三,create_time用DEFAULT CURRENT_TIMESTAMP,插入时不用手动塞时间;第四,外键我建议不建物理外键,只建普通索引,因为物理外键在删除分类或用户时会连锁报错,毕设阶段用逻辑关联在代码层控制就够了。第五,t_article_tag这种关联表的主键用的是联合主键,防止同一篇文章打同一个标签两遍。

2.3 项目报告和答辩 PPT:三块内容决定你是 60 分还是 90 分

源码再漂亮,报告和 PPT 写不明白照样被卡。我的经验是,无论模板里原本写了什么,你至少要在这三块上投入时间。第一块是需求分析和用例图,别写「本系统实现了用户管理」这种废话,要写「管理员可以发布、编辑、删除文章,游客可以按分类和标签浏览文章并发表评论」,每个角色配两三个典型流程。第二块是系统设计,把架构图画成三层:控制层(Controller)、业务层(Service)、数据访问层(Mapper),再把 2.2 里的 ER 图贴上去,标注主键、外键和一对多关系。第三块是测试结果,除了功能测试用例表,强烈建议放两三个接口测试截图——用 Postman 调 /article/list、/admin/article/save 这些接口,把返回 JSON 贴进 PPT,比十页功能截图都有说服力。

文档这块有个常见翻车点:直接从别的毕设复制需求分析,导致「系统角色」还留着根本没实现的后台评论审核功能。答辩老师对项目里没有的东西问得最狠。我建议对着自己的功能清单一项项核,报告里出现的每个功能,代码里必须能找到对应入口;代码里有的功能,报告里必须有截图。能做到这个闭环,答辩基本就稳了。

3. 从源码到跑起来:部署视频没拍全的关键步骤与参数

3.1 环境准备:JDK、Maven、MySQL 的版本匹配关系

部署视频通常会快进这段,但环境不匹配是「跑不起来」的第一大原因,这不是玄学,是版本兼容问题。先把三个版本对清楚,再动手。

java -version mvn -version mysql --version

三条命令分别查 JDK、Maven 和 MySQL 的版本。常见的 Java 个人博客模板对应的是 JDK 1.8 + Maven 3.6+ + MySQL 5.7 或 8.0。如果你电脑上装的是 JDK 17,直接跑 Spring Boot 2.x 老模板,启动时大概率报UnsupportedClassVersionError或者 CGLIB 相关错误,因为新版 JDK 移除了部分反射权限。两个处理办法:一是装一个 JDK 1.8 并在 IDEA 的 Project Structure 里切过去;二是把 pom.xml 里的 Spring Boot 版本升到 2.7 以上,同时检查 MyBatis 和 Thymeleaf 的兼容性。我一般倾向第一种,成本最低,也最贴近模板原作者的运行环境。

MySQL 这块注意一个小细节:5.7 和 8.0 的驱动类名不一样。5.7 用com.mysql.jdbc.Driver,8.0 用com.mysql.cj.jdbc.Driver,而且 8.0 的连接 URL 必须带时区参数,不然报Communications link failure。下面配置章节我会把标准写法给出来。如果你用 IDEA,直接把源码目录当 Maven 项目导入,等依赖下载完成,src/main/java下的启动类会有一个绿色的运行按钮,点了就能起——但先别急,数据库还没导。

3.2 导入数据库:先建库再导数据,别跳过 charset

资源包里通常会有一个.sql文件,可能是blog.sql或database.sql。导入前先做一件事:打开看看文件开头有没有CREATE DATABASE语句。有的话,直接一条命令全导;没有的话,先建库再导。

mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS blog DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;" mysql -u root -p blog < blog.sql

第一行创建名为 blog 的数据库,DEFAULT CHARSET 和 COLLATE 必须显式指定,因为有些 MySQL 服务器的默认字符集是 latin1,表即使写了 utf8mb4,建库这一步兜底错了后面查中文会乱码。第二行把 SQL 文件导入到 blog 库。成功后执行mysql -u root -p -e "USE blog; SHOW TABLES;",能看到 t_user、t_article 这些表就对了。

还有一坑:有些模板的 SQL 文件里已经写了USE blog;,但你本地库名不叫 blog 叫 blog_system,导入时就会把数据写进它指定的库,你的配置文件却连着一个空库。遇到这种情况,要么建一个和文件里同名的库,要么把 SQL 文件里的USE语句注释掉再导入。导入完了顺手查一下 t_user 表有没有初始账号数据,没有的话自己插入一条管理员账号,密码先用最简单的 123456,登录跑通后再改。

3.3 application.yml 的五个必调参数:改错一个就起不来

源码里在src/main/resources下找到application.yml或application.properties。Spring Boot 2.x 模板基本都用 yml 格式,层次比 properties 清楚。下面是按标准写法给出的最小可用配置:

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 你自己的密码 driver-class-name: com.mysql.cj.jdbc.Driver thymeleaf: cache: false mybatis-plus: mapper-locations: classpath:mapper/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

五个重点逐一说明。第一,server.port改 8080 以外,要保证没被占用。第二,URL 里serverTimezone=Asia/Shanghai是 MySQL 8.0 的必填项,缺了直接连接失败。第三,characterEncoding=utf8配合数据库的 utf8mb4 保证中文不乱码,URL 里的useUnicode=true也顺手留着。第四,spring.thymeleaf.cache: false是开发期福利,改 HTML 模板不重启就能看到效果,如果设成 true,你改了首页死活没变化,就是这个在作怪。第五,log-impl配成 StdOutImpl 后,每次 SQL 执行都会打印到控制台,调试和答辩排错都靠它。密码字段提醒一句:本地开发可以明文,但不要把这个配置提交到公开的 GitHub 仓库,源代码管理里把配置文件的敏感信息替换成环境变量是基本素质。

3.4 本地启动和打包:mvn 两种方式的区别

环境配好、库导好、配置改好,就可以启动了。IDEA 里直接点运行最省事,但更推荐命令行方式,因为你以后要写部署文档,里面所有命令必须是命令行可执行的。

mvn spring-boot:run

这是开发模式,前台运行,按 Ctrl+C 结束,日志实时滚。适合本地调代码。

mvn clean package -DskipTests java -jar target/blog-0.0.1-SNAPSHOT.jar

这是生产模式,先跳过测试打包成 jar,再java -jar跑起来。打包完你会发现 target 目录下多了个几十 MB 的 jar,里面带着内嵌 Tomcat,扔到任何装了 JDK 的机器上都能起,这才是部署视频里常说的「可执行文件」。启动日志里看到Tomcat started on port(s): 8080就成功了,浏览器访问http://localhost:8080,如果能打开首页,整个链路就算跑通。接着做两件事:登录后台,然后发一篇测试文章,确认数据库的增删改查都是好的。到这一步,你已经完成了这段毕设最「虚」但最容易卡住的环节。

4. 源码骨架怎么读、怎么改:核心模块的套路和必调参数

4.1 登录与权限:拦截器是最适合毕设的轻量方案

把项目跑起来后,就该打开源码认真读了。我不建议一开始就从 controller 逐行看,而是先顺着一个请求走完:你的登录请求是怎么进到后台的?大多数个人博客模板用的是拦截器方案而不是 Spring Security,因为后者的过滤器链、UserDetailsService、权限配置对毕设来说太重,讲不清楚还容易出配置问题。拦截器的实现就是一个类加一段注册代码。

@Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object loginUser = request.getSession().getAttribute("loginUser"); if (loginUser == null) { response.sendRedirect("/admin/login"); return false; } return true; } }
@Configuration public class WebConfig implements WebMvcConfigurer { @Resource private LoginInterceptor loginInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor) .addPathPatterns("/admin/**") .excludePathPatterns("/admin/login", "/admin/doLogin", "/css/**", "/js/**", "/images/**"); } }

这段逻辑的关键在excludePathPatterns:登录接口和静态资源必须放行,否则样式全丢、登录接口也进不去。真实模板中这几个放行路径经常写漏写错,表现为「登录成功了但后台页面没有样式」,八成是/css/**这类没放行,或者 JSP 老模板把静态资源放在 webapp 下导致路径对不上。

读取请求处理流程时,顺带把登录密码的校验方式看一眼。好的模板会存 BCrypt 密文,答辩时可以主动提一句「密码不是明文存储,用的 BCrypt 加盐哈希」。如果你的模板是明文存密码,我建议改掉:在 Service 里用BCryptPasswordEncoder的matches方法做校验,改动量不大,但这是答辩老师最喜欢的细节之一。

4.2 文章增删改查:MyBatis-Plus 让代码少写一半

文章模块是个人博客系统的核心,你要能讲清楚「新增一篇文章从页面到数据库走过了什么」。常见模板的 Mapper 层写法是 MyBatis-Plus 风格,接口长这样:

public interface ArticleMapper extends BaseMapper<Article> { }

你没看错,空接口就够了。BaseMapper<T>内置了insert、deleteById、updateById、selectById、selectList等十几个通用方法,单表 CRUD 零 SQL。真正需要写条件查询的地方,用的是LambdaQueryWrapper,比如后台分页查文章列表:

@Override public Page<Article> pageArticles(int pageNum, int pageSize, String keyword, Long categoryId) { LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>(); wrapper.like(StringUtils.hasText(keyword), Article::getTitle, keyword) .eq(categoryId != null, Article::getCategoryId, categoryId) .orderByDesc(Article::getCreateTime); return articleMapper.selectPage(new Page<>(pageNum, pageSize), wrapper); }

参数说明:like和eq的第一个参数是布尔条件,为 true 时该条件才生效,这样搜索框没填关键词时就自动跳过模糊查询,不需要手动写三个 if。Article::getTitle是方法引用,MyBatis-Plus 靠它解析成数据库字段名,避免了硬编码字符串导致改字段名后 SQL 崩掉。selectPage的返回值Page里带着records(当前页数据)、total(总条数)、current(当前页码)、size(每页条数),前端遍历records,分页组件读这四个属性就够。

答辩时老师常追问「分页怎么实现的」,你要能答出两层:应用层用 Page 对象传页码和每页大小,MyBatis-Plus 底层自动拼接LIMIT(MySQL)或ROWNUM(Oracle)语句,数据库层返回当页数据而不是全表。如果你的模板不是 MyBatis-Plus 而是纯 MyBatis 的 XML 写法,也没问题,去src/main/resources/mapper/下打开 ArticleMapper.xml,你会看到selectPageByCondition这类手写 SQL,那里才是你真正要读的地方。

4.3 前端 Thymeleaf:三个必改页面和它们的属性套路

前端模板页在src/main/resources/templates/下,常见结构是index.html(前台首页)、article.html(文章详情)、admin/(后台管理)。Thymeleaf 的语法核心就是th:属性,看懂了下面这段首页列表,其他页面都是变体:

<ul> <li th:each="article, stat : ${page.records}"> <a th:href="@{/article/{id}(id=${article.id})}" th:text="${article.title}">文章标题</a> <span th:text="${#dates.format(article.createTime, 'yyyy-MM-dd')}">发布日期</span> <em th:text="'共' + ${article.viewCount} + '次浏览'">浏览量</em> </li> </ul>

th:each是循环,page.records对应 Controller 放进 Model 的分页数据,stat是循环计数器,可以取stat.index拿序号。th:href的@{/article/{id}(id=${article.id})}是带参数的 URL 写法,比字符串拼接安全,自动做 URL 编码。th:text输出纯文本,如果文章正文存的是 HTML,详情页要用th:utext输出,否则标签会被转义成文字显示。这是毕设里出现频率最高的 bug:正文全部变成了带<p>标签的源码,就是因为用了th:text。

改前端时两条血泪经验:第一,页面里的静态资源路径一律用th:href="@{/css/style.css}",别在 HTML 里手写/css/style.css,否则项目部署到子路径时全部 404;第二,后台表单提交改成 POST 后,Controller 要加@PostMapping并处理重定向,表单验证出错时用BindingResult把错误信息回显到页面。你把这些点改过一遍,源码就算是真正读懂了。

5. 部署与答辩避坑:高频翻车现象、原因与排查方法

5.1 数据库连不上:时区、编码、未建库三类报错

现象一:启动日志报Communications link failure或The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized。原因:MySQL 8.0 要求连接串显式指定时区,而配置里没带serverTimezone。解决:在application.yml的 URL 末尾加上&serverTimezone=Asia/Shanghai,重启。

现象二:控制台报Unknown database 'blog'。原因:SQL 文件没导入,或者导入时库名和连接串不一致。解决:按 3.2 的命令重新建库导入,然后确认配置文件里的库名和实际库名一字不差。注意大小写,MySQL 在 Linux 下表名库名是区分大小写的。

现象三:中文乱码,页面上全是???。原因:建库时没指定utf8mb4,或者 JDBC URL 少了characterEncoding=utf8。解决:把库、表、连接串三级全部统一成utf8mb4 / utf8,改完重新启动并刷新页面。这三个问题占了「数据库连不上」九成以上,任何一个都可以在答辩现场直接让你翻车,提前用上面的命令自查一遍。

5.2 端口被占用和项目起不来

现象:启动日志有Port 8080 was already in use。原因:之前运行的后台程序没退干净,或者本地有其他服务占了 8080。排查命令:

# Windows 查看占用 8080 的进程 netstat -ano | findstr 8080 taskkill /PID 你的进程号 /F # macOS / Linux lsof -i :8080 kill -9 你的进程号

杀掉进程后重启即可。另一个起不来的场景是java -jar启动后访问 404,原因多半是模板引擎页面路径不对——Thymeleaf 默认去templates/下找 HTML,如果你的页面放到了static/下,Controller 返回的视图名永远找不到,控制台还会打一行Circular view path [index]的警告。解决是确认视图名和templates/下的文件名完全一致,区分大小写。

5.3 打包后资源丢失和静态 404

现象:IDEA 里运行一切正常,按 3.4 打包成 jar 后,再访问发现 CSS、JS 全部 404。原因:打包时资源文件没被包含进 jar,或者代码里用了硬编码路径。解决:打开pom.xml,确认<build>段里有<resources>配置把src/main/resources纳入打包;然后把页面里的/css/xx.css全部改成th:href动态写法,重新mvn clean package。这个坑几乎人人都踩,提前踩完,部署演示时就多一分从容。

还有个冷门但常发生的:SQL 文件没被包进 jar。如果你的初始化 SQL 放在resources/sql/下,而 pom 没包含**/*.sql,部署到新机器上就会「有代码没数据」。解决是在resources配置里加一条<include>**/*.sql</include>,或者干脆把 SQL 文件和 jar 放在一起,手动导入。

5.4 答辩演示前的四个准备动作

演示翻车往往不是技术问题,是流程问题。第一,准备一个专用演示账号并确认密码正确,不要现场输密码,手一抖就完蛋。第二,预置演示数据至少 5 篇文章、3 个分类、4 个标签、2 条评论,别打开后台发现是空库。第三,把log-impl的 SQL 日志留着,演示时故意操作一次新增文章,让控制台滚出INSERT INTO语句,这是证明「你懂底层」的现场证据。第四,断网检查——如果页面里引用了外部 CDN 的图标或字体,答辩教室没网时页面会很难看,提前把静态资源本地化。这四条做完,心态上已经赢了七成。

5.5 初始账号找不到:模板最容易被忽略的坑

现象:数据库导入成功,但登录页面输什么密码都报错。原因:SQL 文件里的初始用户表数据有,但密码是加密串,你输的 123456 明文自然匹配不上。解决:找到项目里处理登录的 Service,看它用的是 BCrypt、MD5 还是别的算法;如果是 BCrypt,去在线生成器把 123456 加密后 UPDATE 进用户表;如果是 MD5,同样生成密文后更新。这条我建议无论如何都提前做好,因为它是「看起来全对但就是进不去」的典型黑匣子问题,也是我见过导致答辩现场直接断片的头号原因。

6. 让毕设从「能跑」到「能加分」:三个进阶方向与一个验证方法

基础功能全通后,你有余力就可以往加分项上走,优先级按投入产出比排。第一个是 Markdown 富文本编辑:把文章 content 字段存 Markdown 源文,展示时用 commonmark-java 库渲染成 HTML,改动只涉及编辑页和详情页两个地方,答辩却能讲出「编辑器层和数据展示层分离」的设计思想。第二个是全文搜索:别自己用LIKE '%keyword%'硬扛,数据量大了性能断崖,直接给文章表加 MySQL 全文索引,用MATCH(title, content) AGAINST('关键词')查询,一句话就能讲清楚「数据库级的全文检索方案」。

第三个是图片上传。给后台加一个图片上传接口,存储到本地目录,再把访问路径映射成虚拟 URL。这个功能几乎每个答辩老师都会问「你的图片存哪」,你能答出「服务器目录 + 虚拟映射 + 数据库存路径」三层,比答「存数据库」高一截。

验证方法用一条命令就能完成。启动服务后,用 curl 连打三个接口验证核心链路:

curl -X POST http://localhost:8080/admin/doLogin -d "username=admin&password=123456" curl http://localhost:8080/article/list?pageNum=1&pageSize=5 curl -X POST http://localhost:8080/admin/article/save -d "title=测试&content=内容&categoryId=1"

第一条看登录是否返回成功,第二条看列表是否返回 JSON,第三条写一条测试数据后去数据库里查SELECT * FROM t_article ORDER BY id DESC LIMIT 1;,确认落库成功。这三步做完,你的毕设从代码、数据到部署就是一条完整的、经得起验证的链路。我个人的习惯是每次改完代码都跑一遍这三条命令,确认没有「改一处崩三处」。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进