1. 为什么“线上陪玩店系统”是一道低成本、高覆盖的毕设题
每年到毕设季,我都会被问类似的问题:老师要求用 Spring Boot 做系统,但选商城太烂大街,选秒杀又容易把自己坑进去,到底什么题目工作量合适、技术栈能覆盖核心 Spring Boot 知识点、同时答辩时还能讲得出东西?
我的建议里一直有一个高频选项:线上陪玩店系统。这是一个典型的“轻商城 + 服务撮合”模型,业务上兼顾了用户端、陪玩师端、平台管理端三方角色,功能上覆盖了注册登录、服务展示、下单支付、状态流转、评价结算和后台管理等常见模块。相比很多只有简单 CRUD 的班级管理系统,它有几个天然优势:状态多、角色多、能聊的业务点密集。相比电商秒杀,它又不需要真的处理高并发库存扣减,做起来和心理负担都小很多。
从我做计算机 Java 毕设拆解和带人复现的经验来看,基于 Spring Boot 的线上陪玩店系统真正难得的地方在于:它不是“代码写不出来难”,而是“业务边界想不清楚难”。很多同学拿到代码后忙着跑通,跑完发现不懂的就直接背——这种状态到答辩现场会非常危险。陪玩店这种业务本身逻辑链很长,从用户浏览陪玩师、下单选时段,到陪玩师接单、服务结束、双方互评,再到平台结算、商家对账,完全可以用状态机一条线串起来。你只要把这条线摸透了,哪怕原项目不是你从零写的,也能做到问一句答一句,不至于一上来就被问穿。
1.1 陪玩店的真实业务面拆解
所谓“线上陪玩店”,在真实业务里就是陪玩师入驻平台开店,把自己的技能、时间、服务价格挂出来;用户进来之后浏览、筛选、下单;支付完成后陪玩师接单开始服务;服务结束后平台把订单金额结算给陪玩师,同时保留自己的抽成部分。
具体到系统里,通常可以拆成这些模块:
- 平台端:用户管理、陪玩师入驻审核、服务分类管理、订单监管、举报/投诉处理、平台抽成统计
- 陪玩师端:个人主页维护、服务技能设置、上线/接单状态切换、接单列表、收入明细、提现申请
- 用户端:陪玩师浏览、按分类/价格/好评率筛选、下单并支付、申请退款、服务后评价、订单历史
这就是为什么这题很适合当毕设题目,因为它的模块数量、角色数量、数据表数量天然足够多。只要拆得合理,甚至可以不加任何花哨的前沿技术,都能有 10 张以上的表、20 多个接口。而这对于一个 Spring Boot 毕设项目来说,已经属于相当扎实的工作量了。
1.2 它和普通商城系统的核心差异
很多人一听陪玩店系统,第一反应是“这不就是商城吗”,如果真照着商城做,极容易跑偏。
普通电商商城卖的是“SKU 库存”,围绕的是商品、购物车、库存、物流。陪玩店模式下,核心商品是陪玩师提供的服务,它的库存是“人的时间”,服务价格又可能随分段、大区、时长变化。如果用传统商城的商品表去硬套,做出来的项目答辩时非常容易被老师一句话问住:如果你的陪玩师正在服务中,怎么保证他不会同时接到第二单?
因此我建议把陪玩店系统理解成一个“撮合平台”而不是“商城”。陪玩师上线时就有一个身份状态:可用、服务中、休息中、已下线。用户能下单的前提是对方当前处于“可接单”状态。这样的设计,远比“下单先减库存再退款再恢复库存”更贴合实际业务。老师听到这个逻辑会觉得你真的动过脑子,而不是把电商模板改改字段就交差了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型与 Spring Boot 版本搭配:先别急着敲代码
这套系统我复现过,也帮同专业的学弟校准过选型。第一个最容易被忽视的问题不是代码能不能跑,而是“项目技术搭配”是不是合适。一个毕业设计不需要过于炫技,但也不能看起来像 2015 年的老古董。建议按如下方式选型:
- 开发语言:Java
- 框架:Spring Boot 2.7.x(配合 JDK 8 或 11)
- 持久层:MyBatis-Plus 3.5.x
- 数据库:MySQL 8.0
- 缓存:Redis(主要用于 token、验证码、热数据)
- 鉴权:JWT 无状态登录(配合 Spring MVC 拦截器)
- 前端:Vue 2 + Element UI / 原生 HTML + Layui 都可以,主要看你想不想卷前端
- 项目管理:Maven
2.1 单体架构已经足够:给答辩一个能自圆其说的边界
很多同学一看到“陪玩店”这种平台型项目,就想着上 Spring Cloud 微服务、上 Nacos、上 Gateway。我劝你不要。
一个典型的毕业设计,重点是验证你对 Spring Boot 整体开发流程的理解。微服务需要拆服务、处理服务间调用、分布式事务,一套下来工作量翻好几倍,但评分时老师并不会因此多给更多分。多数学校考核的是:项目是否完整、是否体现主流框架能力、功能模块是否齐全、你是否能讲清楚设计思路。
所以正解不是“用微服务”,而是明确说明:这个项目采用模块化的单体架构。所有子业务在工程内部按包划分,比如 controller、service、mapper、entity、dto、vo、common、config、utils。单体架构在这个业务规模下,性能完全足够,同时代码组织清晰、容易部署。这就是一个经得起追问的边界判断。
如果老师问“以后用户量上来怎么办”,你可以提前准备一个回答路径:先把 Redis 缓存加上,再把支付与订单服务拆出去,前面再加 Nginx 做负载均衡,需要的主要成本都在业务上,单体架构可以先作为 1.0 版落地。这样的回答是有清晰演进思路的,比“我当初就想学微服务”但什么都没做出来要强太多。
2.2 JDK、Spring Boot 版本和依赖版本的关系
这一部分是最容易让人翻车的,我见过太多“照着 B 站视频装 JDK17 + Spring Boot 3.2 + MyBatis-Plus 3.5.5,结果一堆依赖对不上,一个 mapper 都启动不了”的例子。核心原因是 Boot 2.x 和 Boot 3.x 建立在不同的 Java EE 基础上,Boot 3 强制要求 JDK17,并且很多旧版依赖(比如某些版本的 druid、swagger、jwt 库)没有及时适配。
如果你没有特别强的版本管理意识,请直接用一套稳定的组合:JDK 8 + Spring Boot 2.7.18 + MyBatis-Plus 3.5.3.x + MySQL 8 + Hutool + jjwt 0.9.1。
为什么这么稳妥?因为 Boot 2.7 是 2.x 的最后一个版本,生命周期已经打磨完整,网上资料巨多;JDK8 是所有学校机房和大多数旧服务器都有的环境;MyBatis-Plus 3.5.3 可以完美兼容 Boot 2.x。这套搭配下你基本不会遇到启动报 Invalid value type for attribute 'factoryBeanObjectType' 或 java.lang.NoSuchMethodError 这类版本冲突问题。
提示:如果你用的是 JDK17 + Spring Boot 3.x,千万别把网上抄的 Boot 2.x 代码直接贴进去,尤其是 springfox(Swagger2)、javax.* 包名改成 jakarta.*、Redis 连接工厂配置这些,改到怀疑人生。
2.3 JWT 还是 Session:视角不同,技术选型就不同
这个问题答辩老师非常喜欢问。
传统的 Java Web 开发常用 Session + Cookie,同源应用里实现简单、改起来方便,配合 Redis 做分布式 Session 也能增强扩展性。但如果在前后端分离的项目里,前端跑在 localhost:8081,后端跑在 localhost:8080,还要自己处理跨域请求带去 Cookie,就很别扭,往往前端明明登录成功,后续请求却不携带身份信息。
我在这套线上陪玩店系统里更推荐 JWT。用户登录成功后,后端签发一个带过期时间的 token 字符串,前端存在本地并在每次请求的请求头 Authorization 里带上;后端过滤器解析 token 并放入线程上下文,后续 Controller 就能拿到当前用户 ID。毕业设计规模下,这种无状态方案已经够用且很能体现你对当前主流做法的了解。
需要注意,JWT 不是没有坑。它最大的问题是“不能主动失效”。用户退出登录后,只要 token 没过期,理论上还能继续用。针对毕设场景,我的处理建议是:后端提供一个退出登录接口,把 token 加入 Redis 黑名单并设置与 token 相同的过期时间,然后在拦截器里统一检查。这样又自然引出了 Redis 的用法,一举两得。
3. 后端表结构怎么设计才经得起追问
数据库设计是整个项目的骨架。一个项目代码写得再花哨,表设计不讲究,一打眼就露怯。线上陪玩店系统的核心表并不需要太多,但必须把“用户、服务、订单、钱包”这四个领域锚牢。
这里有张参考表清单,基本覆盖陪玩店模式最常见的字段模型:
| 模块 | 表名 | 关键字段 | 备注 |
|---|---|---|---|
| 用户 | user | id, phone, password, nickname, avatar, role, status | role 区分用户/陪玩师/管理员 |
| 陪玩师 | player_info | id, user_id, title, intro, price, game_ids, tags, status, order_count, rating | 一条用户记录对应一条陪玩师信息 |
| 服务类目 | category | id, name, parent_id, sort, status | 支持分层级 |
| 游戏/大区 | game_region | id, name, region, level, price_factor | 非必选,可选 |
| 订单 | orders | id, order_no, user_id, player_id, service_id, price, status, start_time, end_time | 全流程核心 |
| 评价 | comment | id, order_id, user_id, player_id, content, score | 一单一评 |
| 钱包 | wallet | id, user_id, balance, frozen_amount | 余额与冻结隔离 |
| 钱包流水 | wallet_log | id, wallet_id, amount, type, order_no, remark | 充值/支付/入账/提现 |
| 举报/投诉 | complaint | id, order_id, reporter_id, content, status | 合规模块,加分项 |
做毕设时,我发现很多同学设计的订单表过于简陋,比如只有“订单号、商品名、价格、用户ID、状态”,状态还只有 0 未支付、1 已支付、2 已完成三种。这不算错,但经不起问。
3.1 用户端与陪玩师端:一套用户体系还是两套
最省事的做法是一个 user 表,通过 role 字段区分普通用户、陪玩师、管理员。陪玩师入驻后,再在 player_info 表存昵称、头像、介绍、服务状态等扩展信息。不要单独再建一张“陪玩师账号表”,那会导致登录逻辑混乱、密码要存两份。
一口咬定这么设计的原因:现实中一个陪玩师本人也可能是另一个陪玩师店铺下的用户,平台的基础账号体系必须统一。所以 user_id 就是全系统的通用身份凭证,订单里记录用户的 user_id 和陪玩师的 user_id,下单、评价、提现都围绕一个账号体系转。这在逻辑上最干净,答辩老师也比较认可。
3.2 订单状态机:设计得越清楚实现越轻松
线上陪玩店系统最容易被老师追问的地方,就是订单状态为什么这样流转。这里我给你一套实际项目里常用的状态定义:
| 状态值 | 含义 | 说明 |
|---|---|---|
| 0 | 待支付 | 用户已下单,未付款 |
| 1 | 待接单 | 已付款,陪玩师还没接单 |
| 2 | 服务中 | 陪玩师已接单,双方建立线上密室频道 |
| 3 | 待确认完成 | 陪玩师发起了“服务完成”,等用户确认 |
| 4 | 已完成 | 用户确认完成,订单正常关闭,平台结算给陪玩师 |
| 5 | 已取消 | 未支付超时/用户主动取消 |
| 6 | 退款中 | 用户申请退款,平台或陪玩师被通知 |
| 7 | 已退款 | 退款完成,订单关闭 |
这套状态值比“商城直接发货收货”更有业务层次,它的流程十分接近真实陪玩平台:用户先付款、陪玩师再接单,是平台为了保证陪玩师不被“空单”骚扰;陪玩师发起完成、用户确认,是为了防止陪玩师单方面终止服务还能拿到钱。
状态流转可以用一句话串起来:用户下单选好用 0,支付成功改 1,陪玩师接单改 2,服务结束后陪玩师申请表里发起待确认 将状态改成 3,用户确认后改 4,完成。退款可以发生在 1、2、3 这几个节点上,变为 6 再决定是否变为 7。
3.3 三个容易被忽视但很加分的表
有些线下项目的订单支付完全靠管理员“手动改状态”,不做钱包和流水,总觉得少了点什么。我的建议是至少加上五张不那么常见但合理的表:钱包、钱包流水、评价、举报、系统公告。
钱包的意义在于,它能支撑一套完整的资金闭环。用户注册后可以充值。下单时,订单金额先从用户钱包余额中冻结(frozen_amount + 仓位),服务完成后再扣减余额并给陪玩师钱包入账按平台抽成后的金额。没有真实支付通道时,用“钱包模拟支付”是最安全、最完整的替代方案,同时完美避开做支付接口没有商户资质的问题。
钱包流水则是审计和排查问题的核心。每一笔钱的变动都应该落一条流水,用户在钱包页能看到充值记录、消费记录、退款记录,陪玩师能看到每一笔订单的入账记录。这是一个很提分的设计,因为很多同学都做不到,而它并不难实现。
举报表是一个容易被忽视的合规加分项。线上陪玩这类平台很容易涉及服务争议,平台需要给用户提供举报/投诉入口,管理端能查看和处理投诉,并可以执行封禁陪玩师账号等操作。这块内容展示了系统的完整性和安全意识,很符合当前对平台型应用的预期,属于标准的正面设计。
4. 核心功能实战:从用户注册到下单选陪玩师的完整链路
很多教程一上来就是教你写一堆 CRUD,但 CRUD 谁都会,真正的价值在于把主流程串通。以下按“用户视角”走一遍核心链路:注册登录 → 浏览陪玩师 → 创建订单 → 支付 → 陪玩师接单 → 服务完成 → 评价 → 结算。
4.1 注册与登录:密码不能存明文,也不能用 MD5
先解决一个最基本但很多新手都会犯的问题:密码怎么存。正确做法是用 BCrypt 加密。Spring Security 里自带的 BCryptPasswordEncoder 可以直接用,或者你也可以引入 spring-security-crypto 单独作为工具包,而不需要引入整个 Spring Security。项目里配置好之后,注册时加密,登录时 matches 校验。
这里我强烈不建议你用 MD5,哪怕加盐也不行。答老师问的时候你可以讲清楚:MD5 是一种快速散列算法,计算极快,黑客可以用彩虹表或高频穷举来碰撞;BCrypt 设计时就内置了盐并且是慢哈希算法,能显著提高破解成本。一个“为什么别人都用 MD5 而你不用”的回答,能让答辩印象分往上拉不少。
登录流程上,我通常用短信验证码或账号密码登录。真实平台肯定有短信收发,但毕设里建议用 Redis 存一个模拟的短信验证码,方便演示又不出卖身份证/手机号。演示时输入 123456 就能通过,老师会觉得你考虑了真实场景却留了演示入口,逻辑合理。
获取登录身份时,可以从 request.getHeader("Authorization") 中解析 token,然后把 userId 放进 BaseContext 之类的 ThreadLocal 工具类中。Service 层拿到 userId 后,才能在下单时取当前用户、在评价时校验是否本人购买过。每个需要登录的接口都建议在 Controller 层调用一个类似 UserContext.getUserId() 的方法,避免在每个方法里写重复的解析代码。
4.2 陪玩师列表的带条件分页查询
陪玩师列表是这个平台的核心页面。用户可能通过首页搜索框输入游戏名或昵称,也可能在分类里点击某个玩法标签,还可能按价格、好评率、接单量排序。
如果直接用拼接字符串去写 SQL 的 WHERE,很容易注入,即使前端过滤了空格,代码审计时也很难看。我建议使用 MyBatis-Plus 的 LambdaQueryWrapper,配合 Page 分页实现动态条件查询。例如需要过滤状态为可接单、价格在区间内、分类匹配和关键词匹配等条件时,lambdaQuery 可以做到清晰可读,加上 OrderByDesc 实现倒序排列。
还有一个细节:陪玩师列表展示的价格。如果只展示基础价,点进去才发现高级分段需要另算,会导致用户退货。我通常会在 player_price_config 里建立“服务项目(如王者陪伴 1 小时、刺激战场上分 1 星)与价格映射”,当前端请求列表时只返回基础价;点击进入详情再返回可选的细分服务项和价格。这样列表页简单、详情页才有立体感,业务链也完整,不至于一张表从头用到底。
4.3 下单、防重和状态更新:用乐观锁保护关键一步
下单接口是整个系统最容易出错的地方。如果用默认的 http 请求直接落一条 Orders 记录,用户在前端连点两次“立即下单”,就会生成两条完全相同的订单,这在真实业务里不可能接受。
解决思路是给下单接口增加幂等控制。前端生成一个 requestId 传给后端,后端在 Redis 里用 setIfAbsent 设置一个 key,比如 order:submit:{userId}:{requestId},只有第一次请求能成功写入并继续执行,重复请求直接返回“请勿重复提交”。这种方式不需要引入分布式锁,代码量小,也足够撑起毕设需要的业务逻辑。
在陪玩师接单或者用户确认完成这些关键操作时,我建议使用“条件更新 + 返回值判断”的方式,而不是先 SELECT 再 UPDATE。直接执行类似这样的逻辑来更新订单状态:
java复制boolean updated = orderMapper.update(null,
new LambdaUpdateWrapper<Order>()
.eq(Order::getId, orderId)
.eq(Order::getStatus, OrderStatus.WAIT_ACCEPT.getCode())
.set(Order::getStatus, OrderStatus.SERVING.getCode())
.set(Order::getStartTime, LocalDateTime.now())
) > 0;
if (!updated) {
throw new BizException("订单已被接走或状态已变更");
}
这种写法好在:如果两个陪玩师同时抢同一单,只有一个人的 UPDATE 语句能匹配到“待接单”状态,另一个人会更新 0 行。这就是数据库层面的乐观锁,不用加 FOR UPDATE 也不会拖累并发性能。答辩时如果能讲清这个细节,老师基本不会再为难你。
4.4 服务完成、评价跟结算解耦
当陪玩师点击“结束服务”,订单状态从“服务中”变为“待确认完成”。这时候业务逻辑要做两件事:给用户发站内通知,同时等待用户确认。只有用户确认之后,结算逻辑才应该触发。
结算逻辑的关键是:不要直接把整单金额全打给陪玩师,要考虑平台抽成。假设平台抽成的比例是 10%,那么用户支付 100 元,平台抽 10 元,陪玩师入账 90 元。这个抽成比例你可以做成一个系统配置项,不要到处写死常量。后续如果老师临时问“抽成 20% 的话你代码怎么改”,你只需要改数据库,无需改代码。
我建议把结算动作放到独立 Service 中,用 @Transactional 注解包裹。完成时要同时做三件事:更新订单状态为已完成、给陪玩师钱包增加入账金额、为两条流水生成记录。任何一步失败都要把整体回滚,否则会出现订单已完成但陪玩师没收到钱,或者钱包有钱但流水对不上账的问题——这就是典型的面试题“分布式事务想考什么”的单机版本。
评价也应该放在订单状态已完成之后,且一个订单只能评价一次,通过订单表的 unique 约束或评价表里 order_id 唯一索引来保证。如果用户先评价再确认完成,会打乱资金流和状态机,所以我直接让评价只能在状态 4(已完成)下进行,并且评价时把用户的 rating、订单的评分同步回 player_info.rating 中。这些逻辑听起来很简单,但里面承载的是“你对业务闭环的理解”,而不仅仅是 CRUD。
5. 本地部署与常见环境问题:逐条对照排查
这个项目做得再好,部署不起来就前功尽弃。我以前帮人调过的绝大多数问题,不在业务代码,而在环境和配置细节。下面这些坑几乎每个 Spring Boot 毕设都会碰到。
5.1 数据库连接失败:八成是驱动和时区问题
如果你是本地 Windows 用 Navicat 能连上数据库,但项目启动报 Access denied for user 'root'@'localhost' 或者 Could not create connection to database server,通常是两种原因:
一是 Spring Boot 2.7 默认数据库驱动版本和 MySQL 8.0 有兼容问题,需要在 pom.xml 或者 application.yml 中指定 MySQL 驱动版本。
实际上 Spring Boot 2.7.x 内置依赖管理已经能正确选中 com.mysql:mysql-connector-j,如果你的 pom 里没有此依赖,则应用无法启动;如果显示 Unknown database 则说明库不存在:先执行 CREATE DATABASE project DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;,再去执行 SQL 脚本。另一个常见现象是 The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized,这是因为 8.0 后 MySQL 时区设置更严格。在 JDBC 连接参数上加上 serverTimezone=Asia/Shanghai 即可。
注意:我见过很多同学把数据库密码写在
application.yml里,还顺手提交到 GitHub。虽然这是毕设,但内部评审也能看到公开仓库。建议把密码改成环境变量形式,例如password: ${DB_PASSWORD:root},既能本地快速跑,也演示了配置项外部化的能力。
5.2 Mapper 无法注入或无绑定 SQL
Invalid bound statement (not found) 是 MyBatis-Plus 项目中出场率最高的错误。出现时,检查三处:
- 启动类的
@MapperScan扫描包路径是否正确; xxxMapper.xml的 namespace 是否与 Mapper 接口全限定名一致;- mapper xml 文件是否被 Maven 打包排除了,如果在
src/main/java下放 xml,需要在 pom.xml 中加上:
xml复制<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
如果不是 XML 方式而是纯注解 SQL,确保实体类上的 @TableName 和数据表名一致,字段驼峰转下划线要靠全局配置或 @TableField 指定。多数情况下,MapperScan 路径写错才是最让大家抓狂的点。
5.3 前后端分离的跨域问题
前端在 3000 端口访问后端 8080 端口,浏览器默认会拦截跨域请求。处理方式通常是后端提供一个全局配置类,添加一个 CorsFilter。注意:拦截器或过滤器中不要对 OPTIONS 请求做 JWT 校验,否则前端 preflight 预检请求会被拦截,导致你看到“CORS error”却找不到原因。
我的写法和很多老项目不太一样,不会在 Controller 上加 @CrossOrigin 注解,因为接口多了容易漏;而是选择一个大容器级的 CorsConfig 全局配置。配置里只要通过 allowedOriginPatterns("*") 允许所有来源,再把 allowCredentials(true) 设好即可。若你使用 Nginx 做前端转发,跨域问题会少很多,因为前后端变成同源,改为通过 proxy 转发 /api 到后端端口。
如果你的前端不是独立项目,而是用 thymeleaf 或后端直接返回页面,那没有跨域概念。这里就看你是前后端分离还是混合式开发了。既然是 Spring Boot 毕设,我建议前端直接采用 Vue 脚手架或简单的静态页面,既漂亮也展示了全栈能力。
5.4 首次演示视频录制前要准备哪些数据
一个项目的演示视频如果磕磕绊绊,极大影响评阅老师观感。很多同学在演示时才临时注册账号、下单,结果验证码没收到、Redis 没启动、图片上传失败。我建议留一套“演示专用数据”和一段节奏固定好的剧本。
演示前至少准备这些:
- 一个管理员账号,能登录后台看用户/订单统计;
- 一个陪玩师账号,确保该陪玩师状态是“可接单”,个人信息、头像、服务价格全部填完;
- 一个普通用户账号,钱包里有足够余额;
- 数据库中准备 5 条以上“可接单”状态的陪玩师记录,方便演示列表页的丰富感;
- 在 Redis 中预写入几个短信验证码,演示时直接输入并勾选“记住登录状态”。
录制前还要确认本地没有其他进程占用 8080 或 3306,提前双击运行一键启动脚本,或手动启动 redis-server 后再启后端。这样视频里不会出现“服务启动失败”的现场翻车。
6. 文档(LW)和源码怎么配合:把设计稿写到能答辩
“LW”在这类毕设资料的语境下通常指论文/设计文档。我有必要说一句:强烈不建议把源码、题和文档当成“交完即删”的临时工具,更不建议你拿买来的整套资料直接送审。正确心态应当是:把这些材料当作参考实现,通过阅读源码把每一张表、每个关键状态给彻底弄懂,再拆散后自己写一遍。因为查重不过的时候,没有任何“全套一条龙”能替你兜底。
真正合格的毕设文档,要能和源码对得上号。很多人的“LW”和实际代码完全两个样,老师一运行发现截图里的表单不是那样,那比没有文档还尴尬。建议按照经典本科毕设大纲写:绪论、需求分析、系统设计、数据库设计、核心功能实现、系统测试、总结与展望。其中“需求分析”和“系统设计”要跟着你真正做出的功能走,不要网上扒个电商论文改名字。
6.1 如何用小规模测试数据让演示有说服力
系统演示不需要大数据量,但至少要能展示分页、排序、按条件筛选。有些同学库里只塞了 3 条记录,列表翻不了页,只能跟老师解释“因为没有加分页”。这种话其实暴露了自己没准备演示数据。
我一般是写一个 DataInitializer 或者在数据库脚本里固定插入一批演示数据。常见的组合是:管理员账号 admin、用户账号 user、陪玩师账号 player1/player2/player3;订单数据做成不同状态各几条:一条待支付、一条待接单、一条服务中、一条已完成、一条退款中。这样一来,管理后台打开订单管理页时,五个状态标签页都能点开看到内容,演示效果马上完整。
但要注意:不要在录视频时把所有已完成的订单都显示成同一个卖家同一个买家。尽量制造一些不同的会话,至少保证每个状态有记录、有真实感。数据文件里尽可能加上状态变更时间、订单号、金额等字段,方便老师看到演示时产生代入感。
6.2 答辩前要重点记住的接口调用链
回到技术内容本身。作为毕设答辩人,你不需要背完所有接口,但至少要能不看代码,口述出一条完整的业务链路以及每个环节对应的控制器方法:
用户输入账号密码调 /api/auth/login -> 后端校验并签发 token -> 前端将 token 存起来并放全局 headers -> 用户请求 /api/player/list 拿陪玩师列表 -> 点击某一位陪玩师调 /api/player/{id}/detail -> 下单调 /api/order/create -> 支付调 /api/order/pay(钱包扣款) -> 陪玩师轮询待接单列表 /api/player/order/wait -> 点击接单调 /api/order/accept -> 服务结束,陪玩师调 /api/order/finishRequest -> 用户调用 /api/order/confirmFinish -> 系统完成订单并调 /api/order/comment 让用户评价。
只要能把“每次状态变更时权限是谁、前端做了什么校验、后端怎么保证并发安全”这三件事讲清楚,就已经超过 90% 的同学了。千万不要只回答“前端点个按钮就调了接口”这种话,那是把后端代码当骰子。
7. 我反复踩过、也看到别人踩的五个实战坑
最后不加总结提纲,只挑几个真实高发的坑来聊。如果你是从网上一份不错的整套源码开始,那么这些小问题你早晚会遇到。
7.1 文件上传后找不到图片
很多陪玩店项目都会有头像上传、陪玩师相册上传。如果你是把图片存在本地路径比如 /upload/avatar/xxx.jpg,但前端访问时用的是 localhost:8080/files/avatar/xxx.jpg,需要给项目加一个静态资源映射,或在 Nginx 上单独配置静态路由。否则就会出现“上传成功但页面图片裂开”的经典 Bug。
这段映射代码很小,放在配置类继承 WebMvcConfigurer,然后通过 addResourceHandlers 将 /files/** 映射到本地磁盘路径即可。这个点很小,却经常被卡住。
7.2 时间字段在 JSON 里变成“T”或 UTC 格式
LocalDateTime 默认序列化格式很丑,比如 2025-05-12T11:22:33,前端展示时需要转格式。可以在全局 application.yml 中设置:
yaml复制spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: Asia/Shanghai
这样 JSON 响应里会统一输出 2025-05-12 11:22:33;接收前端传来的时间参数时也建议用 @JsonFormat 标注。
7.3 金额用 double 导致精度对不上
钱包余额、订单金额千万不要用 double 或者 float 字段存。你做完支付、平台抽成、退款之后会发现各种类似 99.999999 的数字。数据库改成 DECIMAL(10,2),Java 里用 BigDecimal。加起来相减时调用 add、subtract,不要直接用运算符。
7.4 数据库初始化脚本执行顺序混乱
有些开源项目把表结构和演示数据都放在同一个 SQL 文件里,但是含有外键约束时,表必须先创建主表再创建从表。解决方式是每个脚本文件顶部都用 DROP TABLE IF EXISTS 处理,再按“基础账号表 → 业务表 → 订单流水相关表”的顺序从上到下执行。
如果你想演示得顺滑,建议自己手工执行一次数据库初始化,别指望双击一个 init.sql 就万事大吉。
7.5 管理端和用户端没有统一错误码
很多同学做后端接口时,喜欢一个接口返回 true,另一个返回 "error",第三接口返回 12345。前端拿到后无法统一判断。我推荐做一个统一返回体类 R<T>,固定包含 code、message、data 三个字段。成功时 code=200,失败时 code=500,并配合全局异常处理 @RestControllerAdvice 捕获异常。这样前端只需要判断 code 是否等于 200,联调速度快,模板代码也少。
我自己帮别人跑通这套线上陪玩店系统的时候,一个很深的体会是:Java 毕设真正拉开差距的地方,不在于用了多高级的中间件,而在于你能否把一个不算复杂的业务、用可靠的表结构和清晰的状态流转完整落地。Spring Boot 只是你的表达工具,陪玩店业务本身就是你最好的项目故事。先把主流程理顺、把钱包和订单状态补齐、把关键接口的状态保护做好,这已经是一份很能拿得出手的毕业设计了。
