
本身是做毕设带学生的每年springboot类题目占一半还多酒店客房预订系统又是其中被点率最高的一个。这个题目看着简单但真到答辩时能讲清楚的人不多——大部分人卡在同一个地方系统能跑但说不明白为什么这么设计。这篇就把我从选题、建表、写接口到部署的完整思路拆开讲给正在做这个题目的人一个能直接参照的骨架也顺带讲讲springboot项目里那些课堂上很少展开、但实际一碰就翻车的细节。整个项目我按选题价值 → 技术选型 → 数据库设计 → 核心业务 → 集成部署 → 答辩准备这条线来写。你只要跟着这条线走做完系统之后心里是有底气的不管是自己复盘还是应付答辩追问都能站得住。1. 这个毕设题目为什么值得做市场需求与技术覆盖面的双重考量每年选题季我都被问同一句话老师酒店客房预订系统是不是太普通了我的回答一直是普通不等于没价值关键看你怎么把它做深。酒店客房预订系统在毕设题目里热度高恰恰是因为它覆盖的技术面非常完整而且业务逻辑足够清晰——既不像纯电商那样有复杂的支付分摊也不像内容管理系统那样只有单纯的增删改查它处在有一定业务复杂度但又完全可控的黄金区间。从市场需求角度说酒店行业的信息化改造一直没停过前台手工排房、电话预订、纸质登记这些小旅馆还在用的老流程正是小型管理系统要解决的问题。你做一个面向中小型酒店的预订系统是有真实业务场景支撑的不是空中楼阁。体现在论文里研究背景和意义那一章写起来就能言之有物落不了地。从技术覆盖面上看这个题目几乎能把Spring Boot生态的主要知识点串起来Web层RESTful API设计、参数校验、统一异常处理数据层MySQL表设计、MyBatis持久化、事务管理业务层预订状态流转、并发防超卖、日期冲突校验进阶功能定时任务超时未支付订单自动取消、缓存房型库存缓存、文件上传房间照片前端联调Vue打包后整合进Spring Boot或者前后端分离部署这几个点单独拿出来都不算难但组合在一个系统里整体工作量、整体深度就上来了。很多学生做完之后跟我反馈说真正弄懂了一个请求从前端进来到数据库返回中间经过了哪些环节——这个认知比项目本身值钱。再说点实际的这类系统查重也比较好过。因为你在表结构设计、状态机设计、并发控制这几个地方是能写出差异化内容的不是网上那种千篇一律的CRUD。后面几章我会重点讲这几个差异化点怎么落。2. 技术栈定型Spring Boot生态下的选型取舍与版本决策2.1 为什么锁定Spring Boot而不是SSH或SSM这个答案其实在热度词里已经摆得很明显了Spring Boot全家桶已经是JavaWeb开发的事实标准。SSHStrutsSpringHibernate早被市场淘汰了SSM虽然还能见到但配置那套东西——XML文件写到手软各种bean之间绕来绕去的依赖关系——对毕设周期来说是纯纯的负担。Spring Boot的核心价值是约定大于配置它把原来SSM里要手工做的一大半配置变成了自动装配。你搭一个Web项目从零到能跑起来用Spring Boot大概十分钟用SSM至少折腾一上午。这不是说SSM的技术含量低于Spring Boot而是说SSM的复杂度来自基建Spring Boot把基建收敛掉了让你把精力放在业务上。我在给学生定方案时一直是这个原则毕设的展示重心是业务设计和工程化能力不是展示你会写配置文件。哪个框架能让你更快地表达业务就用哪个。2.2 版本决策逻辑直白的选法避免被坑版本这块我要重点提醒。很多人在官网一看到Spring Boot 3.4.x、3.5.x就顺手选了最新版结果JDK版本不匹配、依赖下载报错、启动直接黑屏一卡就是两三天。这是热度词springboot版本太高的真实写照几乎每周都有人因为这个来找我排查。我的建议非常保守做毕设就选Spring Boot 2.7.x系列配套JDK 1.8。原因有三点这是国内教程资源覆盖率最高的组合遇到任何报错百度Google都能秒出答案MyBatis Plus、Redis、EasyExcel这些常用中间件对Spring Boot 2.x的兼容性经过了大批量项目验证坑最少Spring Boot 3.x开始把javax迁移到jakarta很多老代码示例直接复制会报包不存在对刚接触框架的人来说这是完全没有排查头绪的编译错误如果你非要用3.x也可以但要做好心理准备——网上大量示例代码里的javax.servlet要手动改成jakarta.servlet一些starter的坐标也要换成3.x专用版本。这笔时间成本对毕设来说不划算。项目结构上标准的Maven单模块工程就够了不需要微服务那套。按我习惯的包结构组织com.example.hotel ├── controller # 接口层 ├── service # 业务层 │ └── impl ├── mapper # MyBatis持久层接口 ├── entity # 数据库实体类 ├── dto # 接口入参出参对象 ├── config # 配置类拦截器、跨域、定时任务等 ├── common # 统一返回结果、异常处理、工具类 └── HotelApplication.java这个分包是把表现层、业务层、持久层的经典分层落到了代码目录上答辩时面试官一眼就能看出你懂分层思想。2.3 Maven构建的节奏感先骨架后依赖热度词里有个javamaven项目构建方法这确实是一个新手容易卡壳的点。直接用IDEA创建Spring Initializr项目是最省事的路径File → New → Project → Spring Initializr填好Group和Artifact选好Spring Web、MySQL Driver、MyBatis这些依赖项目骨架就出来了。这里要注意一个细节不要一上来就一股脑把所有依赖全勾上。比如MyBatis Plus要单独加坐标Lombok也要单独加这些Initializr自带的勾选项里没有。我的习惯是先把Web和MySQL Driver勾上项目创建成功后再根据业务需要在pom.xml里逐项添加。这样每一步加依赖报错都能精准定位到是哪个引起的而不是做了一堆操作之后突然启动失败连哪一步出了问题都不知道。pom.xml里最常用的这份依赖清单可以直接抄作业dependencies !-- Web -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- MyBatis Plus -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency !-- MySQL 驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- Lombok简化实体类 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency !-- 参数校验 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency !-- 后续做定时任务时引入 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-quartz/artifactId /dependency /dependenciesLombok不多说了实体类的getter/setter/toString全自动生成代码量少一大截。参数校验那是我特别建议加的——所有接口入参用Validated注解校验客人订房时手机号格式、日期格式、入住人数这些交给框架去挡比自己在service里写if else判断干净得多答辩时也算一个亮点。3. 数据库设计是这类系统的灵魂从表结构到状态流转的完整梳理3.1 五张核心表先回答业务需要哪些数据酒店客房预订系统的数据模型我把它归纳成两个主数据、一个核心单据、两个辅助数据主数据1房型room_type——豪华大床房、标准双床房、行政套房这类可售卖的产品定义包含房价、面积、床型、可住人数、房间图片主数据2客房room——实际物理房间属于某个房型有房号、楼层、朝向核心单据订单order——客人预订行为的完整记录关联房型和具体客房包含入住日期、离店日期、订单金额、状态辅助数据1用户user——系统登录账号区分顾客和管理员角色辅助数据2预订明细order_detail可选——如果一次订单预订多间房用明细表记录每间房的具体信息方便后续排房为什么把房型和客房拆成两张表这是这类数据库设计里最值得解释的一个点。你可以这样理解房型好比菜单上的菜品客房好比厨房里实际的锅。一个房型对应多间客房一间客房唯一属于一个房型。如果把它们揉在一张表里每个房间都要重复维护一份房价、图片、床型信息改价格要挨个房间改数据冗余不说还会出现同一个房型下各客房价格不一致的脏数据。拆开之后要给豪华大床房调价只改room_type表里的一行记录就行了。3.2 状态字段设计订单的一生订单表里最核心的字段不是金额是status状态字段。我设计的订单状态流转是毕设答辩时的重点展示内容也是一套完整的状态机待支付(0) → 已支付(1) → 已入住(2) → 已完成(3) │ ├→ 已取消(4) 用户主动取消/超时未支付自动取消 └→ 已退款(5) 支付后取消并退款这个状态流转在设计时要回答三个问题每种状态由谁触发待支付到已支付是用户支付动作触发已支付到已入住是前台办理入住触发已完成是退房结算触发哪些状态可以回退待支付可以取消已支付可以退款取消但已入住之后只能走到已完成不能回退状态变更要不要记录历史严谨的做法是加一张订单状态变更日志表每次状态变化都记录操作人、时间、变更前后值。毕设系统里可以加工作量不大但论文里写通过状态日志实现全链路审计追踪是很有分量的功能点3.3 日期冲突与库存判断用SQL表达业务规则酒店预订最核心的业务规则是一间客房在同一时间段内不能被两个订单占用。这个判断不能靠Java代码遍历硬算要用SQL在数据库层面解决。订单表里存check_in_date和check_out_date。判断某个时间段是否与已有订单冲突的SQL长这样SELECT COUNT(*) FROM orders WHERE room_id #{roomId} AND status IN (1, 2) -- 已支付和已入住才算占用 AND NOT ( #{newCheckOut} check_in_date OR #{newCheckIn} check_out_date )这个NOT (新离店 旧入住 OR 新入住 旧离店)的两时间段交叉判断逻辑看起来简单但写错的人不在少数。容易错的地方是把OR写成AND或者判断条件里漏了边界值处理。实际订房场景中旧订单中午12点退房新订单下午2点入住中间是有缓冲时段的具体要不要允许同一天首尾相接取决于酒店设定的打扫时间这种业务规则建议在代码里定成常量后面调起来方便。库存判断同理。房型维度看的是该房型下处于可售状态的客房数量SELECT COUNT(*) FROM room WHERE room_type_id #{typeId} AND status 0 -- 0启用 1停用 AND id NOT IN ( SELECT room_id FROM orders WHERE status IN (1, 2) AND NOT ( #{newCheckOut} check_in_date OR #{newCheckIn} check_out_date ) )这条SQL的结果就是当前可用的房间数。预定页面上显示还剩几间就是用它查出来的。3.4 表结构落地的实操建议建表时我习惯用Navicat或者IDEA的Database插件直接可视化建建完导出SQL脚本放工程里。下面是一个简化的订单表DDL照着这个思路扩展就行CREATE TABLE orders ( id bigint(20) NOT NULL AUTO_INCREMENT, order_no varchar(32) NOT NULL COMMENT 订单编号, user_id bigint(20) NOT NULL COMMENT 下单用户ID, room_type_id bigint(20) DEFAULT NULL COMMENT 房型ID下单时预订房型, room_id bigint(20) DEFAULT NULL COMMENT 具体客房ID办理入住时确定, check_in_date date NOT NULL COMMENT 入住日期, check_out_date date NOT NULL COMMENT 离店日期, guest_name varchar(50) NOT NULL COMMENT 入住人姓名, guest_phone varchar(20) NOT NULL COMMENT 入住人手机号, total_amount decimal(10,2) NOT NULL COMMENT 订单总金额, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 状态0待支付 1已支付 2已入住 3已完成 4已取消 5已退款, remark varchar(255) DEFAULT NULL COMMENT 备注, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_room_date (room_id, check_in_date, check_out_date) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4;几点说明订单编号别用自增ID直接暴露给用户用时间戳随机数拼一个唯一单号联合索引idx_room_date是给日期冲突查询加速的金额用decimal(10,2)千万别用float——浮点数的精度误差在钱上是不能容忍的这也是一个可以主动讲的细节。4. 核心业务接口的落地思路预订流程与数据一致性的攻防4.1 预订主流程七步走完一笔订单整个预订系统的业务闭环是七个步骤串联起来的。我画一遍完整流程你照着这个顺序去实现接口就不会乱用户注册/登录JWT签发token前端请求带上token访问受保护接口查询房型列表展示房型、价格、图片、剩余可订数量查询房型详情传入房型和日期返回该时间段内的可用房间列表提交预订前端提交房型、入住日期、离店日期、入住人信息后端做日期校验、库存校验生成订单状态待支付模拟支付因为不做真实支付对接用点击支付按钮直接回调或接入沙箱支付来模拟订单状态改为已支付办理入住管理员把订单状态改为已入住同时绑定具体客房号退房结算把订单改为已完成释放房间如果你愿意增加一点复杂度还可以在支付前加一个预占库存步骤——用户下单后锁住房型数量15分钟超时不支付自动释放。这个机制就是热度词里的springboot定时任务典型应用场景。4.2 并发防超卖同一间房不能被订出去两次这是整个系统含金量最高的技术点必须单独拿出来讲。现实场景剩最后一间豪华大床房两个客人同时下单如果代码只做了先查库存再扣减两步操作并发情况下两个请求都查到了库存为1都认为有房都能下单成功——超卖了。解决思路有三个层次方案一乐观锁最推荐做进毕设的给房型表加一个version版本号字段。下单时先SELECT查出version更新库存时带上这个versionUPDATE room_type SET stock stock - 1, version version 1 WHERE id #{typeId} AND version #{oldVersion}MyBatis执行后返回受影响行数如果影响行数为0说明version已被其他请求修改当前请求失败返回手慢了房间被抢走啦。这个方案代码量小逻辑好讲答辩时解释乐观锁和悲观锁的区别是加分的。方案二悲观锁SELECT ... FOR UPDATE把行锁住别人查不到这条记录等当前事务提交后才释放。实现上要配合Transactional使用。优点是不会出现更新失败重试缺点是并发性能差——但对于毕设这种并发量完全够用。如果要讲SHOW ENGINE INNODB STATUS之类的底层机制工作量上来。方案三Redis分布式锁热度词里出现了Redis的影子。用setIfAbsent加锁设置过期时间业务执行完释放锁这是小系统实现分布式锁的经典做法。但它引入了一个新组件系统复杂度上升如果对Redis不熟可能出现锁没释放导致死锁这类自己查不出来的问题。我的建议是方案一打底论文里把方案三作为优化方向提一句就够不要真引进来。4.3 事务边界哪些操作必须打包处理下单操作不是单条SQL而是查库存→扣库存→生成订单→可能还要写状态日志一串操作。如果中间某一步失败了前面的操作必须全部回滚否则会出现库存扣了订单没产生的严重问题。这就要给服务方法加事务注解Transactional(rollbackFor Exception.class) public OrderResult createOrder(CreateOrderRequest request) { // 1. 参数校验日期合法性、入住人数 // 2. 库存校验查可用房间数大于0才继续 // 3. 乐观锁扣减库存 // 4. 生成订单记录 // 5. 返回订单信息待支付 }rollbackFor Exception.class这个必须有——Spring的Transactional默认只在RuntimeException时回滚普通的受检异常不会触发回滚。如果漏了这句业务上抛一个Exception出去数据库库存已经减了订单一查没有这就是经典的不完整原子性bug。4.4 超时未支付自动取消定时任务的正确用法用户在待支付状态停了20分钟不付款房间就白白被他占着别人订不了。解决方式很直接用Spring Boot的Scheduled定时任务每1分钟扫描一次待支付订单超过支付时限的自动改为已取消状态并回补房型库存。Component public class OrderTimeoutTask { Autowired private OrderService orderService; Scheduled(cron 0 */1 * * * ?) public void cancelTimeoutOrders() { // 1. 查询所有待支付且创建时间超过15分钟的订单 // 2. 逐单状态改为已取消 // 3. 回补库存 } }启动类上加EnableScheduling。这个功能做进去之后演示效果很直观提交订单后把系统时间改到超过15分钟等定时任务跑完去看订单状态和房型库存自动完成闭环。不过需要提醒的是Scheduled定时任务默认是单线程串行执行的如果任务执行时间很长会阻塞下一个任务。毕设阶段数据量小感受不明显但最好写成独立线程池或Async异步方式这也是一个能体现工程思维的细节。5. 从IDEA配置到Vue打包再塞进Spring Boot集成部署的高阶坑5.1 IDEA中配置启动参数端口、热部署和编码热度词里那句idea 2026 怎么配置springboot服务 编辑配置数据 比如启动端口本质问的是Run Configuration的用法。其实修改端口的第一优先方式不是IDEA的配置面板而是application.ymlserver: port: 8081 servlet: context-path: /hotel # 可选让所有接口带前缀如果要改IDEA里一次性的运行参数是Run → Edit Configurations → 选你的Application启动类 → Program arguments里填--server.port8082这个参数的优先级高于配置文件。说白了IDEA的配置面板最终也是把参数透传给Spring Boot启动命令真正起作用的还是Spring Boot的参数解析机制。热部署建议加上spring-boot-devtools依赖改代码后自动重启不用手动点那个小乌龟图标。但注意一个坑devtools的自动重启依赖构建时机IDEA里要打开Build project automatically不然改了代码不会触发。另外如果用了Scheduled定时任务devtools重启会导致定时任务重复注册这个我自己遇到过调试时偶尔会出现任务跑两次的情况需要手动把旧进程结束掉再启动。5.2 一个主流的做法Vue前端打包进入Spring Boot热度词中有个非常实际的问题vue打包放进springboot中。这个需求源于毕设答辩时往往只有一台电脑一个应用不方便起两个服务把Vue的前端dist包放进Spring Boot的静态资源目录是主流做法。具体操作分四步前端项目根目录执行npm run build生成dist文件夹把dist文件夹里的内容复制到Spring Boot项目的src/main/resources/static目录下重新打包后端mvn clean package -DskipTests运行jar包浏览器访问http://localhost:8080/看到的就是前端页面这个方案能跑通的关键是Spring Boot默认把/static以及/public、/resources、/META-INF/resources作为静态资源目录。但有个大坑——前端用的是history路由模式时刷新页面会出现404因为刷新请求打到了后端而后端没有对应的接口处理。最省事的解法前端路由模式改成hash模式也就是http://localhost:8080/#/index这种带#号的URL刷新不会发请求到后端不会404。如果你想保留history模式就需要在后端配置一个转发规则所有非接口路径都转发到index.html这个配置稍微复杂一点毕设阶段更推荐hash模式省心又够演示。另外一个必踩的坑是接口联调时的跨域问题。前端Vue开发时跑在localhost:5173后端跑在localhost:8080端口不同就是跨域。开发期在前端的vite.config.js里配代理server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }这样前端请求/api/xxx会被代理转发到后端浏览器不直接跨域。如果前后端已经打包到一起了同域同端口跨域问题就不存在了这也是打包进Spring Boot方案的另一个舒服之处。5.3 application.yml里的关键配置一个能正常连接数据库和跑起前后端整合的application.yml是经验清单一样的存在server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/hotel_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 servlet: multipart: max-file-size: 10MB max-request-size: 10MB mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0map-underscore-to-camel-case: true必须开这能让数据库的下划线字段自动映射到Java的驼峰属性比如check_in_date对应checkInDate省掉手写ResultMap的重复劳动。连接MySQL时最容易出的错误是serverTimezone时区配置。中国本地的MySQL没配时区Java连接时报错The server time zone value...加上serverTimezoneAsia/Shanghai就好。还有useSSLfalse本地开发关掉SSL握手减少一个报错源。MyBatis Plus的逻辑删除配置值得展开一下订单列表和删除订单是我建议必做的但是真的从数据库把记录删掉还是用一个deleted字段逻辑标记我建议用逻辑删除——数据完整性和可追溯性都更好。配置了上面的logic-delete之后MyBatis Plus会自动在所有查询SQL里拼上WHERE deleted0删除操作自动变成UPDATE ... SET deleted1完全不用手写。5.4 打包构建的最终形态整个项目完成后交付物是一个可执行的jar包。构建过程就三个命令# 后端 mvn clean package -DskipTests # 前端 npm run build # 然后把前端dist内容拷进后端static目录重新打包最终纯jar包化。运行方式java -jar hotel-system.jar --spring.profiles.activeprod如果嫌命令行起jar麻烦用nohup java -jar hotel-system.jar log.txt 21 丢到后台跑日志输出到文件方便排查。这个交付形态在论文系统部署章节里很好写单体架构、一键部署、跨平台运行。6. 答辩最容易被追问的技术细节与应对思路毕设答辩的实质是让评审老师相信这个系统真的是你做的而且你真的理解它。我带队时经常提醒学生不要怕被追问关键是提前把可能会被问到的点全部摸一遍。下面这几个点是我总结的springboot酒店客房预订系统答辩命中率最高的追问区域。6.1 Spring Boot自动装配原理必问三连评委会问你说你用了Spring Boot那它到底是靠什么机制省去了那些繁琐配置的这个问题答案的核心是自动装配AutoConfiguration。可以这样通俗回答Spring Boot在启动时会扫描META-INF/spring.factories或新的AutoConfiguration.imports文件这些文件里列出了所有需要自动装配的配置类。以数据源为例DataSourceAutoConfiguration看到classpath里有MySQL驱动和spring.datasource.url配置就自动帮你创建好HikariDataSource。你想改啥application.yml里写。这就是约定大于配置的实现原理。平时在网上可以看到的热门话题springboot自动装配原理详解用的就是这个思路。答辩时把这个讲清楚已经超过80%的学生了。6.2 为什么选MyBatis Plus而不是JPA这个追问本质是在考你ORM选型的判断力。我的标准回答MyBatis Plus在SQL层面有完全的控制力复杂查询——比如查某时间段可用客房数这种带NOT EXISTS子查询的SQL——能保证执行出的SQL和你设计的一致性能可以预见分页插件、逻辑删除、条件构造器这些现成能力减少大量样板代码国内企业用MyBatis系的比例远高于JPA毕业之后进公司更无缝衔接但也要承认JPA在简单CRUD场景效率更高。这样正反都讲显得你不是只背了结论而是真的比较过。6.3 事务、并发、分布式三层追问的递进关系如果商店里只剩最后一件衣服两个顾客同时恰在提交订单时恰好都通过了库存检查——系统会不会把这件衣服卖给两个人这问题是个递进式先问你能不能说出问题超卖再问你解决方案的思路乐观锁/悲观锁最后问你这两个方案分别在什么场景下更合理。我的建议是把乐观锁和悲观锁的区别做成一个小表格放在脑子里对比项乐观锁悲观锁思想更新时检查版本访问时锁住资源实现version字段影响行数判断SELECT FOR UPDATE并发性能高失败后重试或提示低排队等待适用场景读多写少冲突概率低写多冲突概率高酒店预订是典型的读多写少场景乐观锁就够了。这个逻辑讲出来老师会觉得你是有工程判断力的。6.4 日期冲突SQL的边界说明为什么你判断订单时间冲突用的是NOT (...)而不是直接判断交叉这问题实际上是考SQL逻辑思维。直接写法容易遗漏边界情况NOT (新离店 旧入住 OR 新入住 旧离店)把完全不相交的两个情况先排除剩下的必然相交这是数理逻辑里的德摩根律。回答时可以把新旧订单首尾相接的情况单独拎出来讲如果你不允许同一天首尾相接直接在两条OR条件里加等号处理即可——这让老师知道你不只是抄了一条SQL而是真理解这个判断的边界条件。6.5 一个提升印象分的测试意识毕设答辩演示环节通常局限于页面能点、订单能跑通但如果你能主动展示测试成果印象分会明显提升。单元测试OrderServiceTest里写几个核心用例比如乐观锁冲突回滚、日期冲突拦截、超时订单自动取消接口测试用Postman导出一份接口调试集展示各接口的请求响应性能测试有条件的用JMeter对查询房型列表接口压1000个并发贴出TPS和响应时间数据论文的系统性能测试章节素材也一并有了这些测试不需要覆盖全模块挑核心的关键业务覆盖就行。论文里写系统核心模块的单元测试覆盖率达到XX%接口平均响应时间XXms整篇论文的工程完整度都会上一个台阶。6.6 个人项目中踩过的坑也是最好的谈资答辩时与其机械背诵流程不如主动讲讲你遇到的真实问题和解决过程。比如下单时库存扣了但订单因为参数校验失败没生成后来加了Transactional(rollbackFor Exception.class)才解决——这是事务原子性的真实案例前端打包放进Spring Boot后刷新404后来改成hash路由模式解决——这是前后端集成部署的真实案例数据库date字段和Java的LocalDate时区对不上报时间解析错误统一为Asia/Shanghai时区后解决——这是环境配置的真实案例这些实际踩坑经历比任何理论背诵都更有说服力因为它是你的、是唯一的老师一听就知道不是你抄的。我的体会是这种题目的最佳完成状态不光是写完了系统而是把我的设计和得失完整地复盘了一遍。做完之后把上面的状态机、事务边界、并发方案、部署链路这几个问题在脑子里过一遍你会发现这个题目真正教会你的不是那些API怎么调而是怎么把一个模糊的业务需求一步步落地成可靠解决它的软件系统。这才是毕设的初心所在。后面如果还要扩展可以朝着小程序端、在线选房、财务报表图表这些方向做但那都是拿到合格之后的事了。先把主系统做扎实比什么包装都值。