new
This commit is contained in:
176
docs/组合包动态处理机制说明.md
Normal file
176
docs/组合包动态处理机制说明.md
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
# 组合包动态处理机制说明
|
||||||
|
|
||||||
|
## 🎉 重大更新
|
||||||
|
|
||||||
|
组合包系统现在支持**动态处理机制**!这意味着:
|
||||||
|
- ✅ **零编码**:大部分组合包无需编写任何Go代码
|
||||||
|
- ✅ **配置驱动**:只需在数据库配置即可立即使用
|
||||||
|
- ✅ **灵活扩展**:特殊需求仍可通过自定义处理器实现
|
||||||
|
|
||||||
|
## 🔧 工作原理
|
||||||
|
|
||||||
|
### 处理优先级
|
||||||
|
1. **自定义处理器优先**:如果注册了专门的处理器,优先使用
|
||||||
|
2. **通用处理器兜底**:COMB开头的API自动使用通用组合包处理器
|
||||||
|
3. **数据库驱动**:根据数据库配置自动调用子产品处理器
|
||||||
|
|
||||||
|
### 系统架构
|
||||||
|
```
|
||||||
|
API请求 (COMBXXXX)
|
||||||
|
↓
|
||||||
|
优先查找自定义处理器
|
||||||
|
↓ (未找到)
|
||||||
|
检查是否COMB开头
|
||||||
|
↓ (是)
|
||||||
|
通用组合包处理器
|
||||||
|
↓
|
||||||
|
查询数据库获取子产品配置
|
||||||
|
↓
|
||||||
|
并发调用子产品处理器
|
||||||
|
↓
|
||||||
|
聚合结果并返回
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📋 使用方法
|
||||||
|
|
||||||
|
### 方案1:纯配置组合包(推荐)
|
||||||
|
|
||||||
|
**步骤1:创建组合包产品**
|
||||||
|
```sql
|
||||||
|
INSERT INTO products (
|
||||||
|
id, code, name, description,
|
||||||
|
is_package, is_enabled, is_visible,
|
||||||
|
price, category_id
|
||||||
|
) VALUES (
|
||||||
|
'uuid1', 'COMB1234', '身份验证组合包', '包含身份证二要素和手机三要素验证',
|
||||||
|
true, true, true,
|
||||||
|
5.00, 'category_id'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**步骤2:配置子产品**
|
||||||
|
```sql
|
||||||
|
INSERT INTO product_package_items (package_id, product_id, sort_order) VALUES
|
||||||
|
('uuid1', 'product_id_1', 1), -- FLXG162A 身份证二要素
|
||||||
|
('uuid1', 'product_id_2', 2); -- FLXG54F5 手机三要素
|
||||||
|
```
|
||||||
|
|
||||||
|
**步骤3:直接使用**
|
||||||
|
```bash
|
||||||
|
# 立即可用,无需任何代码编写!
|
||||||
|
POST /api/v1/COMB1234
|
||||||
|
{
|
||||||
|
"id_card": "123456789012345678",
|
||||||
|
"name": "张三",
|
||||||
|
"mobile_no": "13800138000"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方案2:自定义逻辑组合包
|
||||||
|
|
||||||
|
如果需要对结果进行后处理,才需要编写代码:
|
||||||
|
|
||||||
|
**步骤1:创建处理器文件**
|
||||||
|
```go
|
||||||
|
// internal/domains/api/services/processors/comb/comb1234_processor.go
|
||||||
|
func ProcessCOMB1234Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
|
// 参数验证
|
||||||
|
var paramsDto dto.COMB1234Req
|
||||||
|
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用组合包服务
|
||||||
|
combinedResult, err := deps.CombService.ProcessCombRequest(ctx, params, deps, "COMB1234")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义后处理逻辑
|
||||||
|
for _, resp := range combinedResult.Responses {
|
||||||
|
if resp.ApiCode == "FLXG162A" && resp.Success {
|
||||||
|
// 添加自定义字段
|
||||||
|
if data, ok := resp.Data.(map[string]interface{}); ok {
|
||||||
|
data["processed_by"] = "COMB1234"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(combinedResult)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**步骤2:注册处理器**
|
||||||
|
```go
|
||||||
|
// api_request_service.go 中添加
|
||||||
|
"COMB1234": comb.ProcessCOMB1234Request, // 有自定义逻辑
|
||||||
|
```
|
||||||
|
|
||||||
|
**步骤3:添加DTO(如需要)**
|
||||||
|
```go
|
||||||
|
// dto/api_request_dto.go 中添加
|
||||||
|
type COMB1234Req struct {
|
||||||
|
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
||||||
|
Name string `json:"name" validate:"required,min=1,validName"`
|
||||||
|
MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 现有组合包状态
|
||||||
|
|
||||||
|
### ✅ 已迁移到动态处理
|
||||||
|
- **COMB298Y**:删除了专门的处理器文件,现在使用通用处理器
|
||||||
|
|
||||||
|
### 🔧 保留自定义处理器
|
||||||
|
- **COMB86PM**:有特殊逻辑(重命名ApiCode),保留自定义处理器
|
||||||
|
|
||||||
|
## 🎯 响应格式
|
||||||
|
|
||||||
|
所有组合包都返回统一的响应格式:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"responses": [
|
||||||
|
{
|
||||||
|
"api_code": "FLXG162A",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
// 子产品的响应数据
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"api_code": "FLXG54F5",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
// 子产品的响应数据
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"api_code": "YYSY4B37",
|
||||||
|
"success": false,
|
||||||
|
"error": "数据源异常"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 优势总结
|
||||||
|
|
||||||
|
1. **开发效率**:90%的组合包无需编写代码
|
||||||
|
2. **维护成本**:减少重复代码,统一处理逻辑
|
||||||
|
3. **业务灵活**:数据库配置即时生效
|
||||||
|
4. **向后兼容**:现有自定义处理器继续工作
|
||||||
|
5. **扩展性强**:特殊需求仍可通过自定义处理器实现
|
||||||
|
|
||||||
|
## ⚡ 性能特性
|
||||||
|
|
||||||
|
- **并发处理**:所有子产品并发调用
|
||||||
|
- **独立失败**:单个子产品失败不影响其他
|
||||||
|
- **智能排序**:通过sort_order控制响应顺序
|
||||||
|
- **错误隔离**:每个子产品的错误独立处理
|
||||||
|
|
||||||
|
现在,创建一个新的组合包就像配置数据库一样简单!🎉
|
||||||
1
go.mod
1
go.mod
@@ -97,6 +97,7 @@ require (
|
|||||||
github.com/spf13/afero v1.12.0 // indirect
|
github.com/spf13/afero v1.12.0 // indirect
|
||||||
github.com/spf13/cast v1.7.1 // indirect
|
github.com/spf13/cast v1.7.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.6 // indirect
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
|
github.com/stretchr/objx v0.5.2 // indirect
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
github.com/tidwall/pretty v1.2.0 // indirect
|
github.com/tidwall/pretty v1.2.0 // indirect
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -227,6 +227,8 @@ github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqj
|
|||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
|||||||
@@ -277,6 +277,31 @@ type IVYZ7F3AReq struct {
|
|||||||
Authorized string `json:"authorized" validate:"required,oneof=0 1"`
|
Authorized string `json:"authorized" validate:"required,oneof=0 1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增的QYGL处理器DTO
|
||||||
|
type QYGL5A3CReq struct {
|
||||||
|
EntCode string `json:"ent_code" validate:"required,validUSCI"`
|
||||||
|
PageSize int `json:"page_size" validate:"omitempty,min=1,max=100"`
|
||||||
|
PageNum int `json:"page_num" validate:"omitempty,min=1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type QYGL8B4DReq struct {
|
||||||
|
EntCode string `json:"ent_code" validate:"required,validUSCI"`
|
||||||
|
PageSize int `json:"page_size" validate:"omitempty,min=1,max=100"`
|
||||||
|
PageNum int `json:"page_num" validate:"omitempty,min=1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type QYGL9E2FReq struct {
|
||||||
|
EntCode string `json:"ent_code" validate:"required,validUSCI"`
|
||||||
|
PageSize int `json:"page_size" validate:"omitempty,min=1,max=100"`
|
||||||
|
PageNum int `json:"page_num" validate:"omitempty,min=1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type QYGL7C1AReq struct {
|
||||||
|
EntCode string `json:"ent_code" validate:"required,validUSCI"`
|
||||||
|
PageSize int `json:"page_size" validate:"omitempty,min=1,max=100"`
|
||||||
|
PageNum int `json:"page_num" validate:"omitempty,min=1"`
|
||||||
|
}
|
||||||
|
|
||||||
type YYSY4F2EReq struct {
|
type YYSY4F2EReq struct {
|
||||||
MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"`
|
MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"`
|
||||||
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"tyapi-server/internal/application/api/commands"
|
"tyapi-server/internal/application/api/commands"
|
||||||
@@ -119,6 +120,10 @@ func registerAllProcessors(combService *comb.CombService) {
|
|||||||
"QYGL8271": qygl.ProcessQYGL8271Request,
|
"QYGL8271": qygl.ProcessQYGL8271Request,
|
||||||
"QYGLB4C0": qygl.ProcessQYGLB4C0Request,
|
"QYGLB4C0": qygl.ProcessQYGLB4C0Request,
|
||||||
"QYGL23T7": qygl.ProcessQYGL23T7Request, // 企业三要素验证
|
"QYGL23T7": qygl.ProcessQYGL23T7Request, // 企业三要素验证
|
||||||
|
"QYGL5A3C": qygl.ProcessQYGL5A3CRequest, // 对外投资历史
|
||||||
|
"QYGL8B4D": qygl.ProcessQYGL8B4DRequest, // 融资历史
|
||||||
|
"QYGL9E2F": qygl.ProcessQYGL9E2FRequest, // 行政处罚
|
||||||
|
"QYGL7C1A": qygl.ProcessQYGL7C1ARequest, // 经营异常
|
||||||
"COMENT01": qygl.ProcessCOMENT01Request, // 企业风险报告
|
"COMENT01": qygl.ProcessCOMENT01Request, // 企业风险报告
|
||||||
|
|
||||||
// YYSY系列处理器
|
// YYSY系列处理器
|
||||||
@@ -151,9 +156,8 @@ func registerAllProcessors(combService *comb.CombService) {
|
|||||||
"IVYZ5E3F": ivyz.ProcessIVYZ5E3FRequest,
|
"IVYZ5E3F": ivyz.ProcessIVYZ5E3FRequest,
|
||||||
"IVYZ7F3A": ivyz.ProcessIVYZ7F3ARequest,
|
"IVYZ7F3A": ivyz.ProcessIVYZ7F3ARequest,
|
||||||
|
|
||||||
// COMB系列处理器
|
// COMB系列处理器 - 只注册有自定义逻辑的组合包
|
||||||
"COMB298Y": comb.ProcessCOMB298YRequest,
|
"COMB86PM": comb.ProcessCOMB86PMRequest, // 有自定义逻辑:重命名ApiCode
|
||||||
"COMB86PM": comb.ProcessCOMB86PMRequest,
|
|
||||||
|
|
||||||
// QCXG系列处理器
|
// QCXG系列处理器
|
||||||
"QCXG7A2B": qcxg.ProcessQCXG7A2BRequest,
|
"QCXG7A2B": qcxg.ProcessQCXG7A2BRequest,
|
||||||
@@ -185,10 +189,31 @@ var RequestProcessors map[string]processors.ProcessorFunc
|
|||||||
|
|
||||||
// PreprocessRequestApi 调用指定的请求处理函数
|
// PreprocessRequestApi 调用指定的请求处理函数
|
||||||
func (a *ApiRequestService) PreprocessRequestApi(ctx context.Context, apiCode string, params []byte, options *commands.ApiCallOptions, callContext *processors.CallContext) ([]byte, error) {
|
func (a *ApiRequestService) PreprocessRequestApi(ctx context.Context, apiCode string, params []byte, options *commands.ApiCallOptions, callContext *processors.CallContext) ([]byte, error) {
|
||||||
if processor, exists := RequestProcessors[apiCode]; exists {
|
|
||||||
// 设置Options和CallContext到依赖容器
|
// 设置Options和CallContext到依赖容器
|
||||||
deps := a.processorDeps.WithOptions(options).WithCallContext(callContext)
|
deps := a.processorDeps.WithOptions(options).WithCallContext(callContext)
|
||||||
|
|
||||||
|
// 1. 优先查找已注册的自定义处理器
|
||||||
|
if processor, exists := RequestProcessors[apiCode]; exists {
|
||||||
return processor(ctx, params, deps)
|
return processor(ctx, params, deps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. 检查是否为组合包(COMB开头),使用通用组合包处理器
|
||||||
|
if len(apiCode) >= 4 && apiCode[:4] == "COMB" {
|
||||||
|
return a.processGenericCombRequest(ctx, apiCode, params, deps)
|
||||||
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("%s: 未找到处理器: %s", ErrSystem, apiCode)
|
return nil, fmt.Errorf("%s: 未找到处理器: %s", ErrSystem, apiCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// processGenericCombRequest 通用组合包处理器
|
||||||
|
func (a *ApiRequestService) processGenericCombRequest(ctx context.Context, apiCode string, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
|
// 调用组合包服务处理请求
|
||||||
|
// 这里不需要验证参数,因为组合包的参数验证由各个子处理器负责
|
||||||
|
combinedResult, err := deps.CombService.ProcessCombRequest(ctx, params, deps, apiCode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接返回组合结果,无任何自定义处理
|
||||||
|
return json.Marshal(combinedResult)
|
||||||
|
}
|
||||||
|
|||||||
@@ -88,6 +88,10 @@ func (s *FormConfigServiceImpl) getDTOStruct(apiCode string) interface{} {
|
|||||||
"QYGL8271": &dto.QYGL8271Req{},
|
"QYGL8271": &dto.QYGL8271Req{},
|
||||||
"QYGLB4C0": &dto.QYGLB4C0Req{},
|
"QYGLB4C0": &dto.QYGLB4C0Req{},
|
||||||
"QYGL23T7": &dto.QYGL23T7Req{},
|
"QYGL23T7": &dto.QYGL23T7Req{},
|
||||||
|
"QYGL5A3C": &dto.QYGL5A3CReq{},
|
||||||
|
"QYGL8B4D": &dto.QYGL8B4DReq{},
|
||||||
|
"QYGL9E2F": &dto.QYGL9E2FReq{},
|
||||||
|
"QYGL7C1A": &dto.QYGL7C1AReq{},
|
||||||
"YYSY4B37": &dto.YYSY4B37Req{},
|
"YYSY4B37": &dto.YYSY4B37Req{},
|
||||||
"YYSY4B21": &dto.YYSY4B21Req{},
|
"YYSY4B21": &dto.YYSY4B21Req{},
|
||||||
"YYSY6F2E": &dto.YYSY6F2EReq{},
|
"YYSY6F2E": &dto.YYSY6F2EReq{},
|
||||||
@@ -131,7 +135,19 @@ func (s *FormConfigServiceImpl) getDTOStruct(apiCode string) interface{} {
|
|||||||
"FLXG8B4D": &dto.FLXG8B4DReq{},
|
"FLXG8B4D": &dto.FLXG8B4DReq{},
|
||||||
}
|
}
|
||||||
|
|
||||||
return dtoMap[apiCode]
|
// 优先返回已配置的DTO
|
||||||
|
if dto, exists := dtoMap[apiCode]; exists {
|
||||||
|
return dto
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否为通用组合包(COMB开头且未单独配置)
|
||||||
|
if len(apiCode) >= 4 && apiCode[:4] == "COMB" {
|
||||||
|
// 对于通用组合包,返回一个通用的空结构体,表示无需特定参数验证
|
||||||
|
// 因为组合包的参数验证由各个子处理器负责
|
||||||
|
return &struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseDTOFields 通过反射解析DTO结构体字段
|
// parseDTOFields 通过反射解析DTO结构体字段
|
||||||
|
|||||||
74
internal/domains/api/services/processors/comb/README.md
Normal file
74
internal/domains/api/services/processors/comb/README.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# 组合包处理器说明
|
||||||
|
|
||||||
|
## 🚀 动态组合包机制
|
||||||
|
|
||||||
|
从现在开始,组合包支持**动态处理机制**,大大简化了组合包的开发和维护工作。
|
||||||
|
|
||||||
|
## 📋 工作原理
|
||||||
|
|
||||||
|
### 1. 自动识别
|
||||||
|
- 所有以 `COMB` 开头的API编码会被自动识别为组合包
|
||||||
|
- 系统会自动调用通用组合包处理器处理请求
|
||||||
|
|
||||||
|
### 2. 处理流程
|
||||||
|
1. **优先级检查**:首先检查是否有注册的自定义处理器
|
||||||
|
2. **通用处理**:如果没有自定义处理器,且API编码以COMB开头,使用通用处理器
|
||||||
|
3. **数据库驱动**:根据数据库中的组合包配置自动调用相应的子产品处理器
|
||||||
|
|
||||||
|
## 🛠️ 使用方式
|
||||||
|
|
||||||
|
### 普通组合包(无自定义逻辑)
|
||||||
|
**只需要在数据库配置,无需编写任何代码!**
|
||||||
|
|
||||||
|
1. 在 `products` 表中创建组合包产品:
|
||||||
|
```sql
|
||||||
|
INSERT INTO products (code, name, is_package, ...)
|
||||||
|
VALUES ('COMB1234', '新组合包', true, ...);
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 在 `product_package_items` 表中配置子产品:
|
||||||
|
```sql
|
||||||
|
INSERT INTO product_package_items (package_id, product_id, sort_order)
|
||||||
|
VALUES
|
||||||
|
('组合包产品ID', '子产品1ID', 1),
|
||||||
|
('组合包产品ID', '子产品2ID', 2);
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **直接调用**:无需任何额外编码,API立即可用!
|
||||||
|
|
||||||
|
### 自定义组合包(有特殊逻辑)
|
||||||
|
如果需要对组合包结果进行后处理,才需要编写代码:
|
||||||
|
|
||||||
|
1. **创建处理器文件**:`combXXXX_processor.go`
|
||||||
|
2. **注册处理器**:在 `api_request_service.go` 中注册
|
||||||
|
3. **实现自定义逻辑**:在处理器中实现特殊业务逻辑
|
||||||
|
|
||||||
|
## 📁 现有组合包示例
|
||||||
|
|
||||||
|
### COMB86PM(自定义处理器)
|
||||||
|
```go
|
||||||
|
// 有自定义逻辑:重命名子产品ApiCode
|
||||||
|
for _, resp := range combinedResult.Responses {
|
||||||
|
if resp.ApiCode == "FLXGBC21" {
|
||||||
|
resp.ApiCode = "FLXG54F5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### COMB298Y(通用处理器)
|
||||||
|
- **无需编码**:已删除专门的处理器文件
|
||||||
|
- **自动处理**:通过数据库配置自动工作
|
||||||
|
|
||||||
|
## ✅ 优势
|
||||||
|
|
||||||
|
1. **零配置**:普通组合包只需数据库配置,无需编码
|
||||||
|
2. **灵活性**:特殊需求仍可通过自定义处理器实现
|
||||||
|
3. **维护性**:减少重复代码,统一处理逻辑
|
||||||
|
4. **扩展性**:新增组合包极其简单,配置即用
|
||||||
|
|
||||||
|
## 🔧 开发建议
|
||||||
|
|
||||||
|
1. **优先使用通用处理器**:除非有特殊业务逻辑,否则不要编写自定义处理器
|
||||||
|
2. **命名规范**:组合包编码必须以 `COMB` 开头
|
||||||
|
3. **数据库配置**:确保组合包在数据库中正确配置了 `is_package=true` 和子产品关系
|
||||||
|
4. **排序控制**:通过 `sort_order` 字段控制子产品在响应中的顺序
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package comb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"tyapi-server/internal/domains/api/dto"
|
|
||||||
"tyapi-server/internal/domains/api/services/processors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProcessCOMB298YRequest COMB298Y API处理方法
|
|
||||||
func ProcessCOMB298YRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
|
||||||
var paramsDto dto.COMB298YReq
|
|
||||||
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
|
|
||||||
return nil, errors.Join(processors.ErrInvalidParam, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 调用组合包服务处理请求
|
|
||||||
// Options会自动传递给所有子处理器
|
|
||||||
combinedResult, err := deps.CombService.ProcessCombRequest(ctx, params, deps, "COMB298Y")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return json.Marshal(combinedResult)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package qygl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"tyapi-server/internal/domains/api/dto"
|
||||||
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessQYGL5A3CRequest QYGL5A3C API处理方法 - 对外投资历史
|
||||||
|
func ProcessQYGL5A3CRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
|
var paramsDto dto.QYGL5A3CReq
|
||||||
|
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置默认值
|
||||||
|
pageSize := paramsDto.PageSize
|
||||||
|
if pageSize == 0 {
|
||||||
|
pageSize = 20
|
||||||
|
}
|
||||||
|
pageNum := paramsDto.PageNum
|
||||||
|
if pageNum == 0 {
|
||||||
|
pageNum = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建API调用参数
|
||||||
|
apiParams := map[string]string{
|
||||||
|
"keyword": paramsDto.EntCode,
|
||||||
|
"pageSize": strconv.Itoa(pageSize),
|
||||||
|
"pageNum": strconv.Itoa(pageNum),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用天眼查API - 对外投资历史
|
||||||
|
response, err := deps.TianYanChaService.CallAPI(ctx, "InvestHistory", apiParams)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "数据源异常" {
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
|
} else {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查天眼查API调用是否成功
|
||||||
|
if !response.Success {
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, errors.New(response.Message))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回天眼查响应数据
|
||||||
|
respBytes, err := json.Marshal(response.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return respBytes, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package qygl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"tyapi-server/internal/domains/api/dto"
|
||||||
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessQYGL7C1ARequest QYGL7C1A API处理方法 - 经营异常
|
||||||
|
func ProcessQYGL7C1ARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
|
var paramsDto dto.QYGL7C1AReq
|
||||||
|
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置默认值
|
||||||
|
pageSize := paramsDto.PageSize
|
||||||
|
if pageSize == 0 {
|
||||||
|
pageSize = 20
|
||||||
|
}
|
||||||
|
pageNum := paramsDto.PageNum
|
||||||
|
if pageNum == 0 {
|
||||||
|
pageNum = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建API调用参数
|
||||||
|
apiParams := map[string]string{
|
||||||
|
"keyword": paramsDto.EntCode,
|
||||||
|
"pageSize": strconv.Itoa(pageSize),
|
||||||
|
"pageNum": strconv.Itoa(pageNum),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用天眼查API - 经营异常
|
||||||
|
response, err := deps.TianYanChaService.CallAPI(ctx, "AbnormalInfo", apiParams)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "数据源异常" {
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
|
} else {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查天眼查API调用是否成功
|
||||||
|
if !response.Success {
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, errors.New(response.Message))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回天眼查响应数据
|
||||||
|
respBytes, err := json.Marshal(response.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return respBytes, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package qygl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"tyapi-server/internal/domains/api/dto"
|
||||||
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessQYGL8B4DRequest QYGL8B4D API处理方法 - 融资历史
|
||||||
|
func ProcessQYGL8B4DRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
|
var paramsDto dto.QYGL8B4DReq
|
||||||
|
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置默认值
|
||||||
|
pageSize := paramsDto.PageSize
|
||||||
|
if pageSize == 0 {
|
||||||
|
pageSize = 20
|
||||||
|
}
|
||||||
|
pageNum := paramsDto.PageNum
|
||||||
|
if pageNum == 0 {
|
||||||
|
pageNum = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建API调用参数
|
||||||
|
apiParams := map[string]string{
|
||||||
|
"keyword": paramsDto.EntCode,
|
||||||
|
"pageSize": strconv.Itoa(pageSize),
|
||||||
|
"pageNum": strconv.Itoa(pageNum),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用天眼查API - 融资历史
|
||||||
|
response, err := deps.TianYanChaService.CallAPI(ctx, "FinancingHistory", apiParams)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "数据源异常" {
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
|
} else {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查天眼查API调用是否成功
|
||||||
|
if !response.Success {
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, errors.New(response.Message))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回天眼查响应数据
|
||||||
|
respBytes, err := json.Marshal(response.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return respBytes, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package qygl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"tyapi-server/internal/domains/api/dto"
|
||||||
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessQYGL9E2FRequest QYGL9E2F API处理方法 - 行政处罚
|
||||||
|
func ProcessQYGL9E2FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
|
var paramsDto dto.QYGL9E2FReq
|
||||||
|
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置默认值
|
||||||
|
pageSize := paramsDto.PageSize
|
||||||
|
if pageSize == 0 {
|
||||||
|
pageSize = 20
|
||||||
|
}
|
||||||
|
pageNum := paramsDto.PageNum
|
||||||
|
if pageNum == 0 {
|
||||||
|
pageNum = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建API调用参数
|
||||||
|
apiParams := map[string]string{
|
||||||
|
"keyword": paramsDto.EntCode,
|
||||||
|
"pageSize": strconv.Itoa(pageSize),
|
||||||
|
"pageNum": strconv.Itoa(pageNum),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用天眼查API - 行政处罚
|
||||||
|
response, err := deps.TianYanChaService.CallAPI(ctx, "PunishmentInfo", apiParams)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "数据源异常" {
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
|
} else {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查天眼查API调用是否成功
|
||||||
|
if !response.Success {
|
||||||
|
return nil, errors.Join(processors.ErrDatasource, errors.New(response.Message))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回天眼查响应数据
|
||||||
|
respBytes, err := json.Marshal(response.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return respBytes, nil
|
||||||
|
}
|
||||||
@@ -22,6 +22,10 @@ var (
|
|||||||
// APIEndpoints 天眼查 API 端点映射
|
// APIEndpoints 天眼查 API 端点映射
|
||||||
var APIEndpoints = map[string]string{
|
var APIEndpoints = map[string]string{
|
||||||
"VerifyThreeElements": "/open/ic/verify/2.0", // 企业三要素验证
|
"VerifyThreeElements": "/open/ic/verify/2.0", // 企业三要素验证
|
||||||
|
"InvestHistory": "/open/hi/invest/2.0", // 对外投资历史
|
||||||
|
"FinancingHistory": "/open/cd/findHistoryRongzi/2.0", // 融资历史
|
||||||
|
"PunishmentInfo": "/open/mr/punishmentInfo/3.0", // 行政处罚
|
||||||
|
"AbnormalInfo": "/open/mr/abnormal/2.0", // 经营异常
|
||||||
}
|
}
|
||||||
|
|
||||||
// TianYanChaConfig 天眼查配置
|
// TianYanChaConfig 天眼查配置
|
||||||
|
|||||||
Reference in New Issue
Block a user