接到一个叫 Springboot 品牌购物官网 rmu1i 的项目时,我第一反应是:这是典型的用 Spring Boot 做的企业品牌官网,附带一套完整的前后台代码、数据库脚本、调试部署说明、开发环境配置,再加一份万字以上的论文文档。这种项目看着简单,但真正从零到一跑通、能讲清楚每个模块为什么这么设计,需要踩不少坑。
这篇文章就以这个项目为例,从整体设计、技术选型、环境搭建、核心模块实现到论文写作,做一次完整的实操拆解。不管你是准备毕设、课程设计,还是想拿现成源码学 Spring Boot 开发,都能从中找到可直接抄作业的方法。我尽量把每一步的“为什么”也说清楚,而不是只给一个能跑的结果。
1. 项目概览与目标拆解
1.1 品牌购物官网解决了什么问题
品牌购物官网和普通电商平台的核心差异在于“品牌调性”。淘宝、京东这类平台追求的是海量商品和标准化交易,而品牌官网更看重形象展示、商品故事、会员服务和闭环交易。比如一个服饰品牌官网,首页通常是大幅品牌形象图、新品推荐、品牌理念介绍,再往下才是商品列表、购物车、下单流程。
这套 rmu1i 项目就是围绕这个需求设计的。前台部分包含首页轮播、品牌故事、产品中心、商品搜索、购物车、订单提交等模块;后台部分包含管理员登录、商品分类管理、商品管理、轮播图管理、订单管理、会员管理等模块。整体是一个“展示型官网 + 基础交易系统”的组合,既不像商城那样复杂到需要多种营销规则,又能覆盖购物流程的核心闭环。
它适合谁用?第一类是计算机相关专业的毕业生,需要一门体面的课设或毕设项目;第二类是刚学完 Spring Boot 基础,想找一个完整项目看代码结构的开发者;第三类是半路接手别人项目的同学,需要快速搞懂“源码、数据库、部署环境”这些交付物分别怎么用。这篇文章重点面向这三类人。
1.2 交付物拆解:源码、数据库、论文文档、系统界面
我见过很多同学拿到项目包之后,直接打开 IDEA 就点运行,结果不是缺依赖就是数据库连不上。原因很简单:没搞明白交付物里每样东西存在的意义。
一套标准的项目交付物通常包含四块:
- 程序源码:Spring Boot 后端工程,可能是 Maven 项目,也可能带前端模板或 Vue 构建产物。注意看有没有前端的 node_modules,如果没有,就需要用前端构建工具重新打包。
- 数据库脚本:通常是一个 .sql 文件,里面既有建库建表语句,也有初始化数据。执行后就能得到项目需要的所有表和示例数据。
- 调试部署文档:一般是一个 README 或部署手记,写清楚 JDK 版本、Maven 配置、数据库连接修改点、启动命令、默认账号密码。
- 论文文档:多数是 Word 文档,1 万字以上,含需求分析、系统设计、功能实现、测试等内容,对应毕设论文的完整排版。
rMU1i 这个项目代号其实不用深究,它通常只是工程名或版本标识。你在改项目的时候,可以把包名和项目名改成自己学校的学号或题目,比如 brand-mall,避免答辩时导师问起“rmu1i 是什么意思”。
拿到项目后建议按这个顺序处理:先看部署文档,再导入数据库,最后启动后端。如果跳过前两步,大概率会遇到 404、数据库连接失败之类的问题。
2. 技术选型与核心架构拆解
2.1 为什么用 Spring Boot 而不是别的框架
选 Spring Boot 做这类官网项目,几乎是顺理成章的事。
首先,Spring Boot 把 Spring 繁琐的 XML 配置大幅简化了,内嵌了 Tomcat,前端控制器、类型转换、数据校验这些能力都开箱即用。对于学生项目来说,配置成本低,出错的概率也低。
其次,Spring Boot 生态成熟。用户管理用 Spring Security 或拦截器解决,数据库访问用 Spring Data JPA 或 MyBatis Plus,文件上传可以用本地存储或 MinIO 之类。就算你对很多组件不熟,也能通过官方 Starter 快速集成。
再有,企业里面对这种“官网 + 交易”场景,Spring Boot 本身就是最常见的后端选择。在论文里写“基于 Spring Boot 的某某系统设计与实现”答辩时比较有说服力,也容易延伸成高并发、缓存、微服务等设计与讨论。
需要补充的是,前端选型上,这类项目有两种做法:一种是传统模板渲染,使用 Thymeleaf,页面由服务端直接生成;另一种是前后端分离,Vue 打包成静态资源放到 Spring Boot 的 static 目录,或者单独部署到 Nginx。rmu1i 这类项目多数采用后者,因为论文中需要体现“前后端分离”这个热点,界面效果也更灵活。
2.2 数据库设计:核心表结构
数据库设计是这类项目最容易做得混乱的地方。品牌购物官网虽小,但表不能太少,否则论文撑不起来,功能也撑不起来。
我按常见表结构整理如下:
| 表名 | 状态 | 用途 |
|---|---|---|
| user | 用户表 | 存储前台注册用户,用户名、密码(加密)、手机号、头像 |
| admin | 管理员表 | 后台登录账号,通常预先初始化一条记录 |
| category | 商品分类表 | 父级分类和子级分类,可以用 pid 实现树形结构 |
| product | 商品表 | 商品名称、价格、库存、主图、详情、上下架状态 |
| product_image | 商品图片表 | 一个商品对应多张图片 |
| banner | 轮播图表 | 首页 banner 图片、跳转链接、排序值 |
| article | 品牌资讯表 | 品牌新闻、活动公告,官网内容的一部分 |
| cart | 购物车表 | 用户 ID、商品 ID、数量 |
| order | 订单表 | 订单号、用户 ID、总价、收货信息、支付状态 |
| order_item | 订单明细表 | 每个订单包含的商品快照、单价、数量 |
| address | 收货地址表 | 用户收货地址,下单时选择 |
| feedback | 留言反馈表 | 访客留言,体现品牌官网互动功能 |
关键点有三个:
一是商品表要尽量独立,图片放在单独表里。商品详情页通常要展示多张图,放一个字段里逗号分隔看着省事,但查询和扩展都会变麻烦。做答辩时被问“为什么要有图片表”,这就是加分项。
二是订单表里有些字段可以做冗余,比如下单时的商品名称和单价、收货人手机号。很多人不理解为什么不在订单明细表里关联商品表,而是把商品信息复制一份。原因很简单:商品之后可能会改价、改名或删除,但订单历史不能被影响。快照冗余,是交易系统的常见做法。
三是字符集必须用 utf8mb4,否则用户提交的表情符号、特殊字符会报错或变成乱码。这一点在 MySQL 5.7 和 8.0 中尤其重要。
2.3 项目分层与 pom.xml 关键依赖
Spring Boot 项目的代码分层通常是这样:
- controller:接收请求,参数校验,返回结果
- service:业务逻辑,事务控制
- mapper/repository:数据库持久层操作
- entity/domain:数据库实体映射
- config:配置类,比如跨域配置、拦截器配置
- common/utils:公共类、工具类
这种分层结构在论文中能直接对应到“系统设计”章节。Controller 尽量只做参数接收和结果封装,不要写大段业务代码;Service 做事务逻辑;Mapper 只做 SQL 相关操作。哪怕功能简单,也要坚持这个结构,后续扩展会轻松很多。
pom.xml 里的依赖也很有代表性。一个典型的品牌购物官网项目通常包含:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>MyBatis Plus 这类增强组件很适合学生项目,它内置了分页插件,提供大量 CRUD 方法,可以让你的代码量减少不少,同时论文里还能写“基于 MyBatis Plus 优化了数据持久层”。但不要过度依赖,核心业务查询最好手写 SQL,这样论文测试部分才会有真实的 SQL 记录。
3. 开发环境准备与调试部署全流程
3.1 本地开发环境搭建:JDK、Maven、IDEA、MySQL
开发环境没搭建好,后面全是泪。这个项目最稳妥的组合是:
- JDK 1.8 或 JDK 11,Spring Boot 2.x 用 JDK 8 很少出问题
- Maven 3.6 以上,并配置阿里云镜像,否则下载依赖会等到怀疑人生
- IDEA 2020 以上版本,社区版也行
- MySQL 5.7 或 8.0,取决于数据库脚本的版本
- Navicat 或 DBeaver 作为数据库客户端
其中最容易出错的是 JDK 版本。现在很多人电脑默认装了 JDK 17,而项目里 Spring Boot 2.x 用 JDK 17 时,反射、依赖注入可能报异常。可以先看项目里的 pom.xml,确认 spring-boot-parent 版本。如果是 2.3.x 或 2.5.x,建议用 JDK 8;如果是 3.x,则必须使用 JDK 17 及以上。
Maven 的 settings.xml 建议像下面这样配置阿里云镜像:
<mirror> <id>aliyunmaven</id> <mirrorOf>central</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/central</url> </mirror>不配置镜像的话,第一次导入 Spring Boot 项目要下载上百 MB 依赖,经常卡死或超时。这个坑我遇到太多次了。
3.2 数据库初始化与配置修改
数据库这步是最关键也最容易被跳过的。
先用 Navicat 或命令行创建一个数据库,比如 brand_mall。然后直接运行项目里提供的 SQL 脚本。注意,如果 SQL 脚本里有 CREATE DATABASE 语句,就不要先在客户端创建库,直接整体执行就行;如果只有 CREATE TABLE,就需要先建库再导入。
导入成功后,重点检查三张表的数据:admin 表是否有一条管理员账号,category 表是否有分类数据,product 表是否有商品数据。如果这三张表是空的,项目跑起来后前台首页可能一片空白,后台登录也进不去。
接下来打开后端配置文件 application.yml,找到数据源配置:
spring: datasource: url: jdbc:mysql://localhost:3306/brand_mall?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456需要改的就是密码,以及如果数据库不在本机,要把 localhost 改成服务器 IP。这里的 serverTimezone=Asia/Shanghai 必须保留,否则 MySQL 8.0 会报时区错误。
改完配置后,不要急着启动。先在数据库客户端手动执行一条查询,确认账号密码能不能连上。能查出来,基本就成功了一半。
3.3 源码导入与启动调试
用 IDEA 导入项目时,选择 File -> Open,选中项目的 pom.xml 或根目录,IDEA 会识别为 Maven 工程。之后等待 Maven 依赖下载完成。首次导入可能需要几分钟,IDEA 右下角有进度条,等它跑完再看。
启动方式很直接:找到主类,一般是Application结尾的类,里面有@SpringBootApplication注解,右键运行。
启动成功的标志不是控制台没有报错,而是出现类似下面的日志:
Tomcat started on port(s): 8080 (http)然后浏览器访问 http://localhost:8080。如果能看到品牌官网首页,说明启动成功。如果首页是空白或提示 404,先按 F12 看网络请求是接口报错,还是静态资源加载失败。
前台用户端和管理员端通常有两个入口。前台在/或/index,后台在/admin,默认管理员账号往往是 admin / 123456。如果不知道,就去 SQL 脚本里搜 admin 表的密码字段,可能是明文,也可能是 BCrypt 加密后的字符串。
3.4 打包部署:从本地到服务器
不少人的毕设要求做一个“能部署的演示”,这时候需要把项目打包成 jar 放到服务器上。在 IDEA 里先执行 Maven 的 package,成功后 target 目录下会出现一个 xxx.jar。
本地测试时可以用:
java -jar brand-mall.jar指定端口:
java -jar brand-mall.jar --server.port=8081Linux 服务器上部署,推荐用 nohup 方式:
nohup java -jar brand-mall.jar > app.log 2>&1 &看日志用:
tail -f app.log这里要注意:服务器上的 MySQL 必须允许远程连接,并检查安全组是否放行 3306 端口。很多人卡在这一步,本地能跑,服务器上一直报Access denied for user,就是账号权限没开。
前端如果做了分离部署,需要把 Vue 打包后的 dist 目录放到 Nginx 的 html 下,然后配置反向代理到后端接口。具体 Nginx 配置如下:
server { listen 80; server_name yourdomain.com; location / { root /usr/share/nginx/dist; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; } }这样前后端就在同一个域下,避免了跨域问题。
4. 核心功能模块与实现细节
4.1 首页品牌展示与商品搜索模块
首页是品牌官网的脸面,也是论文中截图最多的地方。一般来说,首页包含几个接口:
- 查询轮播图列表
- 查询推荐商品
- 查询商品分类
- 按分类或关键词分页搜索商品
轮播图的接口通常比较简单:
@GetMapping("/api/banner/list") public Result listBanner() { List<Banner> bannerList = bannerService.list(); return Result.success(bannerList); }商品分页查询建议用 MyBatis Plus 的分页插件:
@GetMapping("/api/product/page") public Result pageProduct(@RequestParam Integer page, @RequestParam Integer size, @RequestParam(required = false) Integer categoryId, @RequestParam(required = false) String keyword) { Page<Product> page = new Page<>(page, size); entityWrapper.eq(categoryId != null, "category_id", categoryId) .like(keyword != null, "name", keyword); productService.page(page, wrapper); return Result.success(page); }这里有几个设计点值得在论文中展开:一是分类和关键词是可选参数,不能因为没传就报错;二是分页对象里记录了 total、current、size,前端可以据此渲染分页器;三是商品状态必须过滤,只显示上架商品,避免用户看到未上架的测试数据。
页面上的图片路径不要写死。很多新手会直接在数据库里存http://localhost:8080/img/xxx.jpg,后面部署到服务器全都会失效。正确的做法是存相对路径,比如/upload/2024/xxx.jpg,接口返回时再拼接当前项目域名。这一条建议写进论文的“系统优化”部分,很加分。
4.2 购物车、订单与事务处理
购物车的实现有几种方案:纯数据库表、Redis 缓存、浏览器 localStorage。rMU1i 这类项目通常用数据库表实现,逻辑清晰,论文也好写。
购物车核心操作是加购、修改数量、删除、结算。加购逻辑要注意一个细节:如果用户已经加过同一商品,应该做数量累加,而不是插入一条重复记录。对应的 SQL 可以先查一次,再决定 update 还是 insert。
下单流程是整个后端业务中最容易出现 bug 的地方。典型的流程是:
- 前端提交地址和购物车条目
- 后端校验用户是否登录
- 校验商品是否上架、库存是否足够
- 生成订单主表记录
- 生成订单明细快照
- 扣减库存
- 清空购物车
- 返回订单号
这个流程必须加事务控制,否则扣库存和生成订单分开,就会出现“订单没生成但库存被扣”或“订单生成了但库存没扣”的情况。使用 Spring 的@Transactional可以轻松解决:
@Transactional(rollbackFor = Exception.class) public Order createOrder(OrderCreateDTO dto) { // 校验商品 // 创建订单主记录 // 创建订单明细 // 扣库存 // 清购物车 }在论文的“系统实现”部分,把这段流程画成表格或伪代码描述会很清晰。需要注意rollbackFor = Exception.class很关键,默认情况下 RuntimeException 才会触发回滚,某些 checked 异常不会,为了保险一定要指定所有异常都回滚。
订单状态也不要设计得太复杂。常见状态为 0 待支付、1 已支付、2 已发货、3 已完成、4 已取消。只要在订单表中存一个状态字段即可。答辩时如果被追问如何防止重复下单,可以说加上用户 ID 和下单时间的唯一索引或做幂等校验。
4.3 后台管理与权限控制
后台管理系统一般都有一个简单的登录和请求拦截。很多学生项目是只靠前端隐藏菜单来实现权限,这等于形同虚设。后端必须做拦截,哪怕只是简单判断 session 或 token。
一种简单可用的做法是:
- 用户登录成功后,返回一个 UUID 作为 token,存到数据库或 Redis
- 前端每次请求后台接口时在请求头携带 token
- 后端写一个拦截器,检查后台接口的 token 是否有效
如果项目里引入了 Spring Security,也可以用它来做。但要注意,Spring Security 的过滤器链配置对新手来说有点绕,如果只是为了毕业设计,自己写拦截器反而更可控,而且论文中有完整的“登录验证模块”可以写。
后台的商品管理通常包含增删改查和图片上传。图片上传需要注意两点:一是保存路径不要放在项目根目录里,否则重新打包后图片会丢;二是要考虑文件名重复问题,建议用 UUID 或时间戳重命名。
这样处理:
String originalFilename = file.getOriginalFilename(); String extName = originalFilename.substring(originalFilename.lastIndexOf(".")); String newFileName = UUID.randomUUID().toString().replace("-", "") + extName; file.transferTo(new File(uploadDir, newFileName));文件存储目录建议配置化,写到 application.yml:
upload: dir: /data/upload url-prefix: /upload/再通过一个虚拟路径映射把/upload/**映射到本地磁盘目录,这样代码中就不需要拼接乱七八糟的绝对路径了。
4.4 论文撰写如何与项目结合
这套项目带了一篇万字以上的论文文档,但很多人拿到论文后直接交,结果是内容跟自己的项目细节对不上。论文一定要和项目深度绑定,导师抽查一眼就能看出来。
论文的常规章节框架大概是:
- 第一章 绪论:项目背景、国内外研究现状、研究意义
- 第二章 相关技术介绍:Spring Boot、MySQL、Vue、MyBatis Plus
- 第三章 需求分析:功能性需求、非功能性需求、用例图
- 第四章 系统设计:总体架构、功能模块设计、数据库设计
- 第五章 系统实现:每个功能模块的核心代码和界面截图
- 第六章 系统测试:测试环境、测试用例、测试结果
写技术介绍那一章时,不要照抄百度百科。可以挑一个自己在项目中实际使用的点展开,比如“为什么选择 MyBatis Plus 而不是 JPA”,这类对比内容会让导师觉得你真的理解了。
数据库设计章节是容易充字数也容易写崩的地方。一定要把你实际项目里的表结构贴完整,一张表一条的写法,再补充字段名称、数据类型、约束说明。我见过不少论文,数据库设计写的是网上找的其他项目,和后面系统实现完全对不上,这样答辩基本逃不掉追问。
系统测试章节至少要写 10 条以上测试用例,包括正常流程和异常流程。比如测试未登录用户访问购物车接口能否被拦截,比单纯写“前台展示正常”有价值得多。
5. 常见问题排查与避坑指南
5.1 环境与依赖问题
我调试这套项目时,最常见的环境问题有三个。
第一个是 Maven 依赖下载慢或失败。解决方案就是前面提到的配置阿里云镜像。如果重启后还是失败,可以删除本地仓库下对应的.lastUpdated文件,重新刷新 Maven 工程。
第二个是 Lombok 插件不生效。IDEA 里需要安装 Lombok 插件,并在设置中启用 annotation processing。如果没装,项目运行时会报找不到 setter 或 getter 方法的编译错误。
第三个是 Spring Boot 版本太高导致启动失败。如果你用的是 JDK 17,同时又只把 Spring Boot 版本从 2.x 改到了 3.x,很多老代码会报javax不存在的错误。因为 Spring Boot 3.x 把包名从javax.servlet改成了jakarta.servlet。除非你把所有 import 都改掉,否则不要随便升级版本。
5.2 数据库连接与SQL导入问题
数据库连接报错是重灾区,常见错误和原因整理成表格:
| 错误信息 | 可能原因 | 处理方式 |
|---|---|---|
| Access denied for user | 密码错误或远程权限没开 | 确认 application.yml 中的账号密码;授权远程用户 |
| Public Key Retrieval is not allowed | MySQL 8.0 的驱动参数问题 | url 中加上allowPublicKeyRetrieval=true |
| Unknown database | 数据库名和配置不一致 | 检查建库名和 url 中的库名 |
| Server returns invalid timezone | 时区未设置 | url 中加serverTimezone=Asia/Shanghai |
| Table doesn't exist | SQL脚本没导入完整或表前缀不对 | 重新导入 SQL,注意选择正确的数据库 |
导入 SQL 时还有一个细节:如果你的 MySQL 版本比脚本版本低,比如脚本是 8.0 写的、本地装的是 5.7,那大概率会报语法错误或字符集问题。最好根据脚本开头的注释判断版本,本地装一致的环境。
5.3 前端资源加载与端口占用
前端样式、图片加载不出来,第一反应不要改代码,先看浏览器控制台请求路径。
如果页面有http://localhost:8080/xxx的请求,但登录后是 JSON 数据,那说明接口请求正常。如果是 404,再看看接口路径前缀有没有写对。很多项目把后端接口统一放在/api前缀下,有些前端代码却忘了加。
端口占用也很常见。比如你本地有多个项目,8080 已经被占了。解决办法是启动时指定端口:
java -jar brand-mall.jar --server.port=8081或者在 IDEA 配置里修改 VM options:-Dserver.port=8081。等你正式部署到服务器时,记得开防火墙对应端口,否则外部访问不到。
5.4 论文写作中的常见坑
论文方面,最大的坑是字数不够、结构像代码堆砌。你可以把数据库设计部分扩充,把所有表字段都列出来,很容易多出两千字。但不要直接贴大段代码,导师更希望看到核心逻辑的描述和关键代码的精简片段。
第二个坑是截图不完整。论文里每个功能点至少配一张系统界面截图,截图时要把地址栏和完整页面都截进去,不要只截中间一部分,不然答辩时导师会质疑“这个功能真的做了吗”。
第三个坑是测试用例表格太假。如果只写了“登录成功”“登录失败”两类,撑不起一场答辩。建议至少覆盖权限拦截、商品搜索、购物车加减、订单异常库存处理、未登录下单,这五类场景就足够真实了。
6. 实操心得与后续扩展建议
6.1 拿到项目后应该先做什么
我自己的习惯是:先不急着看代码,先把数据库导进去,然后启动项目,花十分钟把前台后台都点一遍。知道这个项目“长什么样”,再回头看代码就会快很多。
接着,我会看一眼项目的目录结构和 pom.xml,确认用的是什么技术栈、Java 版本多少,避免后面环境不匹配。然后从用户登录这个入口开始入手读代码,因为它串联了前端请求、Controller、Service、Mapper、数据库这几层,理清这一条链路之后,其他的功能模块都是相似套路。
如果你是要把项目作为自己的毕设,强烈建议用 Git 管理代码,并自己复写一遍核心模块,比如把商品查询改成自己的实现方式。答辩时老师如果问“这个功能是你写的吗”,你能解释清楚其中的判断逻辑,而不是只能说是网上找的。
6.2 常见扩展方向:支付、微信小程序、Redis
这个项目想做得更有竞争力,可以往三个方向扩展。
第一个方向是接入支付。可以让项目对接模拟支付平台,比如支付宝沙箱。虽然毕设中不强制要求真实支付,但流程会完整很多。实现时只需要在支付回调接口里更新订单状态,并保证回调的幂等处理。
第二个方向是开发一个微信小程序前台。品牌购物官网天然适合移动端展示。如果你会 Vue,可以直接用 uni-app 把现有页面复制成小程序端,后端接口基本不用改,工作量也不大。论文里还能多写一个“移动端设计”,内容量一下就上去了。
第三个方向是用 Redis 做缓存。把首页轮播、商品分类、热门商品这些访问频率高的数据缓存到 Redis,能在系统测试部分体现出性能优化意识。代码也不复杂,用 Spring Cache 的@Cacheable注解即可实现。
6.3 新人和转行者的使用建议
如果你是刚学 Spring Boot 不久,最好不要从一开始就用 IDE 运行整个项目,而是先用命令行mvn spring-boot:run跑通一次,感受一下项目构建的过程。跑完之后,再回到 IDE 里打断点调试,观察一次用户从发起请求到数据库返回的完整过程。这样做一遍,比你看十遍教程都有用。
遇到报错,把错误信息记住,搜索优先用英文关键词。把 Spring Boot、数据库连接、MyBatis Plus 这三个检索词记在备忘录里,遇到问题先自己排查,解决不了的记录下来去问同学或导师,不要把问题停留在“不懂”。
最后说点实际的:这类项目真正让你成长的地方不在运行成功的瞬间,而在于你把它搞坏又修好的过程。数据库表结构改坏了,你会学到外键关联;依赖冲突了,你会理解 Maven 的依赖传递;跨域报错了,你会记住后端需要配置 CorsFilter。这些经验是论文文档和源码不会给你写上去的,但它们比项目本身更值钱。