从0到99:健身房小程序开发日记(上)
随着移动互联网的普及和全民健身意识的提升,传统健身房的运营模式面临着数字化转型的需求。本文设计并实现了一款基于微信小程序和Spring Boot后端架构的健身房服务小程序。该系统旨在为会员提供便捷的课程预约、场地预订、资讯浏览及个人信息管理服务,同时为健身房管理者提供高效的内容维护、预约核销、用户管理及数据统计功能。系统采用前后端分离架构,前端使用微信小程序原生开发,后端基于Java Spring Boot框架,数据库选用MySQL 8.0+。测试结果表明,该系统有效提升了健身房的运营效率和会员的服务体验,实现了线上线下服务的闭环管理。 交互功能:支持详情查看、微信分享、关键词检索。 绑定微信账号,实现“一键登录”。 到店核销:生成核销二维码,管理员扫码确认到店。 数据库:MySQL 8.0+,存储业务数据。 小程序开发:微信开发者工具 数据访问层:通过MyBatis框架操作MySQL数据库,实现数据的持久化存储。可研
系统需求分析
栏目浏览模块
用户注册模块
服务预约模块
个人中心模块

总体设计
本系统采用前后端分离的开发模式,具体技术栈如下:
开发工具:
系统架构设计
数据库设计
字段名 类型 长度 约束 说明 id BIGINT 20 PK, AI 主键ID openid VARCHAR 64 NOT NULL, UNIQUE 微信OpenID name VARCHAR 50 姓名 age INT 3 年龄 phone VARCHAR 20 联系电话 vehicle_info VARCHAR 100 车辆情况 fitness_goal VARCHAR 255 健身目标 create_time DATETIME 注册时间 status TINYINT 1 DEFAULT 1 状态(1正常 0禁用) 字段名 类型 长度 约束 说明 id BIGINT 20 PK, AI 主键ID name VARCHAR 100 NOT NULL 项目名称 type TINYINT 1 NOT NULL 类型(1私教 2团课 3场地) description TEXT 项目描述 max_capacity INT 最大容纳人数 sort_order INT DEFAULT 0 排序权重 is_available TINYINT 1 DEFAULT 1 是否可用 rule_desc VARCHAR 500 预约规则说明 字段名 类型 长度 约束 说明 id BIGINT 20 PK, AI 主键ID user_id BIGINT 20 FK 用户ID project_id BIGINT 20 FK 项目ID reserve_date DATE NOT NULL 预约日期 time_slot VARCHAR 50 NOT NULL 预约时段 verify_code VARCHAR 64 UNIQUE 核销二维码字符串 status TINYINT 1 DEFAULT 0 状态(0待核销 1已完成 2已取消) create_time DATETIME 创建时间 verify_time DATETIME 核销时间 字段名 类型 长度 约束 说明 id BIGINT 20 PK, AI 主键ID category TINYINT 1 NOT NULL 分类(1动态 2干货 3饮食 4荣誉) title VARCHAR 200 NOT NULL 标题 content LONGTEXT 正文内容(支持HTML) cover_image VARCHAR 255 封面图URL view_count INT DEFAULT 0 浏览量 publish_time DATETIME 发布时间 字段名 类型 长度 约束 说明 id BIGINT 20 PK, AI 主键ID username VARCHAR 50 NOT NULL, UNIQUE 用户名 password VARCHAR 100 NOT NULL 加密密码 role TINYINT 1 NOT NULL 角色(1超级管理员 2普通管理员 3核销员) status TINYINT 1 DEFAULT 1 状态 last_login DATETIME 最后登录时间 核心代码
@RestController
@RequestMapping("/api/reservation")
public class ReservationController {
@Autowired
private ReservationService reservationService;
@PostMapping("/create")
public Result create(@RequestBody ReservationDTO dto, HttpServletRequest request) {
// 从Session或Token中获取当前用户ID
Long userId = UserContext.getCurrentUserId(request);
return reservationService.createReservation(userId, dto.getProjectId(), dto.getDate(), dto.getTimeSlot());
}
@PostMapping("/verify")
public Result verify(@RequestParam String code, HttpServletRequest request) {
// 获取当前管理员ID
Long adminId = AdminContext.getCurrentAdminId(request);
return reservationService.verifyReservation(code, adminId);
}
}
@Service
public class ReservationService {
@Autowired
private ReservationMapper reservationMapper;
@Autowired
private ProjectMapper projectMapper;
/**
* 创建预约
*/
@Transactional(rollbackFor = Exception.class)
public Result createReservation(Long userId, Long projectId, String date, String timeSlot) {
// 1. 检查项目是否存在及可用
Project project = projectMapper.selectById(projectId);
if (project == null || project.getIsAvailable() == 0) {
return Result.error("该项目不可预约");
}
// 2. 检查该时段剩余名额
int bookedCount = reservationMapper.countByProjectAndSlot(projectId, date, timeSlot);
if (bookedCount >= project.getMaxCapacity()) {
return Result.error("该时段名额已满");
}
// 3. 生成核销码
String verifyCode = UUID.randomUUID().toString().replace("-", "");
// 4. 插入预约记录
Reservation reservation = new Reservation();
reservation.setUserId(userId);
reservation.setProjectId(projectId);
reservation.setReserveDate(DateUtil.parse(date));
reservation.setTimeSlot(timeSlot);
reservation.setVerifyCode(verifyCode);
reservation.setStatus(0); // 待核销
reservationMapper.insert(reservation);
return Result.success("预约成功", verifyCode);
}
/**
* 扫码核销
*/
public Result verifyReservation(String verifyCode, Long adminId) {
Reservation reservation = reservationMapper.selectByVerifyCode(verifyCode);
if (reservation == null) {
return Result.error("无效的核销码");
}
if (reservation.getStatus() != 0) {
return Result.error("该预约已" + (reservation.getStatus() == 1 ? "完成" : "取消"));
}
// 更新状态为已完成
reservation.setStatus(1);
reservation.setVerifyTime(new Date());
reservationMapper.updateById(reservation);
return Result.success("核销成功");
}
}UI设计






后台管理系统设计









Git代码