1010 lines
31 KiB
Markdown
1010 lines
31 KiB
Markdown
# 健身房管理系统基础版技术实现详细设计文档(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. 为开发人员提供技术实现指导
|
||
3. 作为架构师、开发工程师的技术参考
|
||
|
||
### 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 总体架构
|
||
|
||
采用分层架构 + 模块化设计的单体应用:
|
||
|
||
```mermaid
|
||
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 基本原则
|
||
|
||
1. **永不阻塞**
|
||
- 禁止在响应式流中使用 `block()`、`blockFirst()`、`blockLast()`
|
||
- 所有 I/O 操作必须使用非阻塞方式
|
||
|
||
2. **链式调用**
|
||
- 使用 `flatMap`、`map`、`filter` 等操作符链式调用
|
||
- 避免嵌套的 `subscribe`
|
||
|
||
3. **错误处理**
|
||
- 使用 `onErrorResume`、`onErrorReturn` 处理错误
|
||
- 避免使用 `try-catch` 捕获响应式异常
|
||
|
||
4. **背压处理**
|
||
- 使用 `onBackpressureBuffer`、`onBackpressureDrop` 处理背压
|
||
- 避免内存溢出
|
||
|
||
#### 4.2.2 代码示例
|
||
|
||
**✅ 正确示例**:
|
||
|
||
```java
|
||
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));
|
||
}
|
||
```
|
||
|
||
**❌ 错误示例**:
|
||
|
||
```java
|
||
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` 注解管理本地事务:
|
||
|
||
```java
|
||
@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 实现分布式锁:
|
||
|
||
```java
|
||
@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 模式:
|
||
|
||
```java
|
||
@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 作为主数据库,原因如下:
|
||
|
||
1. **金融级可靠性**:支持 ACID 事务,数据一致性有保障
|
||
2. **JSONB 支持**:灵活存储配置数据,支持复杂查询
|
||
3. **响应式驱动**:R2DBC 提供非阻塞访问
|
||
4. **开源免费**:降低成本
|
||
|
||
### 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设计原则
|
||
|
||
1. **RESTful风格**:遵循REST架构风格
|
||
2. **统一响应格式**:所有接口返回统一格式
|
||
3. **版本控制**:通过URL路径进行版本控制
|
||
4. **错误处理**:统一的错误码和错误信息
|
||
5. **幂等性**:关键操作支持幂等性
|
||
|
||
### 6.2 统一响应格式
|
||
|
||
```json
|
||
{
|
||
"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 预约团课
|
||
|
||
**请求**:
|
||
|
||
```http
|
||
POST /api/v1/bookings
|
||
Content-Type: application/json
|
||
Authorization: Bearer {token}
|
||
|
||
{
|
||
"memberId": 123,
|
||
"groupClassId": 456
|
||
}
|
||
```
|
||
|
||
**响应**:
|
||
|
||
```json
|
||
{
|
||
"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 部署架构图
|
||
|
||
```mermaid
|
||
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配置
|
||
|
||
```yaml
|
||
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 部署步骤
|
||
|
||
1. **构建镜像**:
|
||
```bash
|
||
docker-compose build
|
||
```
|
||
|
||
2. **启动服务**:
|
||
```bash
|
||
docker-compose up -d
|
||
```
|
||
|
||
3. **查看日志**:
|
||
```bash
|
||
docker-compose logs -f gym-manage
|
||
```
|
||
|
||
4. **停止服务**:
|
||
```bash
|
||
docker-compose down
|
||
```
|
||
|
||
---
|
||
|
||
## 八、监控与运维
|
||
|
||
### 8.1 监控体系
|
||
|
||
本系统采用 Prometheus + Grafana 构建完善的监控体系:
|
||
|
||
| 监控类型 | 监控内容 | 告警阈值 |
|
||
|---------|---------|---------|
|
||
| **应用监控** | JVM内存、CPU、线程数 | 内存使用率 > 80% |
|
||
| **接口监控** | 请求量、响应时间、错误率 | 错误率 > 5% |
|
||
| **数据库监控** | 连接数、查询时间、慢查询 | 慢查询 > 1s |
|
||
| **缓存监控** | 命中率、内存使用 | 命中率 < 80% |
|
||
| **消息队列监控** | 队列长度、消费速率 | 队列长度 > 1000 |
|
||
|
||
### 8.2 日志管理
|
||
|
||
采用结构化日志,便于查询和分析:
|
||
|
||
```java
|
||
@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 数据库优化
|
||
|
||
1. **索引优化**:为常用查询字段添加索引
|
||
2. **查询优化**:避免全表扫描,使用分页查询
|
||
3. **连接池优化**:合理配置连接池大小
|
||
4. **读写分离**:主从复制,读写分离
|
||
|
||
#### 8.3.3 响应式优化
|
||
|
||
1. **非阻塞I/O**:所有I/O操作使用非阻塞方式
|
||
2. **背压处理**:合理处理背压,避免内存溢出
|
||
3. **异步处理**:耗时操作异步处理
|
||
4. **线程池优化**:合理配置线程池大小
|
||
|
||
---
|
||
|
||
## 九、安全设计
|
||
|
||
### 9.1 认证授权
|
||
|
||
采用 JWT + Spring Security 实现认证授权:
|
||
|
||
1. **JWT Token**:用户登录后签发JWT Token
|
||
2. **Token验证**:每次请求验证Token有效性
|
||
3. **权限控制**:基于角色的访问控制(RBAC)
|
||
|
||
### 9.2 数据安全
|
||
|
||
1. **数据加密**:敏感数据加密存储
|
||
2. **传输加密**:HTTPS加密传输
|
||
3. **数据备份**:定期备份数据
|
||
4. **审计日志**:记录关键操作日志
|
||
|
||
### 9.3 接口安全
|
||
|
||
1. **限流**:防止接口被恶意调用
|
||
2. **防重放**:防止请求重放攻击
|
||
3. **参数校验**:严格校验请求参数
|
||
4. **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 | 张翔 | 创建基础版技术设计文档,整合技术架构和实现细节 |
|