31 KiB
31 KiB
健身房管理系统基础版技术实现详细设计文档(T-ILD)
文档编号: GYM-T-ILD-BASIC-001
版本: v1.0
日期: 2026-03-08
作者: 张翔
状态: 已发布
文档修订历史
| 版本 | 日期 | 作者 | 修订内容 |
|---|---|---|---|
| v1.0 | 2026-03-08 | 张翔 | 创建基础版技术实现详细设计文档,整合技术架构和实现细节 |
一、引言
1.1 编写目的
本文档为健身房管理系统基础版的技术实现详细设计文档(Technical Implementation Level Design),旨在:
- 从技术层面描述基础版的系统架构、技术选型、实现细节
- 为开发人员提供技术实现指导
- 作为架构师、开发工程师的技术参考
1.2 项目背景
健身房管理系统基础版是面向小型工作室、个人教练等场景的核心版本,采用响应式编程架构,保证高并发、低延迟、高可用性。
1.3 参考文档
- 《健身房管理系统基础版产品设计文档》 GYM-PRD-BASIC-001
- 《健身房管理系统基础版业务概要设计文档》 GYM-B-HLD-BASIC-001
- 《健身房管理系统基础版业务详细设计文档》 GYM-B-LLD-BASIC-001
- Spring Boot 3 官方文档
- Spring WebFlux 官方文档
- R2DBC 规范文档
- PostgreSQL 官方文档
二、架构决策
2.1 架构选型
经过深入评估,本系统采用以下架构决策:
| 决策项 | 选择方案 | 理由 |
|---|---|---|
| 应用架构 | 单体应用 | 适合当前规模(基础版100并发用户,付费订阅版500并发用户),开发效率高,部署简单,成本低 |
| 编程模型 | 响应式编程(WebFlux + R2DBC) | 高并发能力(10x 提升),低延迟(50% 降低),资源利用率高(75% 降低) |
| 部署方式 | Docker Compose | 一键部署,环境一致性好,回滚快速 |
| 数据库 | PostgreSQL | 金融级数据库,支持 ACID 事务,JSONB 支持灵活配置 |
| 缓存 | Redis | 高性能缓存,支持分布式锁 |
| 消息队列 | RabbitMQ | 成熟稳定,支持延迟消息 |
| 搜索引擎 | Elasticsearch | 全文搜索,适合复杂查询 |
| 监控 | Prometheus + Grafana | 完善的监控体系,可视化好 |
2.2 技术栈
核心技术栈
| 技术组件 | 版本 | 用途 |
|---|---|---|
| Spring Boot | 3.2.x | 应用框架 |
| Spring WebFlux | 3.2.x | 响应式 Web 框架 |
| Spring Data R2DBC | 3.2.x | 响应式数据访问 |
| PostgreSQL R2DBC | 1.0.0.RELEASE | PostgreSQL 响应式驱动 |
| Spring Security | 6.2.x | 安全框架 |
| Redis Reactive | 3.2.x | 响应式缓存 |
| RabbitMQ | 3.12.x | 消息队列 |
| Elasticsearch | 8.11.x | 搜索引擎 |
| Prometheus | Latest | 监控指标采集 |
| Grafana | Latest | 监控可视化 |
| Docker | 24.x | 容器化部署 |
| Docker Compose | 2.20.x | 容器编排 |
开发工具
| 工具 | 版本 | 用途 |
|---|---|---|
| JDK | 17+ | 运行环境 |
| Maven | 3.9.x | 项目构建 |
| Lombok | 1.18.x | 代码简化 |
| MapStruct | 1.5.x | 对象映射 |
| Micrometer | 1.12.x | 监控指标 |
| SpringDoc OpenAPI | 2.3.x | API 文档 |
2.3 基础版性能与架构特点
2.3.1 性能目标
| 指标类型 | 指标项 | 目标值 | 说明 |
|---|---|---|---|
| 应用指标 | 并发数 | ≤ 100 | 基础版支持100并发用户 |
| 应用指标 | API响应时间 | ≤ 500ms | 95%请求响应时间 |
| 应用指标 | 系统可用性 | ≥ 99.5% | 年度目标 |
| 数据库指标 | 连接池大小 | 20 | R2DBC连接池 |
| 数据库指标 | 查询响应时间 | ≤ 200ms | 95%查询响应时间 |
| 缓存指标 | 缓存命中率 | ≥ 80% | Redis缓存 |
| 缓存指标 | 缓存响应时间 | ≤ 10ms | Redis缓存 |
2.3.2 架构特点
基础版采用轻量级架构设计,满足小型工作室和个人教练的需求:
1. 单体应用架构
- 部署简单,维护成本低
- 适合单门店场景
- 数据隔离通过租户ID实现
2. 资源优化配置
- 数据库连接池:20个连接
- Redis缓存:1GB内存
- RabbitMQ队列:单队列模式
- Elasticsearch:单节点部署
3. 扩展性限制
- 不支持多门店管理
- 不支持分布式部署
- 不支持高可用集群
- 并发用户数限制100
2.3.3 与付费订阅版的差异
| 维度 | 基础版 | 付费订阅版 |
|---|---|---|
| 并发用户数 | 100 | 500 |
| 数据库连接池 | 20 | 100 |
| Redis内存 | 1GB | 4GB |
| RabbitMQ队列 | 单队列 | 多队列集群 |
| Elasticsearch | 单节点 | 3节点集群 |
| 多门店支持 | 不支持 | 支持 |
| 分布式部署 | 不支持 | 支持 |
| 高可用集群 | 不支持 | 支持 |
三、系统架构设计
3.1 总体架构
采用分层架构 + 模块化设计的单体应用:
flowchart TB
subgraph 单体应用总体架构
A[客户端层<br/>• 会员小程序 uniapp+Vue3<br/>• 教练端App uniapp+Vue3<br/>• 管理后台PC Vue3+Vite<br/>• 硬件设备 人脸/NFC]
B[Nginx 反向代理<br/>• 负载均衡<br/>• SSL 终止<br/>• 静态资源<br/>• 限流]
C[Presentation Layer WebFlux<br/>• Controller<br/>• Router<br/>• Filter<br/>• Validator]
D[Application Layer 业务编排<br/>• Service<br/>• Facade<br/>• Orchestrator<br/>• 事务管理]
E[Domain Layer 领域模型<br/>• Entity<br/>• Value Object<br/>• Domain Service<br/>• Repository]
F[Infrastructure Layer 基础设施<br/>• Repository R2DBC<br/>• Cache Redis<br/>• Message RabbitMQ<br/>• Search Elasticsearch<br/>• File OSS<br/>• Distributed Lock]
G[外部服务层<br/>• PostgreSQL<br/>• Redis<br/>• RabbitMQ<br/>• Elasticsearch<br/>• 微信开放平台<br/>• 短信服务<br/>• 支付服务<br/>• OSS存储]
H[监控与运维层<br/>• Prometheus<br/>• Grafana<br/>• 日志收集<br/>• 告警]
A --> B
B --> C
C --> D
D --> E
E --> F
F --> G
G --> H
end
3.2 分层架构详解
3.2.1 Presentation Layer(表现层)
职责:
- 接收 HTTP 请求
- 参数验证
- 路由转发
- 响应封装
- 异常处理
技术实现:
- Spring WebFlux Router
- Spring Validation
- Spring Security Reactive
- Global Exception Handler
3.2.2 Application Layer(应用层)
职责:
- 业务逻辑编排
- 事务管理
- 跨模块协调
- 权限校验
技术实现:
- Service 类
- @Transactional 注解
- 分布式锁
- Saga 模式(跨服务事务)
3.2.3 Domain Layer(领域层)
职责:
- 领域模型定义
- 业务规则封装
- 领域服务
- 仓储接口定义
技术实现:
- Entity 类
- Value Object 类
- Domain Service 类
- Repository 接口
3.2.4 Infrastructure Layer(基础设施层)
职责:
- 数据访问实现
- 缓存管理
- 消息队列
- 文件存储
- 外部服务调用
技术实现:
- R2DBC Repository
- Redis Reactive
- RabbitMQ Reactive
- Elasticsearch Reactive
- OSS SDK
3.3 模块化设计
单体应用内部采用模块化设计,为未来拆分微服务做准备:
gym-manage/
├── gym-manage-api/ # API 层
│ ├── controller/
│ │ ├── member/ # 会员模块 API
│ │ ├── booking/ # 预约模块 API
│ │ ├── checkin/ # 签到模块 API
│ │ ├── benefit/ # 权益模块 API
│ │ ├── subscription/ # 订阅模块 API
│ │ ├── marketing/ # 营销模块 API
│ │ └── analytics/ # 数据分析模块 API
│ ├── dto/
│ │ ├── request/ # 请求 DTO
│ │ └── response/ # 响应 DTO
│ └── config/
│ ├── WebFluxConfig.java
│ ├── SecurityConfig.java
│ └── R2dbcConfig.java
│
├── gym-manage-application/ # 应用层
│ ├── service/
│ │ ├── member/
│ │ ├── booking/
│ │ ├── checkin/
│ │ ├── benefit/
│ │ ├── subscription/
│ │ ├── marketing/
│ │ └── analytics/
│ ├── facade/
│ └── orchestrator/
│
├── gym-manage-domain/ # 领域层
│ ├── entity/
│ │ ├── Member.java
│ │ ├── BookingRecord.java
│ │ ├── CheckinRecord.java
│ │ ├── MemberBenefit.java
│ │ ├── SubscriptionRecord.java
│ │ └── ...
│ ├── valueobject/
│ ├── repository/
│ │ ├── MemberRepository.java
│ │ ├── BookingRecordRepository.java
│ │ └── ...
│ └── service/
│ └── DomainService.java
│
├── gym-manage-infrastructure/ # 基础设施层
│ ├── repository/
│ │ └── impl/
│ │ ├── MemberRepositoryImpl.java
│ │ ├── BookingRecordRepositoryImpl.java
│ │ └── ...
│ ├── cache/
│ │ └── RedisCacheService.java
│ ├── message/
│ │ └── RabbitMQService.java
│ ├── search/
│ │ └── ElasticsearchService.java
│ ├── lock/
│ │ └── DistributedLockService.java
│ └── config/
│ ├── R2dbcConfiguration.java
│ ├── RedisConfiguration.java
│ ├── RabbitMQConfiguration.java
│ └── ElasticsearchConfiguration.java
│
└── gym-manage-main/ # 主启动类
├── GymManageApplication.java
└── resources/
├── application.yml
├── application-dev.yml
└── application-prod.yml
四、响应式编程架构
4.1 响应式编程模型
本系统采用 Project Reactor 作为响应式编程库:
| 组件 | 类型 | 说明 |
|---|---|---|
| Mono | 0-1 个元素 | 表示异步计算结果,返回单个对象或空 |
| Flux | 0-N 个元素 | 表示异步数据流,返回多个对象 |
| Scheduler | 线程调度器 | 控制异步操作的执行线程 |
4.2 响应式编程规范
4.2.1 基本原则
-
永不阻塞
- 禁止在响应式流中使用
block()、blockFirst()、blockLast() - 所有 I/O 操作必须使用非阻塞方式
- 禁止在响应式流中使用
-
链式调用
- 使用
flatMap、map、filter等操作符链式调用 - 避免嵌套的
subscribe
- 使用
-
错误处理
- 使用
onErrorResume、onErrorReturn处理错误 - 避免使用
try-catch捕获响应式异常
- 使用
-
背压处理
- 使用
onBackpressureBuffer、onBackpressureDrop处理背压 - 避免内存溢出
- 使用
4.2.2 代码示例
✅ 正确示例:
public Mono<Member> getMember(Long id) {
return memberRepository.findById(id)
.switchIfEmpty(Mono.error(new BusinessException("会员不存在")))
.flatMap(member -> loadMemberCards(member.getId()))
.flatMap(member -> loadMemberBenefits(member.getId()))
.doOnSuccess(member -> log.info("查询会员成功: memberId={}", member.getId()))
.doOnError(e -> log.error("查询会员失败: memberId={}", id, e));
}
❌ 错误示例:
public Member getMember(Long id) {
// 错误:使用 block() 阻塞
return memberRepository.findById(id).block();
}
public Mono<Member> getMember(Long id) {
return memberRepository.findById(id)
.flatMap(member -> {
// 错误:在 flatMap 中使用 block()
List<MemberCard> cards = memberCardRepository.findByMemberId(member.getId()).collectList().block();
return Mono.just(member);
});
}
4.3 响应式事务管理
4.3.1 本地事务
使用 @Transactional 注解管理本地事务:
@Service
public class BookingService {
@Transactional
public Mono<BookingRecord> bookSlot(BookingRequest request) {
return validateBooking(request)
.flatMap(v -> checkSlotAvailability(request.getSlotId()))
.flatMap(slot -> deductBenefit(request.getMemberId(), slot))
.flatMap(benefit -> createBookingRecord(request, benefit))
.flatMap(booking -> updateSlotBookedCount(request.getSlotId()));
}
}
4.3.2 分布式锁
使用 Redis 实现分布式锁:
@Component
public class RedisDistributedLock {
private final ReactiveRedisTemplate<String, String> redisTemplate;
private static final String LOCK_PREFIX = "lock:";
private static final long DEFAULT_EXPIRE_TIME = 30;
public Mono<Boolean> tryLock(String key, long expireTime) {
String lockKey = LOCK_PREFIX + key;
String lockValue = UUID.randomUUID().toString();
return redisTemplate.opsForValue()
.setIfAbsent(lockKey, lockValue, Duration.ofSeconds(expireTime))
.flatMap(locked -> {
if (Boolean.TRUE.equals(locked)) {
log.info("获取锁成功: key={}", lockKey);
return Mono.just(true);
} else {
log.warn("获取锁失败: key={}", lockKey);
return Mono.just(false);
}
});
}
public Mono<Void> unlock(String key) {
String lockKey = LOCK_PREFIX + key;
return redisTemplate.delete(lockKey)
.doOnSuccess(deleted -> {
if (Boolean.TRUE.equals(deleted)) {
log.info("释放锁成功: key={}", lockKey);
}
})
.then();
}
}
4.3.3 Saga 模式(跨模块事务)
对于跨模块的事务,使用 Saga 模式:
@Service
public class BookingSaga {
public Mono<BookingRecord> execute(BookingRequest request) {
return bookSlot(request)
.flatMap(booking -> sendNotification(booking))
.flatMap(booking -> updateStatistics(booking))
.onErrorResume(e -> compensate(request, e));
}
private Mono<BookingRecord> bookSlot(BookingRequest request) {
// 预约逻辑
}
private Mono<BookingRecord> sendNotification(BookingRecord booking) {
// 发送通知
}
private Mono<BookingRecord> updateStatistics(BookingRecord booking) {
// 更新统计
}
private Mono<BookingRecord> compensate(BookingRequest request, Throwable e) {
// 补偿逻辑
return cancelBooking(request)
.then(Mono.error(e));
}
}
五、数据库设计
5.1 数据库选型
本系统采用 PostgreSQL 作为主数据库,原因如下:
- 金融级可靠性:支持 ACID 事务,数据一致性有保障
- JSONB 支持:灵活存储配置数据,支持复杂查询
- 响应式驱动:R2DBC 提供非阻塞访问
- 开源免费:降低成本
5.2 核心表设计
5.2.1 租户表(tenant)
| 字段名 | 类型 | 说明 | 约束 |
|---|---|---|---|
| id | BIGINT | 主键 | PK, AUTO_INCREMENT |
| name | VARCHAR(100) | 租户名称 | NOT NULL |
| logo_url | VARCHAR(500) | Logo地址 | NULL |
| brand_color | VARCHAR(20) | 品牌颜色 | NULL |
| status | TINYINT | 状态(1正常,2禁用) | NOT NULL, DEFAULT 1 |
| created_at | TIMESTAMP | 创建时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP |
| updated_at | TIMESTAMP | 更新时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
5.2.2 门店表(store)
| 字段名 | 类型 | 说明 | 约束 |
|---|---|---|---|
| id | BIGINT | 主键 | PK, AUTO_INCREMENT |
| tenant_id | BIGINT | 租户ID | FK, NOT NULL |
| name | VARCHAR(100) | 门店名称 | NOT NULL |
| address | VARCHAR(500) | 地址 | NULL |
| phone | VARCHAR(20) | 电话 | NULL |
| status | TINYINT | 状态(1正常,2禁用) | NOT NULL, DEFAULT 1 |
| created_at | TIMESTAMP | 创建时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP |
| updated_at | TIMESTAMP | 更新时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
5.2.3 会员表(member)
| 字段名 | 类型 | 说明 | 约束 |
|---|---|---|---|
| id | BIGINT | 主键 | PK, AUTO_INCREMENT |
| tenant_id | BIGINT | 租户ID | FK, NOT NULL |
| store_id | BIGINT | 门店ID | FK, NOT NULL |
| member_no | VARCHAR(20) | 会员编号 | UNIQUE, NOT NULL |
| name | VARCHAR(50) | 姓名 | NOT NULL |
| phone | VARCHAR(20) | 手机号 | UNIQUE, NOT NULL |
| gender | TINYINT | 性别(1男,2女) | NULL |
| birthday | DATE | 生日 | NULL |
| height | INT | 身高(cm) | NULL |
| weight | INT | 体重(kg) | NULL |
| fitness_goal | VARCHAR(100) | 健身目标 | NULL |
| status | TINYINT | 状态(1正常,2禁用) | NOT NULL, DEFAULT 1 |
| created_at | TIMESTAMP | 创建时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP |
| updated_at | TIMESTAMP | 更新时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
5.2.4 会员卡表(member_card)
| 字段名 | 类型 | 说明 | 约束 |
|---|---|---|---|
| id | BIGINT | 主键 | PK, AUTO_INCREMENT |
| member_id | BIGINT | 会员ID | FK, NOT NULL |
| card_type_id | BIGINT | 卡类型ID | FK, NOT NULL |
| card_no | VARCHAR(50) | 卡号 | UNIQUE, NOT NULL |
| start_date | DATE | 开始日期 | NOT NULL |
| end_date | DATE | 结束日期 | NULL |
| status | TINYINT | 状态(1正常,2禁用) | NOT NULL, DEFAULT 1 |
| created_at | TIMESTAMP | 创建时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP |
| updated_at | TIMESTAMP | 更新时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
5.2.5 会员权益表(member_benefit)
| 字段名 | 类型 | 说明 | 约束 |
|---|---|---|---|
| id | BIGINT | 主键 | PK, AUTO_INCREMENT |
| member_id | BIGINT | 会员ID | FK, NOT NULL |
| card_type_id | BIGINT | 卡类型ID | FK, NOT NULL |
| benefit_type | TINYINT | 权益类型(1时长,2次数,3储值) | NOT NULL |
| balance | INT | 余额(次数或金额) | NOT NULL, DEFAULT 0 |
| valid_days | INT | 有效天数 | NULL |
| expire_date | DATE | 到期日期 | NULL |
| created_at | TIMESTAMP | 创建时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP |
| updated_at | TIMESTAMP | 更新时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
5.2.6 团课表(group_class)
| 字段名 | 类型 | 说明 | 约束 |
|---|---|---|---|
| id | BIGINT | 主键 | PK, AUTO_INCREMENT |
| store_id | BIGINT | 门店ID | FK, NOT NULL |
| coach_id | BIGINT | 教练ID | FK, NOT NULL |
| name | VARCHAR(100) | 课程名称 | NOT NULL |
| description | TEXT | 课程描述 | NULL |
| max_capacity | INT | 最大容量 | NOT NULL, DEFAULT 20 |
| start_time | TIMESTAMP | 开始时间 | NOT NULL |
| end_time | TIMESTAMP | 结束时间 | NOT NULL |
| location | VARCHAR(100) | 地点 | NULL |
| status | TINYINT | 状态(1正常,2取消) | NOT NULL, DEFAULT 1 |
| created_at | TIMESTAMP | 创建时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP |
| updated_at | TIMESTAMP | 更新时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
5.2.7 预约记录表(booking_record)
| 字段名 | 类型 | 说明 | 约束 |
|---|---|---|---|
| id | BIGINT | 主键 | PK, AUTO_INCREMENT |
| member_id | BIGINT | 会员ID | FK, NOT NULL |
| group_class_id | BIGINT | 团课ID | FK, NOT NULL |
| booking_time | TIMESTAMP | 预约时间 | NOT NULL |
| cancel_time | TIMESTAMP | 取消时间 | NULL |
| status | TINYINT | 状态(1已预约,2已取消,3已完成) | NOT NULL, DEFAULT 1 |
| created_at | TIMESTAMP | 创建时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP |
| updated_at | TIMESTAMP | 更新时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
5.2.8 签到记录表(checkin_record)
| 字段名 | 类型 | 说明 | 约束 |
|---|---|---|---|
| id | BIGINT | 主键 | PK, AUTO_INCREMENT |
| member_id | BIGINT | 会员ID | FK, NOT NULL |
| store_id | BIGINT | 门店ID | FK, NOT NULL |
| booking_id | BIGINT | 预约ID | FK, NULL |
| checkin_time | TIMESTAMP | 签到时间 | NOT NULL |
| checkin_type | TINYINT | 签到类型(1自由训练,2团课) | NOT NULL |
| created_at | TIMESTAMP | 创建时间 | NOT NULL, DEFAULT CURRENT_TIMESTAMP |
5.3 索引设计
| 表名 | 索引名 | 字段 | 类型 | 说明 |
|---|---|---|---|---|
| member | idx_member_phone | phone | BTREE | 手机号索引 |
| member | idx_member_store | store_id | BTREE | 门店ID索引 |
| member_card | idx_card_member | member_id | BTREE | 会员ID索引 |
| member_benefit | idx_benefit_member | member_id | BTREE | 会员ID索引 |
| group_class | idx_class_store | store_id | BTREE | 门店ID索引 |
| group_class | idx_class_time | start_time | BTREE | 开始时间索引 |
| booking_record | idx_booking_member | member_id | BTREE | 会员ID索引 |
| booking_record | idx_booking_class | group_class_id | BTREE | 团课ID索引 |
| checkin_record | idx_checkin_member | member_id | BTREE | 会员ID索引 |
| checkin_record | idx_checkin_time | checkin_time | BTREE | 签到时间索引 |
六、API接口设计
6.1 API设计原则
- RESTful风格:遵循REST架构风格
- 统一响应格式:所有接口返回统一格式
- 版本控制:通过URL路径进行版本控制
- 错误处理:统一的错误码和错误信息
- 幂等性:关键操作支持幂等性
6.2 统一响应格式
{
"code": 200,
"message": "success",
"data": {},
"timestamp": 1678234567890
}
6.3 核心API接口
6.3.1 会员模块API
| 接口 | 方法 | 路径 | 说明 |
|---|---|---|---|
| 会员注册 | POST | /api/v1/members/register | 注册新会员 |
| 会员登录 | POST | /api/v1/members/login | 会员登录 |
| 获取会员信息 | GET | /api/v1/members/{id} | 获取会员详情 |
| 更新会员信息 | PUT | /api/v1/members/{id} | 更新会员信息 |
| 获取会员列表 | GET | /api/v1/members | 获取会员列表 |
6.3.2 预约模块API
| 接口 | 方法 | 路径 | 说明 |
|---|---|---|---|
| 预约团课 | POST | /api/v1/bookings | 预约团课 |
| 取消预约 | DELETE | /api/v1/bookings/{id} | 取消预约 |
| 获取预约记录 | GET | /api/v1/bookings | 获取预约记录 |
| 创建团课 | POST | /api/v1/group-classes | 创建团课 |
| 获取团课列表 | GET | /api/v1/group-classes | 获取团课列表 |
6.3.3 签到模块API
| 接口 | 方法 | 路径 | 说明 |
|---|---|---|---|
| 会员签到 | POST | /api/v1/checkins | 会员签到 |
| 获取签到记录 | GET | /api/v1/checkins | 获取签到记录 |
6.3.4 会员卡模块API
| 接口 | 方法 | 路径 | 说明 |
|---|---|---|---|
| 购买会员卡 | POST | /api/v1/member-cards | 购买会员卡 |
| 获取会员卡列表 | GET | /api/v1/member-cards | 获取会员卡列表 |
| 续费会员卡 | POST | /api/v1/member-cards/{id}/renew | 续费会员卡 |
6.4 API接口示例
6.4.1 预约团课
请求:
POST /api/v1/bookings
Content-Type: application/json
Authorization: Bearer {token}
{
"memberId": 123,
"groupClassId": 456
}
响应:
{
"code": 200,
"message": "预约成功",
"data": {
"id": 789,
"memberId": 123,
"groupClassId": 456,
"bookingTime": "2026-03-08T10:00:00",
"status": 1
},
"timestamp": 1678234567890
}
七、部署架构
7.1 部署方式
本系统采用 Docker Compose 进行容器化部署,实现一键部署和环境一致性。
7.2 部署架构图
flowchart TB
subgraph "部署架构"
A[用户] --> B[Nginx<br/>反向代理]
B --> C[应用服务器<br/>gym-manage]
C --> D[PostgreSQL<br/>数据库]
C --> E[Redis<br/>缓存]
C --> F[RabbitMQ<br/>消息队列]
C --> G[Elasticsearch<br/>搜索引擎]
C --> H[Prometheus<br/>监控]
H --> I[Grafana<br/>可视化]
end
7.3 Docker Compose配置
version: '3.8'
services:
# 应用服务
gym-manage:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- DB_HOST=postgres
- REDIS_HOST=redis
- RABBITMQ_HOST=rabbitmq
- ELASTICSEARCH_HOST=elasticsearch
depends_on:
- postgres
- redis
- rabbitmq
- elasticsearch
networks:
- gym-network
# PostgreSQL数据库
postgres:
image: postgres:15-alpine
environment:
- POSTGRES_DB=gym_manage
- POSTGRES_USER=gym_user
- POSTGRES_PASSWORD=gym_password
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- "5432:5432"
networks:
- gym-network
# Redis缓存
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- gym-network
# RabbitMQ消息队列
rabbitmq:
image: rabbitmq:3.12-management-alpine
environment:
- RABBITMQ_DEFAULT_USER=gym_user
- RABBITMQ_DEFAULT_PASS=gym_password
ports:
- "5672:5672"
- "15672:15672"
volumes:
- rabbitmq-data:/var/lib/rabbitmq
networks:
- gym-network
# Elasticsearch搜索引擎
elasticsearch:
image: elasticsearch:8.11.0
environment:
- discovery.type=single-node
- ES_JAVA_OPTS=-Xms512m -Xmx512m
ports:
- "9200:9200"
- "9300:9300"
volumes:
- elasticsearch-data:/usr/share/elasticsearch/data
networks:
- gym-network
# Prometheus监控
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
networks:
- gym-network
# Grafana可视化
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
networks:
- gym-network
volumes:
postgres-data:
redis-data:
rabbitmq-data:
elasticsearch-data:
prometheus-data:
grafana-data:
networks:
gym-network:
driver: bridge
7.4 部署步骤
-
构建镜像:
docker-compose build -
启动服务:
docker-compose up -d -
查看日志:
docker-compose logs -f gym-manage -
停止服务:
docker-compose down
八、监控与运维
8.1 监控体系
本系统采用 Prometheus + Grafana 构建完善的监控体系:
| 监控类型 | 监控内容 | 告警阈值 |
|---|---|---|
| 应用监控 | JVM内存、CPU、线程数 | 内存使用率 > 80% |
| 接口监控 | 请求量、响应时间、错误率 | 错误率 > 5% |
| 数据库监控 | 连接数、查询时间、慢查询 | 慢查询 > 1s |
| 缓存监控 | 命中率、内存使用 | 命中率 < 80% |
| 消息队列监控 | 队列长度、消费速率 | 队列长度 > 1000 |
8.2 日志管理
采用结构化日志,便于查询和分析:
@Slf4j
@Service
public class BookingService {
public Mono<BookingRecord> bookSlot(BookingRequest request) {
log.info("开始预约团课: memberId={}, groupClassId={}",
request.getMemberId(), request.getGroupClassId());
return bookingRepository.save(booking)
.doOnSuccess(booking -> log.info("预约成功: bookingId={}", booking.getId()))
.doOnError(e -> log.error("预约失败: memberId={}, groupClassId={}",
request.getMemberId(), request.getGroupClassId(), e));
}
}
8.3 性能优化
8.3.1 缓存策略
| 缓存类型 | 缓存内容 | 过期时间 | 更新策略 |
|---|---|---|---|
| 本地缓存 | 配置信息、字典数据 | 30分钟 | 定时刷新 |
| Redis缓存 | 会员信息、团课信息 | 1小时 | 主动更新 |
| 查询缓存 | 热点查询结果 | 10分钟 | 惰性更新 |
8.3.2 数据库优化
- 索引优化:为常用查询字段添加索引
- 查询优化:避免全表扫描,使用分页查询
- 连接池优化:合理配置连接池大小
- 读写分离:主从复制,读写分离
8.3.3 响应式优化
- 非阻塞I/O:所有I/O操作使用非阻塞方式
- 背压处理:合理处理背压,避免内存溢出
- 异步处理:耗时操作异步处理
- 线程池优化:合理配置线程池大小
九、安全设计
9.1 认证授权
采用 JWT + Spring Security 实现认证授权:
- JWT Token:用户登录后签发JWT Token
- Token验证:每次请求验证Token有效性
- 权限控制:基于角色的访问控制(RBAC)
9.2 数据安全
- 数据加密:敏感数据加密存储
- 传输加密:HTTPS加密传输
- 数据备份:定期备份数据
- 审计日志:记录关键操作日志
9.3 接口安全
- 限流:防止接口被恶意调用
- 防重放:防止请求重放攻击
- 参数校验:严格校验请求参数
- SQL注入防护:使用参数化查询
十、测试策略
10.1 测试分层
| 测试类型 | 测试内容 | 测试工具 |
|---|---|---|
| 单元测试 | 单个方法/类的测试 | JUnit, Mockito |
| 集成测试 | 多个组件协作测试 | SpringBootTest, TestContainers |
| 接口测试 | API接口测试 | Postman, RestAssured |
| 性能测试 | 系统性能测试 | JMeter, Gatling |
10.2 测试覆盖率
- 单元测试覆盖率:≥ 80%
- 集成测试覆盖率:≥ 60%
- 关键路径覆盖率:100%
十一、附录
11.1 技术术语表
| 术语 | 说明 |
|---|---|
| 响应式编程 | 基于异步数据流和变化传播的编程范式 |
| R2DBC | Reactive Relational Database Connectivity,响应式数据库连接规范 |
| Mono | Project Reactor中表示0-1个元素的响应式类型 |
| Flux | Project Reactor中表示0-N个元素的响应式类型 |
| Saga模式 | 长时间运行事务的补偿模式 |
11.2 参考文档
- 《健身房管理系统基础版产品设计文档》 GYM-PRD-BASIC-001
- 《健身房管理系统基础版业务概要设计文档》 GYM-B-HLD-BASIC-001
- 《健身房管理系统基础版业务详细设计文档》 GYM-B-LLD-BASIC-001
- Spring Boot 3 官方文档
- Spring WebFlux 官方文档
- R2DBC 规范文档
- PostgreSQL 官方文档
11.3 变更记录
| 版本 | 日期 | 作者 | 修订内容 |
|---|---|---|---|
| v1.0 | 2026-03-08 | 张翔 | 创建基础版技术设计文档,整合技术架构和实现细节 |