拓冰建站拓冰建站
首页 / 资讯中心 / 正文

SpringBoot+微信小程序+MySQL:健身房预约系统全栈开发实践

简介基于JAVA语言开发整合SpringBoot2.X、微信小程序与MySQL的健身房预约管理系统是一套可直接运行并二次扩展的毕业设计项目。面向计算机相关专业学生、毕业设计作者及预约类系统开发者覆盖用户预约、课程管理、教练排期等场景后端分层清晰前端包含小程序端与管理后台具备较好的工程完整性。压缩包共1642个文件大小106.03MB内含179个java核心后端、173个vue管理端页面、132个wxml和132个wxss小程序页面、143个json配置、319个png页面截图以及sql数据库脚本、部署说明与mp4演示视频便于按目录检索和对照排错。目前已有401人学习下载适合需要完整源码、设计文档及视频演示来支撑毕设或课程设计的读者。1. 为什么健身房预约系统都选 SpringBoot 微信小程序 MySQL如果你打开招聘软件搜“Java 全栈开发”十个岗位里至少有三四个要求候选人做过小程序项目。健身房预约管理系统恰好是这类需求的浓缩样本它前端要适配微信生态、后端要处理并发预约、数据层要设计时段与订单关系规模不大但业务闭环完整特别适合验证一个 Java 开发者从建表到上线部署的全链路能力。这类系统在真实场景里解决的痛点很直接传统健身房靠前台登记或电话预约课程满员、私教时间冲突、会员到场无记录全靠人工协调。换成线上预约后会员在微信里就能看到课程排期、锁定时段、取消预约教练端能查看当日课表管理后台则负责设置场地容量与课程计划。技术上其实没有高深算法核心是时段资源的并发控制和会员与订单的状态管理。从技术选型看SpringBoot 负责提供 RESTful API 和事务管理微信小程序承担 C 端入口MySQL 存储会员、课程、预约订单等结构化数据。三者组合的成熟度非常高SpringBoot 的自动配置降低了集成成本微信小程序有官方登录与支付能力MySQL 则通过事务和行锁解决预约场景的冲突问题。接下来我从数据库设计开始一步一步把整个系统的实现路径拆开讲清楚。2. 数据库设计实现一个可用的健身房预约数据模型2.1 最小表结构会员表、课程表、预约订单表健身房预约系统的数据模型可以从三个核心实体出发会员user、课程/场地course、预约订单appointment。我也见过把场地和课程分成两张表的做法但对中小型健身房来说课程本身就包含场地属性合并成一张表即可避免过度设计。会员表要存的字段包括微信小程序侧需要的 openid、用户昵称、手机号、会员等级、剩余课时数。课程表需要课程名称、教练、上课日期、开始时间、结束时间、容量上限、已预约人数、课程状态。预约订单表则是核心业务表记录哪个会员在什么时间预约了哪节课以及订单当前状态。-- 会员表 CREATE TABLE member ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 主键, openid VARCHAR(64) NOT NULL COMMENT 微信openid, nickname VARCHAR(64) DEFAULT COMMENT 昵称, phone VARCHAR(20) DEFAULT COMMENT 手机号, level TINYINT DEFAULT 1 COMMENT 会员等级 1普通 2高级, remaining_classes INT DEFAULT 0 COMMENT 剩余课时, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT会员表; -- 课程表 CREATE TABLE course ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 主键, name VARCHAR(128) NOT NULL COMMENT 课程名称, coach_name VARCHAR(64) DEFAULT COMMENT 教练, course_date DATE NOT NULL COMMENT 上课日期, start_time TIME NOT NULL COMMENT 开始时间, end_time TIME NOT NULL COMMENT 结束时间, capacity INT DEFAULT 10 COMMENT 容量上限, booked_count INT DEFAULT 0 COMMENT 已预约人数, status TINYINT DEFAULT 1 COMMENT 1可预约 0已约满, PRIMARY KEY (id), KEY idx_date (course_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT课程表; -- 预约订单表 CREATE TABLE appointment ( id BIGINT NOT NULL AUTO_INCREMENT, member_id BIGINT NOT NULL COMMENT 会员ID, course_id BIGINT NOT NULL COMMENT 课程ID, status TINYINT DEFAULT 1 COMMENT 1已预约 2已取消 3已完成, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_member (member_id), KEY idx_course (course_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT预约订单表;以上表结构对「会员-课程-订单」做了最直接的建模。设计时的关键约束在两点第一订单表的业务主键是(member_id, course_id)的组合语义即一个会员对同一节课只能有一条预约记录第二在 MySQL 的 InnoDB 引擎下course_id建立索引后对同一门课程并发写入订单时会产生行锁等待天然为后续预约逻辑提供了并发控制基础。2.2 预约状态机与时间段冲突检测的业务规则预约系统的核心难点不在建表而在状态流转规则的完整性。一个预约订单从创建到结束至少要经历以下几个状态已预约、已取消、已完成。如果后续对接支付还要增加待支付状态。设计状态字段时用 TINYINT 比用字符串更省空间但可读性差一些常见的取舍是实体类里定义常量或枚举统一管理。时间段冲突检测有两种实现路线一种是业务代码里查出课程表同一个日期下所有未结束课程逐一比对时间区间另一种是数据库层面用条件查询直接判断。-- 查出同一日期下冲突的课程 SELECT id FROM course WHERE course_date #{date} AND status 1 AND start_time #{endTime} AND end_time #{startTime} AND id ! #{courseId}这个 SQL 的核心逻辑是判断两个时间区间是否重叠只要新的开始时间小于已有课程的结束时间并且新的结束时间大于已有课程的开始时间就说明存在交叉。我在实际项目里还会把这个校验同时用在课程创建的接口和预约接口上避免管理员在后台上架新课时选到已被占用的时间。另一个容易被忽略的业务规则是取消预约后的容量释放。已预约人数booked_count的增减必须在同一次事务中与订单状态变更一起提交否则会出现订单状态已经取消但课容量仍被占用的数据不一致问题。2.3 初始化数据脚本与演示账号的设计要点源码包里通常会附带sql/init.sql初始化脚本里面除了建表语句还会有演示数据。写初始化数据要特别注意三点第一密码必须存加密后的值不要明文存库第二课程演示数据的时间要设计在「未来几天内」否则一打开小程序全是没有可预约课程的界面体验很差第三如果项目里用了 Flyway 或 Liquibase 做版本管理脚本文件名要遵循对应的命名规范单纯的手工导入 SQL 在生产环境并不推荐。-- 初始化演示课程的示例 INSERT INTO course (name, coach_name, course_date, start_time, end_time, capacity, booked_count) VALUES (动感单车, 李教练, DATE_ADD(CURDATE(), INTERVAL 1 DAY), 19:00:00, 20:00:00, 20, 0), (高温瑜伽, 王教练, DATE_ADD(CURDATE(), INTERVAL 1 DAY), 18:00:00, 19:00:00, 15, 0), (HIIT燃脂, 张教练, DATE_ADD(CURDATE(), INTERVAL 2 DAY), 20:00:00, 21:00:00, 12, 0);DATE_ADD的作用是让课程日期跟随系统当前时间动态生成无论什么时候执行脚本演示数据都在最近几天内。这样做的好处是评审演示时不用手动改 SQL坏处是数据库时间不准确时会直接影响数据展示。3. SpringBoot 后端搭好预约系统的骨架3.1 项目分层与依赖管理的标准动作拿到一个 SpringBoot 项目的源码第一步要看pom.xml。健身房预约系统常用的依赖组合是spring-boot-starter-web、spring-boot-starter-validation、mybatis-plus-boot-starter或 mybatis 原生、mysql-connector-j、lombok、spring-boot-starter-test。如果集成了微信登录与支付还要引入weixin-java-miniapp这类第三方封装库或者参考官方文档自己封装WxMaService。项目结构上我习惯按功能模块分包而不是按技术分层分包。控制器、服务、Mapper 三层按业务领域聚合在一起后续维护时改动面更集中。com.example.gym ├── controller # 接口层 │ ├── AuthController │ ├── CourseController │ └── AppointmentController ├── service # 业务逻辑层 │ ├── AppointmentService │ └── impl/ ├── mapper # 数据访问层 ├── entity # 数据库实体 ├── dto # 请求/响应对象 ├── config # 配置类微信、拦截器等 └── common # 统一返回结果、异常处理3.2 统一响应结构与全局异常处理怎么写不踩坑给小程序端提供接口时最重要的是约定的响应结构。小程序开发者工具里调试接口时看不到 SpringBoot 默认的 Whitelabel Error Page拿到的是 JSON所以必须设计统一的返回格式。Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } public static T ResultT error(Integer code, String message) { ResultT result new Result(); result.setCode(code); result.setMessage(message); return result; } }全局异常处理用RestControllerAdvice拦截业务异常和参数校验异常。实际开发中我会自定义一个BusinessException里面持有错误码和错误信息Service 层需要中断业务流程时直接抛出由全局处理器统一转换为 JSON 返回避免每个接口都写 try-catch。小程序端判断接口是否成功只需检查返回的 HTTP 状态码以及 JSON 里的code字段是否为 200 即可。处理微信接口调用返回的错误码时要特别注意业务语义不能和 HTTP 状态码混在一起。微信小程序端通过wx.request发起请求时基线 URL 要指向 HTTPS 域名秒超时时间也要在wx.request的配置里合理设置前后端超时策略不一致会导致预约提交失败但订单实际已入库的副作用。3.3 基于 JWT 的登录态管理与拦截器配置小程序端的登录态不能依赖传统的 Session 机制因为微信小程序的网络请求天然无 Cookie 概念标准方案是 JWT。用户通过wx.login拿到临时code后端用这个 code 调用微信接口换取openid然后签发 JWT 返回给前端。小程序后续每次请求在 Header 里带上Authorization: Bearer token后端拦截器校验 token、解析出用户身份。Component public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod)) { return true; } String token request.getHeader(Authorization); if (StringUtils.hasText(token) token.startsWith(Bearer )) { token token.substring(7); } try { Claims claims Jwts.parser() .setSigningKey(secretKey) .parseClaimsJws(token) .getBody(); request.setAttribute(memberId, claims.get(memberId)); return true; } catch (Exception e) { response.setStatus(401); response.setContentType(application/json;charsetUTF-8); response.getWriter().write({\code\:401,\message\:\登录已过期\}); return false; } } }这段代码把 JWT 解析后得到的memberId放进requestattribute后续在 Controller 里通过RequestAttribute(memberId)就能拿到当前登录用户避免了每次查询数据库获取会员信息。拦截器注册时要注意排除/auth/login、/wx/callback这类不需要鉴权的路径微信支付回调接口如果被拦截会导致回调签收失败订单状态无法更新。3.4 我的预约功能实现后端接口的三层接口设计后端接口设计上要尽量贴合小程序端的页面需要页面一次只调一个接口。预约系统的核心接口包括获取可预约课程列表、创建预约、取消预约、查看我的预约、获取课程详情。下面以「创建预约」接口为例看 Service 层完整逻辑。public class AppointmentServiceImpl implements AppointmentService { Override Transactional(rollbackFor Exception.class) public Long createAppointment(CreateAppointmentRequest request, Long memberId) { // 1. 锁课程行防止超卖 Course course courseMapper.selectByIdForUpdate(request.getCourseId()); if (course null) { throw new BusinessException(400, 课程不存在); } // 2. 校验课程状态与容量 if (course.getStatus() 0) { throw new BusinessException(400, 课程已下架); } if (course.getBookedCount() course.getCapacity()) { throw new BusinessException(400, 课程已约满); } // 3. 校验会员是否已预约该课程 Integer exists appointmentMapper.selectCountByMemberAndCourse(memberId, request.getCourseId()); if (exists 0) { throw new BusinessException(400, 您已预约过该课程); } // 4. 插入订单累加已预约人数 Appointment appointment new Appointment(); appointment.setMemberId(memberId); appointment.setCourseId(request.getCourseId()); appointment.setStatus(1); appointmentMapper.insert(appointment); courseMapper.increaseBookedCount(request.getCourseId()); return appointment.getId(); } }selectByIdForUpdate是 MyBatis-Plus 里通过自己写 SQL 实现的行锁查询。课程表里同一行记录被事务锁住后第二个用户并发预约同一节课时会被阻塞等第一个事务提交后才能继续执行到这里才能基于最新的bookedCount做判断。这种方式在中小并发下完全够用做毕设或者企业内部系统都不会出问题。4. 微信小程序端从登录到预约完成的完整对接4.1 微信登录流程在本地的联调落地方式小程序的wx.login获取临时凭证code这个 code 只能使用一次有效期五分钟。真实开发中后端拿到 code 后要调用https://api.weixin.qq.com/sns/jscode2session接口会返回openid和session_key。项目里的application.yml中需要配置小程序的appid和secret这两项都在微信公众平台小程序后台获取测试阶段不要拿个人微信号去注册直接用测试号即可。public String wxLogin(String code) { String url https://api.weixin.qq.com/sns/jscode2session?appid appId secret appSecret js_code code grant_typeauthorization_code; RestTemplate restTemplate new RestTemplate(); String response restTemplate.getForObject(url, String.class); JSONObject jsonObject JSON.parseObject(response); if (jsonObject.getInteger(errcode) ! null) { throw new BusinessException(401, 微信登录失败 jsonObject.getString(errmsg)); } String openid jsonObject.getString(openid); // 查询或创建会员 Member member memberMapper.selectByOpenid(openid); if (member null) { // 新用户自动注册 member new Member(); member.setOpenid(openid); member.setNickname(微信用户 openid.substring(openid.length() - 8)); member.setRemainingClasses(5); memberMapper.insert(member); } // 签发JWT return JwtUtil.createToken(member.getId()); }这段代码里两个值得注意的点第一errcode为 0 时接口调用成功如果errcode是 40029 之类说明 code 无效或过期不要向用户抛出原始 JSON要转成友好提示第二新用户自动注册时初始剩余课时设为多少要看业务需求很多项目把体验课时写死在常量里评审老师会追问这个值的来源在数据库里加一张系统配置表管理会更规范。4.2 首页课程列表的渲染与倒计时状态刷新机制小程序首页通常是当日/近几日课程列表需要展示课程名称、时间、已预约人数和剩余名额。数据来源是后端接口/api/course/list?date2025-01-20返回课程列表 JSON。小程序端拿到数据后用wx:for渲染在onShow生命周期里重新拉取数据保证每次从小程序后台切回前台时数据已刷新。剩余名额的展示建议做成动态计算不能直接显示capacity - bookedCount因为开课前一小时被预约的订单还在等待队列里而 PostgreSQL/SQL Server 等数据库的实时性处理方式不同。更稳妥的做法是后端返回remaining capacity - bookedCount小程序端只负责展示。课程卡片上如果remaining为 0按钮要置灰并显示「约满」预约成功的用户显示「已预约」状态并且按钮不可再点击。上级菜单逻辑在index.vue里实现但必须是后端判断 前端置灰双保险前端只做体验优化真正的规则在后端。getCourseList() { const that this; wx.request({ url: app.globalData.baseUrl /api/course/list, data: { date: this.selectedDate }, header: { Authorization: Bearer wx.getStorageSync(token) }, success(res) { if (res.data.code 200) { that.setData({ courseList: res.data.data }); } else if (res.data.code 401) { // token过期跳转登录 wx.navigateTo({ url: /pages/login/login }); } } }); }wx.request的header中带Authorization字段是前后端联调的约定和JwtInterceptor中读取的 header 对应。小程序端每个页面请求前都要先确认token是否存在如果本地没有 token直接跳转登录页执行wx.login再回跳这个「守卫」逻辑在实际项目里会被抽成公共方法。4.3 预约表单的日期选择与跨天数据处理的边界情况预约页面的日期选择器通常使用微信小程序的原生组件picker的modedate。用户选择日期后前端把日期字符串传给后端。这里有一个很典型的坑如果用户选择的是「今天」而后端默认按服务器时区取日期当服务器与客户端相差一个时区时日期可能错一天。对于国内项目这个问题不严重但仍要统一约定格式。picker modedate value{{selectedDate}} bindchangeonDateChange view classdate-picker{{selectedDate}}/view /picker课程开始时间跨天的情况也需要明确约定晚间课程如果结束时间超过凌晨数据库中end_time存的是02:00:00而不是加一天的26:00:00查询时用日期加时间的组合条件判断。MySQL 中TIME类型不支持超过 24 小时的值所以不要在TIME字段上存储跨天时间应该在course_date上加一天表示结束日期SQL 设计时要考虑跨天情况。4.4 自定义底部导航栏与页面层级跳转需要注意的微信平台限制微信小程序的底部导航栏通过app.json的tabBar字段配置这个配置里的页面都必须是主包内的页面跳转层级不能超过十层。预约流程中如果用户从「课程详情」跳转到「确认预约」再跳转到「支付页面」页面栈会逐步增加这在某些场景下会超出微信的跳转限制。处理办法是预约成功后的结果页使用wx.redirectTo替代wx.navigateTo让当前页面在跳转路径中被替换掉。wx.navigateBack返回上一页时如果上方页面需要更新数据要在onShow里重新调用列表接口。很多开发者在实际开发中会比较困扰微信的返回策略与页面数据同步问题其实只需要理解两个原则redirectTo替换当前页、navigateTo压栈新页面、switchTab只能跳向 tabBar 配置的页面、navigateTo不能跳转 tabBar 页面。5. 数据库与接口联调从本地环境到部署上线的完整路径5.1 基于 MySQL Workbench 的数据库初始化和导入步骤拿到项目源码后第一件事是用 MySQL Workbench 打开数据库脚本并执行。打开 MySQL Workbench连接到本地 MySQL 实例在 Navigator 面板中右键创建新 Schema字符集选择utf8mb4排序规则选择utf8mb4_unicode_ci。然后File - Open SQL Script打开init.sql点击闪电图标执行全部语句。执行完后 Tables 列表下面会出现上一章设计的三张核心表。MySQL 8.0 以上版本默认使用caching_sha2_password认证插件而 SpringBoot 项目中pom.xml如果引入的是 5.x 版本的mysql-connector-java连接时会报Public Key Retrieval is not allowed错误。解决办法有两种第一种是升级驱动包到com.mysql:mysql-connector-j的 8.0.x 以上版本第二种是在 JDBC URL 中追加参数allowPublicKeyRetrievaltrueuseSSLfalse。我在实际部署时倾向直接升级驱动因为 MySQL 官方已经明确旧版连接器与 8.0 服务端的认证协议不兼容在源码里塞一个带安全风险的连接参数并不是好实践。5.2 application.yml 的配置解析与多环境切换方法SpringBoot 项目中的application-dev.yml和application-prod.yml分别对应开发与生产环境通过spring.profiles.active切换。健身房预约系统的配置项集中在数据源、MyBatis、微信小程序三块。server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/gym_db?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai username: root password: ${MYSQL_PASSWORD:123456} driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: mapper-locations: classpath:/mapper/*.xml configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl wx: miniapp: appid: ${WX_APPID:your_appid} secret: ${WX_SECRET:your_secret}${MYSQL_PASSWORD:123456}这个写法表示优先读取系统环境变量MYSQL_PASSWORD读取不到时回退到默认值。生产环境部署时密码不要写在 yml 里通过环境变量注入是基本要求。serverTimezoneAsia/Shanghai很重要如果缺失数据库连接时的日期时间会相差 8 小时。MyBatis-Plus 的map-underscore-to-camel-case开启后数据库的booked_count字段会自动映射到 Java 实体类的bookedCount属性。log-impl设为StdOutImpl是开发调试阶段的配置生产环境记得去掉否则每个 SQL 都会打到控制台磁盘日志增长非常快。Java 环境变量配置中要在系统变量里加入JAVA_HOME和PATH这些是 jdk 安装的基础操作源码包的部署说明书里一般会写不过真正部署在 Linux 上时建议用vim /etc/profile持久化配置。5.3 部署到 Linux 服务器的基本步骤用 java -jar 启动项目时的注意事项本地开发通常直接用 IDE 运行启动类生产环境会用 Maven 打包成 jar 文件部署。在项目根目录执行mvn clean package -DskipTests生成的 jar 文件在target/目录下。上传到服务器后有两种常见启动方式直接用nohup java -jar gym-system.jar app.log 21 后台运行或者写成 systemd 服务文件由系统托管。nohup和的组合可以保证 SSH 会话断开后进程继续运行但这种方式在服务器重启后不会自启。把 jar 包交给 systemd 托管之后日志管理用journalctl -u gym-system查看之前 Spring Boot 2.x 的 logback 日志切片配置依然有效。二选一即可在 demo 项目里用nohup最简单在正式系统里则一定要上 systemd。5.4 小程序端请求后端接口的合法域名配置流程后端部署完成后小程序端不能直接通过 IP 加端口请求接口。在微信公众平台后台的「开发管理 - 开发设置 - 服务器域名」中需要配置 request 合法域名。这个域名要求是 HTTPS并且在 ICP 备案后才能生效。本地联调时可以绕过这个限制在微信开发者工具的「详情 - 本地设置」里勾选「不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书」。// app.js 中的全局配置 globalData: { baseUrl: https://api.yourdomain.com // 生产环境域名 }如果是在本地开发真机调试把baseUrl改成电脑的局域网 IP 加上后端端口使用http://192.168.x.x:8080。但是真机预览会提示「不在以下 request 合法域名列表中」解决方法就是勾选开发者工具中的不校验合法域名。考试评审现场如果用真机演示记得提前打开这个选项否则接口全部请求失败体验会很糟糕。5.5 部署完成后的接口自测清单项目部署完成后不要急着演示先用 curl 测一遍核心接口。这里给出一份自测顺序清单能覆盖大部分问题场景。# 1. 登录接口 curl -X POST http://localhost:8080/api/auth/login \ -H Content-Type: application/json \ -d {code:test_code} # 2. 获取课程列表 curl http://localhost:8080/api/course/list?date2025-01-20 \ -H Authorization: Bearer token # 3. 创建预约 curl -X POST http://localhost:8080/api/appointment/create \ -H Content-Type: application/json \ -H Authorization: Bearer token \ -d {courseId:1} # 4. 取消预约 curl -X POST http://localhost:8080/api/appointment/cancel \ -H Content-Type: application/json \ -H Authorization: Bearer token \ -d {appointmentId:1}把上面命令返回的 JSON 结构和数据库实际数据对照着看预约创建后appointment表多一条记录course表的booked_count字段加一取消后订单状态字段变为 2人数减一。这种对照检查能最快发现事务是否生效如果booked_count没有变化而订单新增了多半是事务配置没生效检查Transactional是否加在了public方法上。6. 让预约系统更完整的三个进阶方向支付、压测与数据看板6.1 基于微信支付的订单体系扩展思路如果预约系统需要实现付费预约标题里的 MySQL 表结构需要增加一个支付流水表把支付单号和预约订单号做一一对应。微信支付 v3 接口要求请求头Authorization: WECHATPAY2-SHA256-RSA2048参数签名需要商户私钥开发调试阶段坑很多常见的问题包括回调 URL 必须是外网可访问的 HTTPS 地址、证书序列号不匹配、回调验签失败后平台会重试多次直到收到成功应答。本地开发调试微信支付时一般用内网穿透工具将本机端口映射到外网但这套平台方案的稳定性依赖穿透软件如果不想引入额外依赖可以直接在代码里把「确认预付单创建成功」这一步写死测试阶段跳过回调手动模拟支付成功事件来推动业务流程流转。毕设演示阶段演示支付回调功能时可以投屏手机上真实的微信支付界面讲解流程时把回调时序图讲清楚。6.2 用 JMeter 压测预约接口并发预约同一课程看数据一致性预约系统的核心考验是并发场景评审老师最爱问的是「如果 100 个人同时抢 10 个名额会发生什么」。用 JMeter 可以直观验证添加线程组设置为 100 个线程同时启动每个线程执行一次预约请求添加 HTTP 请求配置请求路径是/api/appointment/create参数中课程 ID 相同。运行结束看聚合报告预约成功数加上课程容量应该刚好等于报名人数上限不会出现 11 个人成功的情况。压测之前要确认数据库连接池上限够用SpringBoot 默认的 HikariCP 连接池大小是 1050 个并发时超过一半的线程会等待获取连接。可以在application.yml里调大连接池上限到 50。响应时间超过 200ms 未必是性能问题先看慢查询日志和 MySQL 的连接数是否打满再决定要不要加索引。给appointment表的member_id加索引是众多调优手段里收益最明显的操作。6.3 管理后台数据看板需要哪些统计 SQL如果源码包里有管理后台通常需要展示三项核心指标今日预约量、课程满员率、会员增长趋势。这三项对应三条 SQL 查询也能顺便检验数据库设计是否合理。-- 今日预约量 SELECT COUNT(*) FROM appointment WHERE create_time CURDATE() AND status 1; -- 课程满员率 SELECT COUNT(CASE WHEN booked_count capacity THEN 1 END) AS full_count, COUNT(*) AS total_count FROM course WHERE course_date CURDATE(); -- 近7日新增会员数 SELECT DATE(created_at) AS day, COUNT(*) AS cnt FROM member WHERE created_at DATE_SUB(CURDATE(), INTERVAL 7 DAY) GROUP BY DATE(created_at) ORDER BY day;三条 SQL 用到了CURDATE()、DATE_SUB和CASE WHEN在 MySQL 中都属于常用统计语法。DATE(created_at)对created_at字段应用函数会导致索引失效吗不会因为created_at的索引在范围查询时已经按日期过滤了数据量这里的分组计算量在本系统规模下可以忽略不计。数据看板的后端接口建议单独做一个StatsController不要混在业务接口里。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门