首页 / 资讯中心 / 文章详情

基于微信小程序的健身房预约平台:SpringBoot后端设计与实现

基于微信小程序的健身房预约平台:SpringBoot后端设计与实现 ★ FEATURED ARTICLE
最近不少同学在选题时都会考虑微信小程序相关的系统健身房预约平台算是出场率很高的一类。这个题目看起来不复杂但真正动手以后你会发现它同时踩到了小程序登录、后端接口设计、数据库并发控制、前端状态同步这几条线任何一个环节没理顺都会在联调阶段反复折腾。这篇文章就着“基于微信小程序的健身房预约平台 SpringBoot 后端”这个课设/毕设题目把从需求拆解到落地的完整链路讲一遍。适合正在选型、写文档、或者已经在开发中卡住的同学尤其是有答辩压力、想把项目讲出亮点的人。我不会把官方文档抄一遍而是把真正编写代码时容易忽略的点以及我自己调试时踩过的坑都摊开来说。项目本身的代码量不算大但每一个模块都有值得展开的技术细节。下面直接进正文。1. 项目整体设计与需求拆解1.1 核心角色与功能用户、教练、管理员健身房预约平台往小了说是一个课表 预约记录往大了说则涉及会员管理、教练管理、课程排期、统计报表。做课设和毕设时最忌讳一上来就堆功能最后哪个都没做透。我建议把角色收敛成三个普通用户微信小程序端、教练、管理员管理后台端。用户端需要完成的是微信登录、浏览课程、按日期筛选、预约课程、取消预约、查看自己的预约记录。教练端的核心是维护可预约的课程信息比如课程名称、上课时间、人数上限。管理员端要能管理用户、教练、课程、预约记录并且能看到基本的预约统计。这三个角色其实对应了三套页面和一组 RESTful 接口。类目不要贪多把这几个模块做完整文档和答辩就够撑起来了。有些同学会额外加签到、评价、私教购买这些可以作为扩展点写进“未来展望”不建议纳入第一版开发。因为每加一个功能数据库表、接口、小程序页面、测试用例都会成倍增加。等主体跑通了再挑一两个扩展来做也不迟。1.2 核心业务流一次预约从开始到完成这条链路是项目的灵魂也应该是文档里最着重画出来的部分。在小程序端用户打开页面后调用微信登录后端根据 wx.login 返回的 code 换取 openid完成注册或登录然后签发一个 token 返回。前端拿着 token 去请求课程列表选择日期后看到当天可预约的课程点击预约按钮后端校验课程状态、人数余量、是否已经预约过全部通过后把预约记录写入数据库并把该课程的已预约人数加一。用户之后可以在“我的预约”里看到这一条记录状态是“已预约”。如果临时有事可以选择取消后端将已预约人数减一把预约状态改成“已取消”。管理员在后台可以看到所有课程和预约记录也可以手动关闭某节课程的预约。这套流程串起来以后系统的骨架就立住了。要注意的是预约和取消这两个动作不是简单的 insert / delete它们都涉及到人数增减和多用户同时操作的并发问题后面我会专门展开。1.3 功能清单与模块优先级这里给一个可以直接抄作业的功能清单按优先级排序。模块用户端管理端优先级登录认证微信登录、token 鉴权管理员账号密码登录P0课程浏览按日期查看课程、查看余量课程增删改查、上下架P0预约管理预约、取消、我的预约列表预约记录查询、状态筛选P0用户管理查看个人资料会员列表、状态管理P1统计看板无今日预约量、热门课程 TopNP1扩展功能签到、评价、私教约课数据导出P2优先级 P0 是第一版必须完成的P1 看时间和精力P2 完全可以放在文档里作为“系统改进方向”不需要真的实现到代码里。这样功能边界清晰开发节奏也容易控制。写完这一部分需求文档和数据库设计就都有了依据。2. 技术选型与关键方案说明2.1 后端为什么选 SpringBoot MyBatis-Plus很多刚做毕设的同学会纠结用 SSM 还是 SpringBoot用 JPA 还是 MyBatis我的建议是 SpringBoot 2.x MyBatis-Plus没有悬念。SpringBoot 内置了 Tomcat省去配置一堆 XML 的麻烦启动一个 main 方法就能跑起来。SpringBoot 3.x 虽然已经发布很久但很多教程和第三方适配还停留在 2.x课设阶段没必要给自己挖坑稳定压倒一切。我用的是 SpringBoot 2.7配 JDK 1.8MySQL 5.7 或 8.0 都可以。MyBatis-Plus 的价值在于单表 CRUD 基本不用写 SQL。选课程、插入预约记录、更新用户昵称这些操作只要继承一个 BaseMapper代码量直线下降。它还内置了分页插件后台管理列表的分页查询可以直接用。对于课设来说MyBatis-Plus 能让你把精力放到业务逻辑而不是重复的 SQL 上而且答辩时说“使用了 MyBatis-Plus 简化数据访问层”也算一个技术亮点。唯一要注意的是多表关联查询还是需要自己写 SQL不要所有查询都靠 QueryWrapper 硬拼。2.2 小程序端原生开发还是用框架小程序端我推荐直接用微信官方原生开发不要引入 uni-app 或者 Taro。原因很简单原生小程序本身就是基于页面、组件、路径路由的一套开发模式代码结构清晰官方调试工具成熟遇到问题搜到的解决方案也最多。虽然 uni-app 能一套代码多端发布但课设只需要一个微信小程序完全没有必要增加编译链的复杂度。至于 UI 组件库Vant Weapp 可以用但也不是必需。如果你对 CSS 不太熟Vant 确实能快速做出漂亮的按钮和表单但如果你希望项目足够“独立”手写少量样式反而更可控出问题也容易排查。我在这个项目里选择的是原生 少量自定义公共样式核心页面控制在 8 个以内开发体验其实很舒服。2.3 为什么不用微信云开发要自己搭后端这是答辩时很常见的一个问题。云开发确实能省掉服务器和域名配置数据库直接在小程序端读写但“基于 SpringBoot 的健身房预约平台”这个题目已经限定了后端技术栈。自己搭后端的价值在于一是能完整体现后端接口设计、权限控制、事务处理这些能力二是方便将来扩展一个独立的管理后台三是课设评分通常会看后端代码的深度云开发很难写出多层业务逻辑也经不起老师追问。当然自建后端的代价是必须要会处理跨域、部署、外部接口调用这些问题。微信小程序的 request 请求只能走 HTTPS 域名本地调试时需要在开发者工具里勾选“不校验合法域名”。这些细节我会在部署部分详细说提前有心理预期就不会慌。2.4 数据库设计核心表结构与字段含义数据库是整个项目的地基。我设计了六张核心表用户表、管理员表、教练表、课程表、预约表、公告表可选。其中 trainer 和 course 可以合并但拆开会更符合业务直觉。重点看两张表course 和 appointment。课程表我采用“日期 时段”的粒度来存也就是每一节具体的课比如“2026-05-20 上午 10:00 的动感单车课”就是一条记录。字段包括 course_id、coach_id、course_name、course_date、start_time、end_time、max_count、booked_count、status。这里的 booked_count 是冗余字段用来快速展示剩余名额也方便在预约时做原子更新。status 表示“可预约/已满/已取消”。预约表是业务核心字段包括 appointment_id、course_id、user_id、appointment_time、status。status 用整型表示1 为已预约2 为已取消3 为已完成。为了避免一个人重复预约同一节课我在 course_id user_id 上加了一个唯一索引这个索引在并发控制里意义很大后面会再次提到。用户表里需要存 openid 和 unionidopenid 用 varchar(64)nickname、avatar 可以允许为空。整体设计做到了第三范式够用又故意保留 booked_count 这个冗余字段来提升查询性能在文档里解释清楚就是得分点。3. 后端核心接口实现细节3.1 微信登录从 code 到 openid 再到自定义 Token小程序端通过 wx.login 拿到的 code 是一次性的临时凭证后端需要拿着这个 code 去微信平台提供的接口换 openid 和 session_key。这里有几个容易出错的地方第一code 只能用一次用完再换就会报 invalid code第二小程序的 appid 和 secret 属于后端配置绝不能写在小程序代码里第三session_key 不需要自己存取对课设来说我们只关心 openid。后端实现大致是这样的。先定义一个 LoginController接收前端传过来的 code然后用 HttpClient 或 RestTemplate 请求微信接口解析返回的 openid。拿到 openid 后去 user 表查记录查不到就自动注册一个新用户。最后用 JWT 生成一个 token把 userId 和 openid 放进去返回给前端。注意这里要引入一个拦截器除了登录接口和公开接口外其他接口都必须校验请求头里的 Authorization。下面是我习惯的代码骨架RestController RequestMapping(/api/user) public class UserController { PostMapping(/login) public Result login(RequestBody LoginDTO dto) { // 1. 用 code 请求微信接口获得 openid String openid wechatService.getOpenid(dto.getCode()); // 2. 查库或注册 User user userService.findOrCreate(openid); // 3. 生成 token String token jwtUtil.generateToken(user.getId()); return Result.success(token); } }实现 getOpenid 时通常会遇到网络请求返回 JSON 解析的问题。用 Spring 的 RestTemplate 就能搞定但要注意把 appid 和 secret 放在 application.yml 里不要写死在代码。答辩时老师可能会问“怎么保证用户身份安全”你就答JWT 无状态鉴权 拦截器统一校验同时 openid 不直接返回给前端只作为服务端标识这样就安全了。3.2 课程列表与日期筛选课程列表接口是访问量最高的接口设计成 GET /api/course/list?date2026-05-20。后端根据日期查询当天 status 为可预约的课程按开始时间排序并且把剩余名额max_count - booked_count返回。可以用 MyBatis-Plus 的 LambdaQueryWrapper 来做条件查询简单直接。这里有一个小经验course_date 最好用字符串类型存储格式 yyyy-MM-dd不要用 datetime。因为前端 date 组件传过来的就是字符串后端处理起来不用做时区转换模糊查询也方便。不要觉得存字符串不专业很多真实项目在日期这类固定格式字段上也会用字符串查询更快代码更少。课程返回对象里除了课程名称和教练姓名还要带上剩余可预约人数这样小程序首页可以直接展示不用二次计算。还需要处理一个状态逻辑当前时间已经超过课程开始时间就不能再预约了。这种判断放在数据库 SQL 里比较麻烦我建议在接口查询时就过滤掉 course_date 小于当天日期的课程。对于当天但开始时间早于当前时间的可以交给前端判断也可以后端额外返回一个 is_expired 字段前端根据这个字段禁用预约按钮。3.3 预约与取消预约如何防止“超卖”这是全项目技术含量最高的地方也是答辩提问的高频区。先说明需求多个用户同时预约同一节只剩最后一个名额的课程系统只能让一个人成功。如果用最简单的“先查余量够再插入”的写法极大概率在并发测试下出现两个人同时看到余量为 1然后都插入成功最终超卖。解决思路是使用数据库的原子更新来保护余量。插入预约记录前先执行这样一条 SQLint rows courseService.update( new LambdaUpdateWrapperCourse() .setSql(booked_count booked_count 1) .eq(Course::getId, courseId) .eq(Course::getStatus, 1) .lt(Course::getBookedCount, Course::getMaxCount) );这行代码的意思是只有满足 booked_count 小于 max_count 时才执行 1 操作并返回受影响行数。如果 rows 等于 0说明已经满了或者课程状态不对直接返回“预约失败”。如果 rows 等于 1说明余量被成功扣减然后再去插入预约记录。这两步放在同一个事务里就能保证不会超卖。取消预约是反过来执行 update 时用 setSql(booked_count booked_count - 1)同时加一个条件 booked_count 0防止出现负数。然后修改预约记录的状态为已取消。还要注意重复取消的问题更新预约记录时带上 status 1 的条件如果更新影响行数为 0就说明这条记录已经被取消过直接提示“该预约已取消”。这段逻辑你完全可以直接写进 Service 类里然后加上 Transactional 注解。事务一旦抛出异常数据库会自动回滚到之前的状态不会出现“余量扣了但预约记录没生成”这种尴尬数据。3.4 管理后台接口统计与课程管理管理后台的接口可以单独放在 /admin 路径下。管理员登录用账号密码生成一个独立的 admin token。课程管理接口包括添加课程、编辑课程、删除或下架课程、分页查询课程列表。删除课程时要注意如果已经有用户预约了不应该物理删除而是把 status 改成 2已取消这样预约过的用户端也能看到状态变化数据更真实。统计接口方面最有用的就是今日预约数和热门课程排行。今日预约数可以用一条 group by 查出 appointment 表里 appointment_time 在当天的记录数。热门课程排行则可以用 group by course_id 加上 count 排序。也可以顺便查一下每个教练的预约量方便后台做绩效。图表展示我推荐在小程序后台管理端用 ECharts或者干脆用简单的柱状图原生组件渲染。后端只需要提供聚合好的数据列表前端负责画图责任单一文档里也容易写。4. 小程序端页面与交互实现4.1 登录流程静默登录与头像昵称的坑微信小程序的登录坑特别多尤其是从基础库 2.27.1 开始官方收紧了 getUserProfile 获取头像昵称的能力。以往那种点击登录弹窗然后获取信息的方式已经废弃了。现在更推荐的做法是页面加载后直接调 wx.login 获取 code把 code 传给后端完成登录后端返回 token。头像昵称可以在用户进入“个人中心”后通过微信提供的“头像昵称填写能力”来维护或者让用户手动上传头像和填写昵称。实际开发时很多同学会遇到“后端登录成功但前端拿不到用户信息”的情况其实就是因为没有区分开“登录态”和“用户资料”。登录态只关心 openid资料是用户自己补充的。我在这个项目里简单地让用户登录后默认显示“微信用户”并提供一个编辑资料页面用户自己设置昵称和头像然后调用后端接口更新 user 表。这样既规避了接口限制又不影响整体流程。4.2 首页课程列表日期选择与余量展示首页是整个小程序最复杂的页面因为要处理多个异步状态加载课程列表、日期切换、下拉刷新。我的建议是页面结构拆成三块顶部日期导航、课程列表、底部占位。日期导航用微信原生 picker 选择日期也可以自己写一个横向滚动的连续日期条后者更常见也更好看。选择日期后触发 setData 更新 currentDate然后调用课程列表接口。请求接口时需要带上 token。我封装了一个 request.js统一拼接 baseUrl统一在请求头里加 Authorization也统一处理 401 跳转。小程序不能用 axios只能用 wx.request所以封装一个 Promise 风格的请求模块非常有必要。课程卡片上要展示课程名称、教练、时间、剩余名额并显示预约按钮。剩余名额建议用 highlight 样式突出显示如果余量为 0按钮置灰。这里要注意不要用模板字符串拼 CSS class 的时候出错状态判断最好是显式写清楚。4.3 预约操作与防重复提交当用户点击“预约”按钮时前端要立刻进入 loading 状态并且禁用按钮防止用户连点造成重复请求。这个细节很多同学会忽略但一旦后端没有做幂等控制连续点了两次就可能出现两条预约记录。我之前就遇到过这种尴尬后来前端加了 disabled后端也做了唯一索引兜底才彻底解决。预约成功后的反馈很重要。不要只是弹一个 toast 就完事最好在接口返回后回调 setData 把当前课程的余量减一并且把按钮状态改成“已预约”。如果接口返回失败也要把按钮恢复成可点击状态并提示失败原因。小程序的 setData 是异步的更新完数据后需要立刻刷新列表建议在回调里重新拉取课程详情或整个列表跟服务端保持最新状态一致。4.4 我的预约列表与状态管理“我的预约”页面需要按用户维度查询预约记录并且展示课程时间、预约时间和状态。状态建议用不同的标签颜色区分已预约是绿色已取消是灰色已完成是蓝色。可以把这个页面做成 tab 切换全部、待上课、已结束。为了减少后端接口维度通常前端传一个 status 参数后端在 SQL 里做筛选。待上课的预约要允许用户取消。取消时同样要弹确认框确定后调用取消接口成功后再刷新页面。这里有一个用户体验上的点如果课程已经开始或者已经结束就不能再取消后端接口同样要做校验不能只靠前端隐藏按钮。另外取消接口返回后之前首页对应课程的余量也会变化所以从“我的预约”返回首页时最好在 onShow 里重新刷新课程列表避免数据不一致。5. 部署运行与踩坑实录5.1 本地联调完整步骤这里按照一套干净环境来写前提是你的电脑已经装了 JDK、MySQL、微信开发者工具。第一步创建数据库名字叫 gym_db然后执行项目里提供的 gym.sql它会自动建表并插入几条测试数据。第二步打开后端项目修改 application.yml把数据库账号密码改成你自己的同时填上小程序的 appid 和 secret。第三步直接运行启动类看到 Tomcat started 字样就代表后端起来了。第四步打开微信开发者工具导入小程序前端目录在 app.js 文件里把 baseUrl 改成 http://localhost:8080。如果你用的是真机预览localhost 会失效要把地址改为电脑局域网 IP比如 http://192.168.x.x:8080。同时要勾选开发者工具右上角“详情”里的“不校验合法域名”否则请求会被拦截。第五步编译运行小程序点登录看后端控制台是否打印请求日志然后正常走一遍预约流程。只要这五步走通整套系统就算本地联调成功了。5.2 高频报错与排查速查表我把做这个项目过程中最常遇到的几个问题整理成一个速查表方便你对照排查。现象可能原因解决办法登录时后端报“invalid code”wx.login 的 code 只能用一次可能是重复发送重新调用 wx.login不要使用缓存的 code小程序请求 401请求头没有带 token或 token 过期在 request.js 里统一添加 Authorization拦截器里处理过期跳转课程列表中文乱码数据库连接没有指定 UTF-8在 jdbc url 后面加 characterEncodingutf8后端启动报端口被占用8080 端口被其他程序占用改 application.yml 里的 server.port或释放端口预约永远提示“失败”课程 status 不是 1或已满或已经预约过检查数据库记录确认唯一索引是否生效小程序页面白屏baseUrl 配置错误或后端未启动查看 console 报错确认网络请求状态找不到 Mapper 接口方法Mapper 接口和 XML 文件没有对应使用 MyBatis-Plus 时尽量用 baseMapper 自带方法避免额外 XML这里重点说一个容易踩的坑由于预约接口加了唯一索引当你测试时预约成功一次后再手工去数据库把预约记录删除但课程表的 booked_count 没有同步减下去之后你再预约同一节课会一直提示“人数已满”。这种脏数据问题在开发阶段很常见。我的建议是不要随便动数据库表数据测试取消功能时一定要通过页面操作保证前后端逻辑完整执行。如果真改了数据库就用 SQL 把 booked_count 手动重置一下。5.3 课程设计/毕业论文的文档写作建议项目跑通只是第一步文档在评分中的占比非常高。万字文档不是流水账而是要有清晰的逻辑链。建议按照“摘要、需求分析、系统设计、数据库设计、系统实现、系统测试、总结”这个结构写其中系统设计部分要重点画总体架构图和功能结构图。这些图不需要多么专业用 Visio、ProcessOn 或者 draw.io 画清楚即可注意图中每个模块都要和代码对应上。在“系统实现”部分不要所有接口平均用力要挑出两到三个有亮点的模块详细写比如微信登录流程、并发预约处理、统计报表。特别是并发预约处理一定要写清楚为什么使用数据库的原子更新留下测试过程数据比如模拟两个用户同时预约同一节课的结果这会成为你答辩时最有力的“技术证据”。测试部分除了功能测试还可以加一点点压力测试的描述用浏览器开发者工具模拟并发效果哪怕只是粗略的记录也比没有强很多。文档里还可以加一节“遇到的问题与解决”把开发过程中真实的坑写进去。不要觉得写问题会显得水平低相反有经验的老师最喜欢看这个它说明你真的动手做了不是下载别人的代码应付了事。最后再分享一点个人体会这个项目最容易被答辩老师追问的点就是并发预约怎么处理。如果你能把“update 条件防超卖”讲清楚再顺带说一下唯一索引兜底基本就能和那些只会增删改查的项目拉开差距。我在实际写代码时还有一个习惯所有前端请求都走了统一的 request 封装所有后端接口都返回统一的 Result 结构包括 code、message、data。虽然前期多花了十几分钟但联调阶段几乎没为参数格式扯皮过非常建议你也这样规范起来。这个小项目做完你会发现 SpringBoot 接口设计、小程序生命周期、数据库事务都有了实感后续再做其他系统思路会顺很多。
阅读完成 · 觉得有帮助?
咨询建站