295 lines
11 KiB
Markdown
295 lines
11 KiB
Markdown
# 认证服务重构说明
|
||
|
||
## 重构目标
|
||
|
||
根据DDD(领域驱动设计)原则,重新划分认证服务的应用层和领域层职责,提高代码的解耦性和可维护性。
|
||
|
||
## 重构前后对比
|
||
|
||
### 重构前的问题
|
||
|
||
1. **职责混乱**:应用服务层直接操作仓库,违反了分层架构原则
|
||
2. **业务逻辑分散**:认证相关的业务逻辑分散在应用服务中,难以维护
|
||
3. **耦合度高**:应用服务与具体的数据访问技术耦合
|
||
4. **可测试性差**:业务逻辑与基础设施代码混合,难以进行单元测试
|
||
|
||
### 重构后的改进
|
||
|
||
1. **职责清晰**:应用层专注业务流程编排,领域层专注业务逻辑
|
||
2. **高内聚低耦合**:按业务功能模块划分领域服务
|
||
3. **易于测试**:业务逻辑独立,可以独立进行单元测试
|
||
4. **易于扩展**:新增业务功能时,只需要在相应的领域服务中添加方法
|
||
|
||
## 新的架构设计
|
||
|
||
### 1. 应用服务层 (Application Layer)
|
||
|
||
**职责**:
|
||
- 业务流程编排和协调
|
||
- 事务管理
|
||
- 数据转换(DTO ↔ 领域对象)
|
||
- 调用领域服务
|
||
- 不直接操作仓库
|
||
|
||
**主要方法**:
|
||
```go
|
||
type CertificationApplicationService interface {
|
||
// 认证状态查询
|
||
GetCertificationStatus(ctx context.Context, query *queries.GetCertificationStatusQuery) (*responses.CertificationResponse, error)
|
||
GetCertificationDetails(ctx context.Context, query *queries.GetCertificationDetailsQuery) (*responses.CertificationResponse, error)
|
||
GetCertificationProgress(ctx context.Context, userID string) (map[string]interface{}, error)
|
||
|
||
// 企业信息管理
|
||
SubmitEnterpriseInfo(ctx context.Context, cmd *commands.SubmitEnterpriseInfoCommand) (*responses.EnterpriseInfoResponse, error)
|
||
|
||
// 企业认证
|
||
EnterpriseVerify(ctx context.Context, userID string) (*responses.CertificationResponse, error)
|
||
|
||
// 合同管理
|
||
ApplyContract(ctx context.Context, userID string) (*responses.CertificationResponse, error)
|
||
CompleteContractSign(ctx context.Context, certificationID, contractURL string) error
|
||
}
|
||
```
|
||
|
||
### 2. 领域服务层 (Domain Layer)
|
||
|
||
#### 2.1 认证管理服务 (CertificationManagementService)
|
||
|
||
**职责**:
|
||
- 认证申请的生命周期管理
|
||
- 认证申请的创建、查询
|
||
- 认证进度信息获取
|
||
|
||
**主要方法**:
|
||
```go
|
||
type CertificationManagementService struct {
|
||
certRepo repositories.CertificationRepository
|
||
stateMachine *CertificationStateMachine
|
||
logger *zap.Logger
|
||
}
|
||
|
||
// 主要方法
|
||
- CreateCertification(ctx context.Context, userID string) (*entities.Certification, error)
|
||
- GetCertificationByUserID(ctx context.Context, userID string) (*entities.Certification, error)
|
||
- GetCertificationByID(ctx context.Context, certificationID string) (*entities.Certification, error)
|
||
- GetCertificationProgress(ctx context.Context, certificationID string) (map[string]interface{}, error)
|
||
```
|
||
|
||
#### 2.2 认证工作流服务 (CertificationWorkflowService)
|
||
|
||
**职责**:
|
||
- 认证流程的状态转换
|
||
- 业务规则验证
|
||
- 状态机操作
|
||
|
||
**主要方法**:
|
||
```go
|
||
type CertificationWorkflowService struct {
|
||
certRepo repositories.CertificationRepository
|
||
stateMachine *CertificationStateMachine
|
||
logger *zap.Logger
|
||
}
|
||
|
||
// 主要方法
|
||
- SubmitEnterpriseInfo(ctx context.Context, certificationID string) error
|
||
- CompleteEnterpriseVerification(ctx context.Context, certificationID string) error
|
||
- ApplyContract(ctx context.Context, certificationID string) error
|
||
- CompleteContractSign(ctx context.Context, certificationID, contractURL string) error
|
||
- CompleteCertification(ctx context.Context, certificationID string) error
|
||
```
|
||
|
||
#### 2.3 企业信息服务 (EnterpriseService)
|
||
|
||
**职责**:
|
||
- 企业信息的创建、更新、查询
|
||
- 企业信息验证状态管理
|
||
- 企业认证流程
|
||
|
||
**主要方法**:
|
||
```go
|
||
type EnterpriseService struct {
|
||
userRepo repositories.UserRepository
|
||
enterpriseInfoRepo repositories.EnterpriseInfoRepository
|
||
logger *zap.Logger
|
||
}
|
||
|
||
// 主要方法
|
||
- CreateEnterpriseInfo(ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID string) (*entities.EnterpriseInfo, error)
|
||
- GetEnterpriseInfo(ctx context.Context, userID string) (*entities.EnterpriseInfo, error)
|
||
- UpdateOCRVerification(ctx context.Context, userID string, isVerified bool, rawData string, confidence float64) error
|
||
- UpdateFaceVerification(ctx context.Context, userID string, isVerified bool) error
|
||
- CheckUnifiedSocialCodeExists(ctx context.Context, unifiedSocialCode, excludeUserID string) (bool, error)
|
||
```
|
||
|
||
## 业务流程示例
|
||
|
||
### 提交企业信息流程
|
||
|
||
```go
|
||
// 应用服务层 - 业务流程编排
|
||
func (s *CertificationApplicationServiceImpl) SubmitEnterpriseInfo(ctx context.Context, cmd *commands.SubmitEnterpriseInfoCommand) (*responses.EnterpriseInfoResponse, error) {
|
||
// 1. 验证企业信息(检查统一社会信用代码是否已存在)
|
||
exists, err := s.enterpriseService.CheckUnifiedSocialCodeExists(ctx, cmd.UnifiedSocialCode, "")
|
||
if err != nil {
|
||
return nil, fmt.Errorf("检查企业信息失败: %w", err)
|
||
}
|
||
if exists {
|
||
return nil, fmt.Errorf("统一社会信用代码已存在")
|
||
}
|
||
|
||
// 2. 获取或创建认证申请
|
||
certification, err := s.certManagementService.GetCertificationByUserID(ctx, cmd.UserID)
|
||
if err != nil {
|
||
// 如果认证申请不存在,自动创建
|
||
if err.Error() == "认证申请不存在" || err.Error() == "record not found" {
|
||
certification, err = s.certManagementService.CreateCertification(ctx, cmd.UserID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("创建认证申请失败: %w", err)
|
||
}
|
||
} else {
|
||
return nil, fmt.Errorf("获取认证申请失败: %w", err)
|
||
}
|
||
}
|
||
|
||
// 3. 提交企业信息(状态转换)
|
||
if err := s.certWorkflowService.SubmitEnterpriseInfo(ctx, certification.ID); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 4. 创建企业信息
|
||
enterpriseInfo, err := s.enterpriseService.CreateEnterpriseInfo(ctx, cmd.UserID, cmd.CompanyName, cmd.UnifiedSocialCode, cmd.LegalPersonName, cmd.LegalPersonID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return s.buildEnterpriseInfoResponse(enterpriseInfo), nil
|
||
}
|
||
```
|
||
|
||
### 企业认证流程
|
||
|
||
```go
|
||
// 应用服务层 - 业务流程编排
|
||
func (s *CertificationApplicationServiceImpl) EnterpriseVerify(ctx context.Context, userID string) (*responses.CertificationResponse, error) {
|
||
// 1. 获取认证申请
|
||
certification, err := s.certManagementService.GetCertificationByUserID(ctx, userID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("用户尚未创建认证申请: %w", err)
|
||
}
|
||
|
||
// 2. 完成企业认证(状态转换)
|
||
if err := s.certWorkflowService.CompleteEnterpriseVerification(ctx, certification.ID); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 3. 更新企业信息验证状态(模拟OCR和人脸识别验证)
|
||
if err := s.enterpriseService.UpdateOCRVerification(ctx, userID, true, "OCR验证通过", 0.95); err != nil {
|
||
s.logger.Warn("更新OCR验证状态失败", zap.Error(err))
|
||
}
|
||
if err := s.enterpriseService.UpdateFaceVerification(ctx, userID, true); err != nil {
|
||
s.logger.Warn("更新人脸识别验证状态失败", zap.Error(err))
|
||
}
|
||
|
||
// 4. 重新获取更新后的认证申请
|
||
updatedCertification, err := s.certManagementService.GetCertificationByID(ctx, certification.ID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return s.buildCertificationResponse(updatedCertification), nil
|
||
}
|
||
```
|
||
|
||
## 依赖注入配置
|
||
|
||
### 领域服务注册
|
||
|
||
```go
|
||
// 领域服务
|
||
fx.Provide(
|
||
user_service.NewUserService,
|
||
user_service.NewSMSCodeService,
|
||
user_service.NewEnterpriseService,
|
||
certification_service.NewCertificationManagementService, // 新增
|
||
certification_service.NewCertificationWorkflowService, // 新增
|
||
certification_service.NewCertificationStateMachine,
|
||
finance_service.NewFinanceService,
|
||
product_service.NewProductService,
|
||
),
|
||
```
|
||
|
||
### 应用服务注册
|
||
|
||
```go
|
||
// 应用服务
|
||
fx.Annotate(
|
||
certification.NewCertificationApplicationService,
|
||
fx.As(new(certification.CertificationApplicationService)),
|
||
),
|
||
```
|
||
|
||
## 重构收益
|
||
|
||
### 1. 代码质量提升
|
||
|
||
- **单一职责原则**:每个服务都有明确的职责范围
|
||
- **开闭原则**:新增功能时不需要修改现有代码
|
||
- **依赖倒置原则**:高层模块不依赖低层模块,都依赖抽象
|
||
|
||
### 2. 可维护性提升
|
||
|
||
- **业务逻辑集中**:相关的业务逻辑集中在对应的领域服务中
|
||
- **易于理解**:代码结构清晰,新人容易理解
|
||
- **易于调试**:问题定位更容易,调试更简单
|
||
|
||
### 3. 可测试性提升
|
||
|
||
- **单元测试**:每个领域服务可以独立进行单元测试
|
||
- **集成测试**:应用服务层可以独立进行集成测试
|
||
- **模拟测试**:可以轻松模拟依赖的服务
|
||
|
||
### 4. 可扩展性提升
|
||
|
||
- **新增功能**:只需要在相应的领域服务中添加方法
|
||
- **修改功能**:修改影响范围小,不会影响其他模块
|
||
- **替换实现**:可以轻松替换某个服务的实现
|
||
|
||
## 最佳实践
|
||
|
||
### 1. 应用服务层设计原则
|
||
|
||
- **业务流程编排**:专注于业务流程的编排和协调
|
||
- **事务管理**:负责事务的边界和一致性
|
||
- **数据转换**:负责DTO和领域对象之间的转换
|
||
- **错误处理**:统一处理业务异常和系统异常
|
||
|
||
### 2. 领域服务层设计原则
|
||
|
||
- **业务功能模块化**:按业务功能划分服务
|
||
- **单一职责**:每个服务只负责一个业务领域
|
||
- **高内聚**:相关的业务逻辑集中在一起
|
||
- **低耦合**:服务之间通过接口进行交互
|
||
|
||
### 3. 命名规范
|
||
|
||
- **应用服务**:`XxxApplicationService`
|
||
- **领域服务**:`XxxManagementService`、`XxxWorkflowService`、`XxxService`
|
||
- **方法命名**:使用动词+名词的形式,如`CreateCertification`、`SubmitEnterpriseInfo`
|
||
|
||
### 4. 错误处理
|
||
|
||
- **业务异常**:在领域服务中抛出业务异常
|
||
- **系统异常**:在应用服务中处理系统异常
|
||
- **错误信息**:使用中文错误信息,提高用户体验
|
||
|
||
## 总结
|
||
|
||
通过这次重构,我们实现了:
|
||
|
||
1. **清晰的职责划分**:应用层专注业务流程编排,领域层专注业务逻辑
|
||
2. **高内聚低耦合**:按业务功能模块划分服务,降低模块间耦合
|
||
3. **易于测试**:业务逻辑独立,可以独立进行单元测试
|
||
4. **易于维护**:代码结构清晰,新人容易理解和维护
|
||
5. **易于扩展**:新增功能时影响范围小,不会影响其他模块
|
||
|
||
这种架构设计符合DDD原则,为后续的功能扩展和维护奠定了良好的基础。 |