
简介这是一套面向高校毕业设计或课程设计场景的小程序理发店预约系统完整源码包后端基于Java语言并采用SSM框架SpringSpringMVCMyBatis可运行于Tomcat7与JDK1.8环境数据库使用MySQL 5.7前端小程序部分则使用uniapp或原生小程序进行开发。系统功能覆盖后台的预约信息管理、理发信息管理、会员信息管理、系统设计管理以及小程序端的首页、理发项目、理发师、我的等模块能够支撑服务行业预约场景下的完整业务流程。资源压缩包共包含416个文件大小约36.21MB文件类型涵盖jar依赖包、java/class源码、xml配置、js/wxml/wxss前端页面、json数据、sql数据库脚本等同时附有说明文档方便导入IDE快速运行或进行二次修改。目前已有165人下载学习。除可运行代码外源码目录划分清晰能够帮助读者理解预约数据从客户端到后台的流转路径掌握SSM整合、小程序接口对接和数据库表设计等核心技能适合用于毕业设计、课程设计或学习典型前后端分离项目的开发思路。1. 拿到一套带 mysql 和 LW 的小程序理发店预约系统源码先搞清楚它到底交付了什么小程序理发店预约系统源码是近两年课程设计里最典型的“拿来即用”型交付物一个 zip 解压后里面有完整前后端代码、mysql 初始化脚本、说明文档和 LW毕业设计论文目标是让验收老师看到一条能跑通的预约闭环。对急着做毕设、又担心自己写不透业务逻辑的学生来说它比从零搭一座省一半时间但前提是你真的能把它讲明白而不是只会双击启动。这篇笔记按我接手这种包的习惯顺序来写先拆表结构和数据流再讲本地跑通的最小步骤然后聊怎么改成你自己的题目最后列部署和答辩时最容易翻车的五个坑。2. 拆开理发店预约系统的骨架预约数据流、表结构和状态机是连在一起的2.1 从用户点预约到理发师核销一次预约在系统里经历了什么要理解这套源码不能一头扎进前端页面代码里找答案。正确顺序是先看数据流用户打开小程序通过微信登录拿到 openid进入首页看到门店列表点进门店后选择理发师、服务项目、时间段提交预约后端把数据写入预约表管理端网页后台或理发师端小程序刷新后看到待确认列表点击确认用户端小程序收到状态变更提示到店后理发师核销状态改成已完成最后用户可以对该次服务做评价。这套流程三个端口各管一段小程序管展示与提交管理端管审核与统计后端 API 管状态流转和数据校验。答辩时最常被追问的就是“哪些逻辑必须放在后端”答案就是时段冲突检测和状态流转。如果把冲突检测放在小程序里用户改一下手机时间就能绕过限制所以这套源码里判重逻辑一定写在后端事务中。看懂这一点后面你要加限制条件时就知道代码该加到哪一层而不是在前端页面里到处找判断。2.2 数据库设计理发店预约至少要拆出这几张表不能堆在一张表里解压后先找到 sql 目录下的初始化脚本常见命名是 init.sql 或 db_hair.sql。打开后第一件事不是看数据而是看建表语句。一套合格的小程序理发店预约系统表结构通常按业务主体拆成五张以上基本形式如下-- 用户表存微信用户的 openid作为登录唯一标识 CREATE TABLE user ( id INT AUTO_INCREMENT PRIMARY KEY, openid VARCHAR(64) NOT NULL UNIQUE, nickname VARCHAR(50) DEFAULT , phone VARCHAR(20) DEFAULT , create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 门店表一个系统可以管多家分店 CREATE TABLE shop ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, address VARCHAR(200) DEFAULT , business_hours VARCHAR(50) DEFAULT 09:00-21:00 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 理发师表归属到门店 CREATE TABLE barber ( id INT AUTO_INCREMENT PRIMARY KEY, shop_id INT NOT NULL, name VARCHAR(50) NOT NULL, avatar VARCHAR(200) DEFAULT , job_title VARCHAR(50) DEFAULT COMMENT 头衔如资深设计师, KEY idx_shop (shop_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 服务项目表洗剪吹、烫发、染发等 CREATE TABLE service ( id INT AUTO_INCREMENT PRIMARY KEY, shop_id INT NOT NULL, name VARCHAR(50) NOT NULL, price DECIMAL(10,2) NOT NULL DEFAULT 0, duration INT NOT NULL DEFAULT 30 COMMENT 单次耗时单位分钟, KEY idx_shop (shop_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 预约主表核心业务表 CREATE TABLE appointment ( id INT AUTO_INCREMENT PRIMARY KEY, order_no VARCHAR(32) NOT NULL COMMENT 预约单号, user_id INT NOT NULL, shop_id INT NOT NULL, barber_id INT NOT NULL, service_id INT NOT NULL, appoint_date DATE NOT NULL, appoint_time TIME NOT NULL, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待确认 1已确认 2已完成 3已取消 4爽约, remark VARCHAR(255) DEFAULT , create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_user (user_id), KEY idx_date_time (appoint_date, appoint_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这段 DDL 里有四个细节值得你留意。第一appointment 表冗余了 shop_id 和 barber_id而不是只存一个 barber_id因为理发师可能调店管理端按门店筛选时能少一次关联查询。第二预约时间拆成 appoint_date 和 appoint_time 两列而不是一个 DATETIME方便按天统计、按时间段渲染管理端格子。第三idx_date_time 联合索引是时段判重的基础判重 SQL 就是 WHERE appoint_date ? AND appoint_time ? AND status IN (0,1)没有这个索引订单量一大判重会明显变慢。第四status 用 TINYINT 而不是字符串数值含义在说明文档里配一张状态表答辩时画状态图也方便。如果打开的源码表比这套还少比如把 service 直接并进 appointment或者没有 shop 表说明这是被精简过的阉割版。老师一旦问“店要开第二家分店怎么办”这种表结构答不上来。这套基础结构能覆盖大部分预约类课程设计后面换美甲店、宠物店也通用属于最稳的模板。2.3 预约状态不是随便一个字段它是一个维护在代码里的状态机appointment.status 的五个取值在源码里通常对应一组常量或枚举命名形式一般是状态码加描述public enum AppointmentStatus { PENDING(0, 待确认), CONFIRMED(1, 已确认), COMPLETED(2, 已完成), CANCELLED(3, 已取消), NO_SHOW(4, 爽约); private final int code; private final String desc; // 构造器和 getter 这里省略 }状态流转的合法路径只有三条待确认到已确认再到已完成待确认直接到已取消已确认后到爽约。如果后端接口允许从“已完成”直接改回“待确认”说明源码没写状态校验这种包答辩容易翻车。收到源码后可以全局搜一下 updateStatus 或 setStatus确认每处修改都带当前状态判断这是评估一套源码质量最省事的技巧。管理端确认预约本质上就是一条 UPDATE ... SET status 1 WHERE id ? AND status 0 的带条件更新。这种写法既是状态机落地也是防止重复确认的兜底。教学版源码一般不会再加乐观锁版本号因为单店预约并发量不高单条件更新已经够用。你在论文里把这条 SQL 的原子性讲清楚老师就会认可。2.4 前后端通信约定baseUrl、登录态和接口前缀小程序端和后端之间走的是 JSON 接口不是页面跳转。在小程序目录的 config.js 或 app.js 里找 baseUrl核心配置就两个参数module.exports { // 本地联调时指向你电脑的局域网 IP不能写 localhost真机访问不到 baseUrl: http://192.168.1.100:8080/api, appId: , // 有真实小程序账号就填没有就留空用测试号 version: 1.0.0 };这套源码的接口风格一般是 /api/login、/api/appointment/create、/api/appointment/list、/api/appointment/confirm、/api/appointment/complete。登录接口的逻辑基本都是拿 wx.login 的 code 换 openid再把 user 表里的用户信息塞进 token 返回。前后端约定里有一条通用规则小程序端每次请求都要在 header 带 Authorization后端用一个拦截器统一校验登录接口除外。如果你发现某个接口在小程序里能打开但 wx.request 一调就返回 401先去查登录态是不是过期这是最常见的联调卡点。mysql 在整个架构里的位置很简单用 InnoDB 引擎保证预约写入不丢用 utf8mb4 保证中文备注不乱码。后面启动时如果中文全部变成问号基本就是建表没指定 charset或者连接串漏了 characterEncodingutf8。这套约定吃透了换任何前后端分离的预约系统都能快速上手。3. 本地跑通全套源码JDK、MySQL、微信开发者工具的配置与最小启动链路3.1 装环境时先定版本JDK 8 搭配 MySQL 8.x 是最稳的起点解压后先花五分钟看说明文档里的运行环境一栏。大多数毕设包的默认搭配是 JDK 8 MySQL 8.0 微信开发者工具稳定版。JDK 版本是最容易翻车的点后端如果是 Spring Boot 2.x用 JDK 17 一般也能跑但有些老包的依赖用了过时的 javax 命名空间JDK 17 下直接启动失败。组合能否启动遇到报错时怎么办JDK 8 Spring Boot 2.x稳定基本无兼容问题优先选这个JDK 17 Spring Boot 2.7 以上多数能跑报 java.lang.NoClassDefFoundError 时切回 JDK 8MySQL 8.x mysql-connector-java 8.x稳定确认连接串加 useSSLfalseMySQL 5.7 8.x 驱动兼容驱动对 5.7 兼容但时区参数必须加MySQL 这边8.0 和 5.7 的差异主要体现在认证方式和连接驱动上。如果源码 pom.xml 里 mysql-connector-java 版本写的是 8.x数据库就装 8.x写的是 5.1.x用 MySQL 8 会报认证插件错误需要在连接串里加 allowPublicKeyRetrievaltrue。这两个参数后面一起写进配置文件避免反复重启。3.2 导入数据库和初始化数据两条命令搞定别用图形工具拖拽我建议第一次导库先用命令行因为报错信息比图形工具直白。打开终端进入 sql 脚本所在目录# 登录 mysql密码是安装时设置的 root 密码 mysql -u root -p # 登录后执行创建数据库并导入脚本 CREATE DATABASE IF NOT EXISTS hair_system DEFAULT CHARACTER SET utf8mb4; USE hair_system; SOURCE /path/to/db_hair.sql;这里解释一下为什么不要直接双击 sql 文件很多毕设包里的 sql 文件头部没有 CREATE DATABASE 语句直接导入会不知道导入到哪个库或者把表建在别的库下面。SOURCE 方式是逐行执行报错会停在出错行方便你定位是哪条语句字段类型写错。导入完成后执行 SHOW TABLES应该能看到 user、shop、barber、service、appointment 五张基础表好一点的包还会带 comment 评价表和 admin 管理员表。看到表还不算完再执行 SELECT COUNT(*) FROM barber有初始数据才算导入成功。如果 mysql 命令报 ERROR 2002 (HY000)Cant connect to local MySQL server through socket /tmp/mysql.sock这说明服务没起来不是密码错。处理方式放到第五章避坑里细讲这里你先确认 mysql 服务正常运行。3.3 改后端连接配置application.yml 里必须核对的五个参数后端项目在 src/main/resources 下Spring Boot 工程常见文件名是 application.yml。需要改的配置集中在数据源那一块server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/hair_system?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 username: root password: 123456 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai五个必须核对的参数是数据库名、用户名、密码、端口、时区。其中 serverTimezoneAsia/Shanghai 如果写成 UTC预约时间在你列表里会整体差 8 小时这是时间字段最经典的“黑匣子”现象。driver-class-name 用 com.mysql.cj.jdbc.Driver 表示连接 MySQL 8如果源码适配的是 5.7改成 com.mysql.jdbc.Driver 也可以但一般新驱动对 5.7 是兼容的不用动。改完配置后在后端根目录执行启动命令# 项目根目录有 pom.xml 时 mvn spring-boot:run # 或者先打包再跑答辩前适合用这种方式 mvn clean package -DskipTests java -jar target/hair-system-0.0.1-SNAPSHOT.jar看到日志里出现 Started ... in 10.2 seconds并且没有 Exception后端就算起来了。这时打开浏览器访问 http://localhost:8080/api/shop/list能返回 JSON 数组说明后端已经连上 mysql。如果这里返回 404看是不是接口前缀少了 /api如果返回 500 且控制台有 SQL 错误回 sql 脚本里比对表名和字段名。这套源码是打 jar 直接跑的不需要额外装 tomcat别被网上那些 SSM 老教程带偏去部署 war 包。3.4 拉起小程序端开发者工具里的三个设置和一个验证动作后端跑通后小程序端才能联调。用微信开发者工具“导入项目”选择小程序目录AppID 先选测试号然后别急着点编译先改三处config.js 的 baseUrl 改成你本机局域网 IP详情设置里勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”再确认调试基础库版本和说明文档一致常见是 2.30.x 以上。点编译后首页应能看到门店列表。进到预约页正常情况服务项目和理发师都来自接口不是写死的假数据。打开调试器的 Network 面板刷新一次能看到类型为 XHR 的请求打到你的局域网 IP状态码 200说明前后端联调成功。如果看到 ERR_CONNECTION_REFUSED先 ping 一下后端 IP 通不通再确认后端是不是监听在 0.0.0.0 而不是 127.0.0.1。关于 mysql 的细节点一句这套系统的数据源用的是标准连接池配置Spring Boot 默认的 HikariCP 不用额外调参数本地跑并发不高所以连接池大小保持默认就行。不要在源码里硬塞存储过程预约这种轻业务用存储过程反而会让论文讲不清楚写进 Mapper 的 SQL 更直观。4. 把模板改成你自己的毕业设计换行业、改预约逻辑、对齐 LW 的三个切入点4.1 从理发店换到美甲店或宠物店改四处数据不动表结构理发店预约系统换行业不需要动表结构只要改造内置数据和展示文案。具体改四处sql 脚本里的服务项目 seed 数据把“洗剪吹、烫发、染发”改成“基础美甲、接睫毛、手部护理”或“宠物洗澡、美容、驱虫”小程序首页的 banner 图和店铺介绍文案管理端的图表标题LW 里的系统名称。服务项目的初始化数据在 sql 脚本末尾按这个格式替换即可INSERT INTO service (shop_id, name, price, duration) VALUES (1, 基础美甲, 68.00, 60), (1, 接睫毛, 128.00, 90), (1, 手足护理, 88.00, 45);注意两点duration 单位是分钟price 用 DECIMAL 不要加人民币符号如果你在数据里写了“¥68”小程序端格式化价格时可能显示成 NaN。真正要动代码的是服务时长粒度理发剪发一般 30-45 分钟宠物美容可能要 90 分钟。如果源码里时段生成固定是半小时一格而新行业需要一小时一格去后端生成时段列表的工具类里改 STEP_MINUTES 这样的常量。标题里的“理发店”到这里就算替换完成其余预约状态机完全不用碰。4.2 给预约加一个并发保护同一时段不允许两个人同时抢到原始源码大概率只做了基础判重预约前查一次有没有冲突记录没有就插入。但答辩老师爱问“两个人同时提交同一个时段怎么办”。这里花 20 分钟打一个补丁就能把上线变得有说法。最常见的做法是在后端加事务把“判重加插入”包成原子操作// 事务方法核心思路 Transactional public synchronized Appointment createAppointment(CreateRequest req) { // 1. 判重同一理发师同一日期同一时段只允许一个预约 int count appointmentMapper.countByBarberAndTime( req.getBarberId(), req.getAppointDate(), req.getAppointTime(), Arrays.asList(Status.PENDING.getCode(), Status.CONFIRMED.getCode())); if (count 0) { throw new ServiceException(该时段已被预约请选择其他时间); } // 2. 生成单号并插入 Appointment app buildAppointment(req); appointmentMapper.insert(app); return app; }关键在 Transactional判重和插入在同一个数据库事务里要么都成功要么都回滚。synchronized 是给 JVM 进程内加的第二道锁防止同一实例并发进入以后如果拆多实例部署再换 Redis 分布式锁毕设阶段做到两层已经足够。改完后用后端接口做并发测试把同一个创建预约请求复制两份同时发送第二条必然收到“该时段已被预约”的报错。这个改进写进 LW 的系统优化小节就是现成的加分点。还需要注意判重查询一定要走索引。如果源码表里没建 barber_id、appoint_date、appoint_time 的联合索引先补一句 ALTER TABLE appointment ADD INDEX idx_barber_time (barber_id, appoint_date, appoint_time)否则并发一上来会锁表范围变大延迟明显。4.3 LW 论文怎么和代码对得上三处一致性检查必须做拿到源码附带的 LW 文档最忌讳直接交原稿。老师翻文档时是拿实跑界面核对的查重系统也会比对图表和代码。建议按三个一致性去改LW 里的 ER 图字段必须和 sql 表字段一致如果文档里写 userInfo 而代码里是 user说明文档没跟上代码时序图里的接口路径必须是 baseUrl 加实际路径不能画一个 /appointment 却跑的是 /appointment/create功能列表必须和小程序页面一一对应别在论文里写了“会员卡管理”页面里却找不到入口。检查项对照位置常见问题ER 图字段sql 建表语句文档用旧表名代码已改名时序图接口config.js 的 baseUrl Controller 映射路径少写 /api 前缀功能列表小程序 pages 目录论文写了的页面不存在具体操作上用 mysqldump 导出当前表结构mysqldump -u root -p --no-data hair_system schema_now.sql然后打开 LW 里 ER 图的字段清单逐行核对。带 LW 的包评阅老师第一眼看目录摘要、需求分析、系统设计、数据库设计、系统实现、测试。把这六章的图表全部换成导入脚本生成的新截图不要用文档自带截图因为那些截图截的是旧数据日期。比如界面里显示 2023-05-01放在 2025 年的论文里就是硬伤答辩时会被一眼盯上。4.4 管理端再加一个日报表统计把“能用”变成“有亮点”很多源码的管理端只有预约列表和基础的增删改查缺一个按日维度统计营业额的功能。这个功能代码量不大但很贴合理发店场景店主想知道今天剪了几个头、烫了几个头、收了多少钱。常见的实现是在管理端 Controller 加一个统计接口// 统计接口按日期和服务项目分组 GetMapping(/api/report/daily) public Result dailyReport(RequestParam String date) { ListMapString, Object rows reportMapper.countByDate(date); return Result.success(rows); }对应的 Mapper 查询按服务项目分组统计已完成订单的数量和金额SELECT s.name AS service_name, COUNT(a.id) AS order_count, SUM(s.price) AS total_amount FROM appointment a JOIN service s ON a.service_id s.id WHERE a.appoint_date #{date} AND a.status 2 GROUP BY s.name;这张报表做出来后在管理端导航里加一个入口LW 的系统实现章节就能多一张真实截图。这类功能比调 UI 样式更能体现你对业务的理解答辩时也更有东西可讲。注意 SUM(s.price) 用 DECIMAL 字段不会有精度问题但如果 service 表里价格存成了 VARCHAR这里会报错所以初始化数据时一定要按规范字段类型写入。5. 部署和答辩避坑指南mysql 连不上、真机白屏、LW 对不上的五条踩坑记录5.1 mysql 2002 错误启动半天死在 socket 连接上现象打开终端执行 mysql -u root -p直接报 ERROR 2002 (HY000)Cant connect to local MySQL server through socket /tmp/mysql.sock重启电脑后最常出现。原因MySQL 服务没启动或者安装时配置的 socket 路径和默认路径不一致。最常见的是前者手动安装的 MySQL 不会开机自启你打开终端时服务还没起来。解决macOS 上执行 brew services start mysqlLinux 上执行 systemctl start mysqld 或 service mysql startWindows 上在服务管理器里找到 MySQL80 并启动。如果服务状态已经是 running 仍报错去 mysql 安装目录找 my.cnf确认 socket 路径是不是 /tmp/mysql.sock改成实际路径。改完再看后端日志如果此时报警 Access denied for user rootlocalhost说明用户名密码和 application.yml 里不一致回去改配置文件不要反复卸载重装 mysql那是大多数新手最后悔的一步。5.2 真机预览白屏或接口 401问题出在 baseUrl 和登录态现象微信开发者工具里一切正常用手机预览后页面空白或者能进首页但一提交预约就提示登录过期。原因开发者工具的“不校验合法域名”只对工具内生效真机上 wx.request 请求的是 http 明文地址另外 baseUrl 如果写 localhost手机访问的是手机自己还有一种情况是 request header 没带 token后端拦截器直接放行失败。解决第一baseUrl 改成电脑的局域网 IP手机和电脑连同一个 Wi-Fi。第二开发商用工具时保持“不校验合法域名”勾选但答辩现场建议直接用开发者工具演示避免被追问为什么不走 HTTPS。第三登录态过期时回 app.js 确认每次 wx.request 的 header 都带 token写法是 header: { Authorization: getApp().globalData.token }并在 onShow 里重新执行 wx.login 换新 openid。这三件事互相叠加排查时按 IP、网络、token 的顺序逐个排除几分钟就能定位。5.3 时间段明明空着提交却说“已预约”索引和状态判断各查一处现象管理端看到某时段没有任何预约小程序一提交就提示已被预约或者反过来已确认的时段还能再被提交数据直接覆盖。原因第一种往往是判重 SQL 只查了 CONFIRMED 状态没查 PENDING数据库里恰好有一笔状态为 0 的旧数据界面不展示但它真实存在判重逻辑认它。第二种是判重 SQL 没走索引或者 Mapper 里的条件写漏了 barber_id并发下两边同时插入成功。解决打开后端 Mapper XML找到判重 SQL确认 WHERE 里包含 status IN (0,1)并把状态过滤参数补全。再给 barber_id、appoint_date、appoint_time 加联合索引ALTER TABLE appointment ADD INDEX idx_barber_time (barber_id, appoint_date, appoint_time);改完重跑并发测试复制同一个创建预约请求同时发两次第二条会被拒绝。能拒绝说明事务逻辑是通的。这里要顺带提一下 mysql 的默认值问题appointment 表里 status 字段用 DEFAULT 0也就是说哪怕后端代码忘记传状态也会落到待确认而不是空值这种设计能少一类脏数据。5.4 管理端图表数字和 SQL 查出来对不上十有八九是缓存或时区错位现象LW 测试章节截图显示今日预约 12 条但你在管理端看到 3 条或者订单时间差 8 小时日期范围对不上。原因管理端首页可能用了本地缓存或框架的 keep-alive没有强刷导致界面数据是旧的时间偏移则基本是 jdbc:mysql 连接串没带 serverTimezoneAsia/Shanghai默认 UTC 导致查询结果整体时差 8 小时。解决先按 CtrlShiftR 强制刷新浏览器不复现就是缓存问题复现就是连库统计逻辑的问题。打开统计 SQL 的日志确认 count 查询的范围是 appoint_date 当前日期并且统计状态是 status 2 已完成。时区问题按前面 3.3 的连接串改一遍重启后端再验证。LW 截图不要直接用文档里的重新导一遍数据让界面数字和 SQL 查出来的一致再截新图替换。5.5 端口被占用导致后端一条接口都调不通8080 被吞了现象启动日志显示 Web server failed to start. Port 8080 was already in use后端点开全是连接拒绝。原因后台有别的 java 进程或开发工具占用了 8080最常见是之前启动过一次没关干净或者电脑上装了其他占用 8080 的服务。解决找到占用进程并结束macOS 和 Linux 用 lsof -i:8080Windows 用 netstat -ano | findstr 8080拿到 PID 后 kill。如果不想每次和别的项目打架把 application.yml 的 server.port 改成 8081然后 config.js 的 baseUrl 同步改成 http://192.168.1.100:8081/api。注意小程序端请求的端口必须和后端配置完全一致改了一处另一处没改就会卡在“开发者工具里能编译但一请求就失败”这种半通不通的状态。6. 答辩前一夜的 30 分钟把演示脚本和两个加分项练到不慌真正决定这套源码成绩的不是代码能跑而是演示节奏和验证动作。我习惯在答辩前一晚把整个流程压缩成 30 分钟脚本只依赖一个终端窗口和一个微信开发者工具窗口避免现场切换翻车。第一步提前用 nohup 把后端启起来并确认 mysql 已开机自启这样答辩现场只需要打开小程序首页不需要当场敲命令等编译。启动命令可以写成一行nohup java -jar target/hair-system-0.0.1-SNAPSHOT.jar app.log 21 第二步演示顺序固定为微信授权登录选店、选理发师、选服务、选时间段、提交预约随后切到管理端确认、核销、评价把预约状态完整走一遍。第三步现场主动加两个验证动作在管理端把预约单状态改成已完成然后立刻切到小程序端展示核销成功页面再加一条数据库查询 SELECT * FROM appointment ORDER BY id DESC LIMIT 5让现场看到所有状态在落库流水里的变化。这两个动作能把“系统真的有数据写进 mysql”这件事讲透比空口说十句都管用。演示时还要准备两个“后悔药”如果管理端页面白屏先确认后端进程还在再看接口返回如果小程序提交一直转圈直接看 Network 面板是超时还是 500。超时多半是 baseUrl 的局域网 IP 变了500 就去看后端日志 tail -200 app.log按第五章的避坑条目逐条核对。我现在接手任何一套毕业设计源码第一件事都是看 sql 文件和连接配置而不是急着点小程序页面。源码能不能过一半取决于 mysql 表结构是否严谨一半取决于 LW 文档和你改过的代码是否一致。这套理发店预约的架构只要把表、状态机、联调配置吃透换十个行业题目都改得出来。希望帮到你。本文还有配套的精品资源点击获取