968 lines
31 KiB
Go
968 lines
31 KiB
Go
package container
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"time"
|
||
|
||
"go.uber.org/fx"
|
||
"go.uber.org/zap"
|
||
"go.uber.org/zap/zapcore"
|
||
"gorm.io/gorm"
|
||
|
||
"tyapi-server/internal/application/article"
|
||
"tyapi-server/internal/application/certification"
|
||
"tyapi-server/internal/application/finance"
|
||
"tyapi-server/internal/application/product"
|
||
"tyapi-server/internal/application/user"
|
||
"tyapi-server/internal/config"
|
||
domain_article_repo "tyapi-server/internal/domains/article/repositories"
|
||
article_service "tyapi-server/internal/domains/article/services"
|
||
domain_certification_repo "tyapi-server/internal/domains/certification/repositories"
|
||
certification_service "tyapi-server/internal/domains/certification/services"
|
||
domain_finance_repo "tyapi-server/internal/domains/finance/repositories"
|
||
finance_service "tyapi-server/internal/domains/finance/services"
|
||
domain_product_repo "tyapi-server/internal/domains/product/repositories"
|
||
product_service "tyapi-server/internal/domains/product/services"
|
||
user_service "tyapi-server/internal/domains/user/services"
|
||
"tyapi-server/internal/infrastructure/cache"
|
||
"tyapi-server/internal/infrastructure/database"
|
||
article_repo "tyapi-server/internal/infrastructure/database/repositories/article"
|
||
certification_repo "tyapi-server/internal/infrastructure/database/repositories/certification"
|
||
finance_repo "tyapi-server/internal/infrastructure/database/repositories/finance"
|
||
product_repo "tyapi-server/internal/infrastructure/database/repositories/product"
|
||
infra_events "tyapi-server/internal/infrastructure/events"
|
||
"tyapi-server/internal/infrastructure/external/alicloud"
|
||
"tyapi-server/internal/infrastructure/external/email"
|
||
"tyapi-server/internal/infrastructure/external/ocr"
|
||
"tyapi-server/internal/infrastructure/external/sms"
|
||
"tyapi-server/internal/infrastructure/external/storage"
|
||
"tyapi-server/internal/infrastructure/external/tianyancha"
|
||
"tyapi-server/internal/infrastructure/external/westdex"
|
||
"tyapi-server/internal/infrastructure/external/yushan"
|
||
"tyapi-server/internal/infrastructure/external/zhicha"
|
||
"tyapi-server/internal/infrastructure/http/handlers"
|
||
"tyapi-server/internal/infrastructure/http/routes"
|
||
"tyapi-server/internal/infrastructure/task"
|
||
shared_database "tyapi-server/internal/shared/database"
|
||
"tyapi-server/internal/shared/esign"
|
||
"tyapi-server/internal/shared/events"
|
||
"tyapi-server/internal/shared/health"
|
||
"tyapi-server/internal/shared/hooks"
|
||
sharedhttp "tyapi-server/internal/shared/http"
|
||
"tyapi-server/internal/shared/interfaces"
|
||
"tyapi-server/internal/shared/logger"
|
||
"tyapi-server/internal/shared/metrics"
|
||
"tyapi-server/internal/shared/middleware"
|
||
sharedOCR "tyapi-server/internal/shared/ocr"
|
||
"tyapi-server/internal/shared/payment"
|
||
"tyapi-server/internal/shared/resilience"
|
||
"tyapi-server/internal/shared/saga"
|
||
"tyapi-server/internal/shared/tracing"
|
||
"tyapi-server/internal/shared/validator"
|
||
|
||
domain_user_repo "tyapi-server/internal/domains/user/repositories"
|
||
user_repo "tyapi-server/internal/infrastructure/database/repositories/user"
|
||
|
||
"github.com/redis/go-redis/v9"
|
||
|
||
api_app "tyapi-server/internal/application/api"
|
||
domain_api_repo "tyapi-server/internal/domains/api/repositories"
|
||
api_service "tyapi-server/internal/domains/api/services"
|
||
api_repo "tyapi-server/internal/infrastructure/database/repositories/api"
|
||
)
|
||
|
||
// Container 应用容器
|
||
type Container struct {
|
||
App *fx.App
|
||
}
|
||
|
||
// NewContainer 创建新的应用容器
|
||
func NewContainer() *Container {
|
||
app := fx.New(
|
||
// 配置模块
|
||
fx.Provide(
|
||
config.LoadConfig,
|
||
),
|
||
|
||
// 基础设施模块
|
||
fx.Provide(
|
||
// 日志器 - 提供自定义Logger和*zap.Logger
|
||
func(cfg *config.Config) (logger.Logger, error) {
|
||
// 将 config.LoggerConfig 转换为 logger.Config
|
||
// 转换 LevelConfigs 类型
|
||
levelConfigs := make(map[string]interface{})
|
||
for key, value := range cfg.Logger.LevelConfigs {
|
||
levelConfigs[key] = value
|
||
}
|
||
|
||
logCfg := logger.Config{
|
||
Level: cfg.Logger.Level,
|
||
Format: cfg.Logger.Format,
|
||
Output: cfg.Logger.Output,
|
||
LogDir: cfg.Logger.LogDir,
|
||
MaxSize: cfg.Logger.MaxSize,
|
||
MaxBackups: cfg.Logger.MaxBackups,
|
||
MaxAge: cfg.Logger.MaxAge,
|
||
Compress: cfg.Logger.Compress,
|
||
UseDaily: cfg.Logger.UseDaily,
|
||
UseColor: cfg.Logger.UseColor,
|
||
EnableLevelSeparation: cfg.Logger.EnableLevelSeparation,
|
||
LevelConfigs: levelConfigs,
|
||
Development: cfg.App.Env == "development",
|
||
}
|
||
|
||
// 初始化全局日志器
|
||
if err := logger.InitGlobalLogger(logCfg); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if cfg.Logger.EnableLevelSeparation {
|
||
// 使用按级别分文件的日志器
|
||
levelConfig := logger.LevelLoggerConfig{
|
||
BaseConfig: logCfg,
|
||
EnableLevelSeparation: true,
|
||
LevelConfigs: convertLevelConfigs(cfg.Logger.LevelConfigs),
|
||
}
|
||
return logger.NewLevelLogger(levelConfig)
|
||
} else {
|
||
// 使用普通日志器
|
||
return logger.NewLogger(logCfg)
|
||
}
|
||
},
|
||
// 提供普通的*zap.Logger(用于大多数场景)
|
||
fx.Annotate(
|
||
func(log logger.Logger) *zap.Logger {
|
||
// 尝试转换为ZapLogger
|
||
if zapLogger, ok := log.(*logger.ZapLogger); ok {
|
||
return zapLogger.GetZapLogger()
|
||
}
|
||
// 尝试转换为LevelLogger
|
||
if levelLogger, ok := log.(*logger.LevelLogger); ok {
|
||
// 获取Info级别的日志器作为默认
|
||
if infoLogger := levelLogger.GetLevelLogger(zapcore.InfoLevel); infoLogger != nil {
|
||
return infoLogger
|
||
}
|
||
}
|
||
// 如果类型转换失败,使用全局日志器
|
||
return logger.GetGlobalLogger()
|
||
},
|
||
),
|
||
|
||
// 数据库连接
|
||
func(cfg *config.Config, cacheService interfaces.CacheService, logger *zap.Logger) (*gorm.DB, error) {
|
||
dbCfg := database.Config{
|
||
Host: cfg.Database.Host,
|
||
Port: cfg.Database.Port,
|
||
User: cfg.Database.User,
|
||
Password: cfg.Database.Password,
|
||
Name: cfg.Database.Name,
|
||
SSLMode: cfg.Database.SSLMode,
|
||
Timezone: cfg.Database.Timezone,
|
||
MaxOpenConns: cfg.Database.MaxOpenConns,
|
||
MaxIdleConns: cfg.Database.MaxIdleConns,
|
||
ConnMaxLifetime: cfg.Database.ConnMaxLifetime,
|
||
}
|
||
db, err := database.NewConnection(dbCfg)
|
||
if err != nil {
|
||
logger.Error("数据库连接失败",
|
||
zap.String("host", cfg.Database.Host),
|
||
zap.String("port", cfg.Database.Port),
|
||
zap.String("database", cfg.Database.Name),
|
||
zap.String("user", cfg.Database.User),
|
||
zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
logger.Info("数据库连接成功",
|
||
zap.String("host", cfg.Database.Host),
|
||
zap.String("port", cfg.Database.Port),
|
||
zap.String("database", cfg.Database.Name))
|
||
|
||
// 设置GORM缓存插件
|
||
if err := SetupGormCache(db.DB, cacheService, cfg, logger); err != nil {
|
||
logger.Warn("GORM缓存插件设置失败", zap.Error(err))
|
||
// 不返回错误,允许系统在没有缓存的情况下运行
|
||
}
|
||
|
||
return db.DB, nil
|
||
},
|
||
// Redis客户端
|
||
NewRedisClient,
|
||
// 缓存服务
|
||
fx.Annotate(NewRedisCache, fx.As(new(interfaces.CacheService))),
|
||
// 事件总线
|
||
// 提供workerCount参数
|
||
func() int {
|
||
return 5 // 默认5个工作协程
|
||
},
|
||
fx.Annotate(
|
||
events.NewMemoryEventBus,
|
||
fx.As(new(interfaces.EventBus)),
|
||
),
|
||
// 健康检查
|
||
health.NewHealthChecker,
|
||
// 提供 config.SMSConfig
|
||
func(cfg *config.Config) config.SMSConfig {
|
||
return cfg.SMS
|
||
},
|
||
// 提供 config.AppConfig
|
||
func(cfg *config.Config) config.AppConfig {
|
||
return cfg.App
|
||
},
|
||
// 事务管理器
|
||
func(db *gorm.DB, logger *zap.Logger) *shared_database.TransactionManager {
|
||
return shared_database.NewTransactionManager(db, logger)
|
||
},
|
||
// 短信服务
|
||
sms.NewAliSMSService,
|
||
// 邮件服务
|
||
fx.Annotate(
|
||
func(cfg *config.Config, logger *zap.Logger) *email.QQEmailService {
|
||
return email.NewQQEmailService(cfg.Email, logger)
|
||
},
|
||
),
|
||
// 存储服务
|
||
fx.Annotate(
|
||
func(cfg *config.Config, logger *zap.Logger) *storage.QiNiuStorageService {
|
||
return storage.NewQiNiuStorageService(
|
||
cfg.Storage.AccessKey,
|
||
cfg.Storage.SecretKey,
|
||
cfg.Storage.Bucket,
|
||
cfg.Storage.Domain,
|
||
logger,
|
||
)
|
||
},
|
||
),
|
||
// OCR服务
|
||
fx.Annotate(
|
||
func(cfg *config.Config, logger *zap.Logger) *ocr.BaiduOCRService {
|
||
return ocr.NewBaiduOCRService(
|
||
cfg.OCR.APIKey,
|
||
cfg.OCR.SecretKey,
|
||
logger,
|
||
)
|
||
},
|
||
fx.As(new(sharedOCR.OCRService)),
|
||
),
|
||
// e签宝配置
|
||
func(cfg *config.Config) (*esign.Config, error) {
|
||
return esign.NewConfig(
|
||
cfg.Esign.AppID,
|
||
cfg.Esign.AppSecret,
|
||
cfg.Esign.ServerURL,
|
||
cfg.Esign.TemplateID,
|
||
&esign.EsignContractConfig{
|
||
Name: cfg.Esign.Contract.Name,
|
||
ExpireDays: cfg.Esign.Contract.ExpireDays,
|
||
RetryCount: cfg.Esign.Contract.RetryCount,
|
||
},
|
||
&esign.EsignAuthConfig{
|
||
OrgAuthModes: cfg.Esign.Auth.OrgAuthModes,
|
||
DefaultAuthMode: cfg.Esign.Auth.DefaultAuthMode,
|
||
PsnAuthModes: cfg.Esign.Auth.PsnAuthModes,
|
||
WillingnessAuthModes: cfg.Esign.Auth.WillingnessAuthModes,
|
||
RedirectUrl: cfg.Esign.Auth.RedirectURL,
|
||
},
|
||
&esign.EsignSignConfig{
|
||
AutoFinish: cfg.Esign.Sign.AutoFinish,
|
||
SignFieldStyle: cfg.Esign.Sign.SignFieldStyle,
|
||
ClientType: cfg.Esign.Sign.ClientType,
|
||
RedirectUrl: cfg.Esign.Sign.RedirectURL,
|
||
},
|
||
)
|
||
},
|
||
// e签宝服务
|
||
func(esignConfig *esign.Config) *esign.Client {
|
||
return esign.NewClient(esignConfig)
|
||
},
|
||
// 支付宝支付服务
|
||
func(cfg *config.Config) *payment.AliPayService {
|
||
config := payment.AlipayConfig{
|
||
AppID: cfg.AliPay.AppID,
|
||
PrivateKey: cfg.AliPay.PrivateKey,
|
||
AlipayPublicKey: cfg.AliPay.AlipayPublicKey,
|
||
IsProduction: cfg.AliPay.IsProduction,
|
||
NotifyUrl: cfg.AliPay.NotifyURL,
|
||
ReturnURL: cfg.AliPay.ReturnURL,
|
||
}
|
||
return payment.NewAliPayService(config)
|
||
},
|
||
),
|
||
|
||
// 高级特性模块
|
||
fx.Provide(
|
||
// 提供TracerConfig
|
||
func(cfg *config.Config) tracing.TracerConfig {
|
||
return tracing.TracerConfig{
|
||
ServiceName: cfg.App.Name,
|
||
ServiceVersion: cfg.App.Version,
|
||
Environment: cfg.App.Env,
|
||
Endpoint: cfg.Monitoring.TracingEndpoint,
|
||
SampleRate: cfg.Monitoring.SampleRate,
|
||
Enabled: cfg.Monitoring.TracingEnabled,
|
||
}
|
||
},
|
||
tracing.NewTracer,
|
||
metrics.NewPrometheusMetrics,
|
||
metrics.NewBusinessMetrics,
|
||
resilience.NewWrapper,
|
||
resilience.NewRetryerWrapper,
|
||
saga.NewSagaManager,
|
||
hooks.NewHookSystem,
|
||
),
|
||
|
||
// HTTP基础组件
|
||
fx.Provide(
|
||
sharedhttp.NewResponseBuilder,
|
||
validator.NewRequestValidator,
|
||
// WestDexService - 需要从配置中获取参数
|
||
func(cfg *config.Config) (*westdex.WestDexService, error) {
|
||
return westdex.NewWestDexServiceWithConfig(cfg)
|
||
},
|
||
// ZhichaService - 智查金控服务
|
||
func(cfg *config.Config) (*zhicha.ZhichaService, error) {
|
||
return zhicha.NewZhichaServiceWithConfig(cfg)
|
||
},
|
||
func(cfg *config.Config) *yushan.YushanService {
|
||
return yushan.NewYushanService(
|
||
cfg.Yushan.URL,
|
||
cfg.Yushan.APIKey,
|
||
cfg.Yushan.AcctID,
|
||
nil, // 暂时不传入logger,使用无日志版本
|
||
)
|
||
},
|
||
// TianYanChaService - 天眼查服务
|
||
func(cfg *config.Config) *tianyancha.TianYanChaService {
|
||
return tianyancha.NewTianYanChaService(
|
||
cfg.TianYanCha.BaseURL, // 天眼查API基础URL
|
||
cfg.TianYanCha.APIKey,
|
||
30*time.Second, // 默认超时时间
|
||
)
|
||
},
|
||
// AlicloudService - 阿里云服务
|
||
func(cfg *config.Config) *alicloud.AlicloudService {
|
||
return alicloud.NewAlicloudService(
|
||
cfg.Alicloud.Host,
|
||
cfg.Alicloud.AppCode,
|
||
)
|
||
},
|
||
sharedhttp.NewGinRouter,
|
||
),
|
||
|
||
// 中间件组件
|
||
fx.Provide(
|
||
middleware.NewRequestIDMiddleware,
|
||
middleware.NewSecurityHeadersMiddleware,
|
||
middleware.NewResponseTimeMiddleware,
|
||
middleware.NewCORSMiddleware,
|
||
middleware.NewRateLimitMiddleware,
|
||
// 每日限流中间件
|
||
func(cfg *config.Config, redis *redis.Client, response interfaces.ResponseBuilder, logger *zap.Logger) *middleware.DailyRateLimitMiddleware {
|
||
limitConfig := middleware.DailyRateLimitConfig{
|
||
MaxRequestsPerDay: cfg.DailyRateLimit.MaxRequestsPerDay,
|
||
MaxRequestsPerIP: cfg.DailyRateLimit.MaxRequestsPerIP,
|
||
KeyPrefix: cfg.DailyRateLimit.KeyPrefix,
|
||
TTL: cfg.DailyRateLimit.TTL,
|
||
MaxConcurrent: cfg.DailyRateLimit.MaxConcurrent,
|
||
// 安全配置
|
||
EnableIPWhitelist: cfg.DailyRateLimit.EnableIPWhitelist,
|
||
IPWhitelist: cfg.DailyRateLimit.IPWhitelist,
|
||
EnableIPBlacklist: cfg.DailyRateLimit.EnableIPBlacklist,
|
||
IPBlacklist: cfg.DailyRateLimit.IPBlacklist,
|
||
EnableUserAgent: cfg.DailyRateLimit.EnableUserAgent,
|
||
BlockedUserAgents: cfg.DailyRateLimit.BlockedUserAgents,
|
||
EnableReferer: cfg.DailyRateLimit.EnableReferer,
|
||
AllowedReferers: cfg.DailyRateLimit.AllowedReferers,
|
||
EnableGeoBlock: cfg.DailyRateLimit.EnableGeoBlock,
|
||
BlockedCountries: cfg.DailyRateLimit.BlockedCountries,
|
||
EnableProxyCheck: cfg.DailyRateLimit.EnableProxyCheck,
|
||
}
|
||
return middleware.NewDailyRateLimitMiddleware(cfg, redis, response, logger, limitConfig)
|
||
},
|
||
NewRequestLoggerMiddlewareWrapper,
|
||
middleware.NewJWTAuthMiddleware,
|
||
middleware.NewOptionalAuthMiddleware,
|
||
middleware.NewAdminAuthMiddleware,
|
||
middleware.NewDomainAuthMiddleware,
|
||
middleware.NewTraceIDMiddleware,
|
||
middleware.NewErrorTrackingMiddleware,
|
||
NewRequestBodyLoggerMiddlewareWrapper,
|
||
// 新增的中间件
|
||
func(logger *zap.Logger) *middleware.PanicRecoveryMiddleware {
|
||
return middleware.NewPanicRecoveryMiddleware(logger)
|
||
},
|
||
func(logger *zap.Logger, cfg *config.Config) *middleware.ComprehensiveLoggerMiddleware {
|
||
config := &middleware.ComprehensiveLoggerConfig{
|
||
EnableRequestLogging: true,
|
||
EnableResponseLogging: true,
|
||
EnableRequestBodyLogging: cfg.App.IsDevelopment(), // 开发环境记录请求体
|
||
EnableErrorLogging: true,
|
||
EnableBusinessLogging: true,
|
||
EnablePerformanceLogging: true,
|
||
MaxBodySize: 1024 * 10, // 10KB
|
||
ExcludePaths: []string{"/health", "/metrics", "/favicon.ico", "/swagger"},
|
||
}
|
||
return middleware.NewComprehensiveLoggerMiddleware(logger, config)
|
||
},
|
||
// 业务日志记录器
|
||
func(logger *zap.Logger) *middleware.BusinessLogger {
|
||
return middleware.NewBusinessLogger(logger)
|
||
},
|
||
),
|
||
|
||
// 仓储层 - 用户域
|
||
fx.Provide(
|
||
// 用户仓储 - 同时注册具体类型和接口类型
|
||
fx.Annotate(
|
||
user_repo.NewGormUserRepository,
|
||
fx.As(new(domain_user_repo.UserRepository)),
|
||
),
|
||
|
||
// 短信验证码仓储 - 同时注册具体类型和接口类型
|
||
fx.Annotate(
|
||
user_repo.NewGormSMSCodeRepository,
|
||
fx.As(new(domain_user_repo.SMSCodeRepository)),
|
||
),
|
||
// 用户信息仓储 - 同时注册具体类型和接口类型
|
||
fx.Annotate(
|
||
user_repo.NewGormEnterpriseInfoRepository,
|
||
fx.As(new(domain_user_repo.EnterpriseInfoRepository)),
|
||
),
|
||
// 合同信息仓储 - 同时注册具体类型和接口类型
|
||
fx.Annotate(
|
||
user_repo.NewGormContractInfoRepository,
|
||
fx.As(new(domain_user_repo.ContractInfoRepository)),
|
||
),
|
||
),
|
||
|
||
// 仓储层 - 认证域
|
||
fx.Provide(
|
||
// 认证命令仓储
|
||
fx.Annotate(
|
||
certification_repo.NewGormCertificationCommandRepository,
|
||
fx.As(new(domain_certification_repo.CertificationCommandRepository)),
|
||
),
|
||
// 认证查询仓储
|
||
fx.Annotate(
|
||
certification_repo.NewGormCertificationQueryRepository,
|
||
fx.As(new(domain_certification_repo.CertificationQueryRepository)),
|
||
),
|
||
// 企业信息提交记录仓储
|
||
fx.Annotate(
|
||
certification_repo.NewGormEnterpriseInfoSubmitRecordRepository,
|
||
fx.As(new(domain_certification_repo.EnterpriseInfoSubmitRecordRepository)),
|
||
),
|
||
),
|
||
|
||
// 仓储层 - 财务域
|
||
fx.Provide(
|
||
// 钱包仓储
|
||
fx.Annotate(
|
||
finance_repo.NewGormWalletRepository,
|
||
fx.As(new(domain_finance_repo.WalletRepository)),
|
||
),
|
||
// 钱包交易记录仓储
|
||
fx.Annotate(
|
||
finance_repo.NewGormWalletTransactionRepository,
|
||
fx.As(new(domain_finance_repo.WalletTransactionRepository)),
|
||
),
|
||
// 充值记录仓储
|
||
fx.Annotate(
|
||
finance_repo.NewGormRechargeRecordRepository,
|
||
fx.As(new(domain_finance_repo.RechargeRecordRepository)),
|
||
),
|
||
// 支付宝订单仓储
|
||
fx.Annotate(
|
||
finance_repo.NewGormAlipayOrderRepository,
|
||
fx.As(new(domain_finance_repo.AlipayOrderRepository)),
|
||
),
|
||
// 发票申请仓储
|
||
fx.Annotate(
|
||
finance_repo.NewGormInvoiceApplicationRepository,
|
||
fx.As(new(domain_finance_repo.InvoiceApplicationRepository)),
|
||
),
|
||
// 用户开票信息仓储
|
||
fx.Annotate(
|
||
finance_repo.NewGormUserInvoiceInfoRepository,
|
||
fx.As(new(domain_finance_repo.UserInvoiceInfoRepository)),
|
||
),
|
||
),
|
||
|
||
// 仓储层 - 产品域
|
||
fx.Provide(
|
||
// 产品仓储 - 同时注册具体类型和接口类型
|
||
fx.Annotate(
|
||
product_repo.NewGormProductRepository,
|
||
fx.As(new(domain_product_repo.ProductRepository)),
|
||
),
|
||
// 产品分类仓储 - 同时注册具体类型和接口类型
|
||
fx.Annotate(
|
||
product_repo.NewGormProductCategoryRepository,
|
||
fx.As(new(domain_product_repo.ProductCategoryRepository)),
|
||
),
|
||
// 订阅仓储 - 同时注册具体类型和接口类型
|
||
fx.Annotate(
|
||
product_repo.NewGormSubscriptionRepository,
|
||
fx.As(new(domain_product_repo.SubscriptionRepository)),
|
||
),
|
||
// 产品API配置仓储 - 同时注册具体类型和接口类型
|
||
fx.Annotate(
|
||
product_repo.NewGormProductApiConfigRepository,
|
||
fx.As(new(domain_product_repo.ProductApiConfigRepository)),
|
||
),
|
||
fx.Annotate(
|
||
product_repo.NewGormProductDocumentationRepository,
|
||
fx.As(new(domain_product_repo.ProductDocumentationRepository)),
|
||
),
|
||
),
|
||
|
||
// 仓储层 - 文章域
|
||
fx.Provide(
|
||
// 文章仓储 - 同时注册具体类型和接口类型
|
||
fx.Annotate(
|
||
article_repo.NewGormArticleRepository,
|
||
fx.As(new(domain_article_repo.ArticleRepository)),
|
||
),
|
||
// 分类仓储 - 同时注册具体类型和接口类型
|
||
fx.Annotate(
|
||
article_repo.NewGormCategoryRepository,
|
||
fx.As(new(domain_article_repo.CategoryRepository)),
|
||
),
|
||
// 标签仓储 - 同时注册具体类型和接口类型
|
||
fx.Annotate(
|
||
article_repo.NewGormTagRepository,
|
||
fx.As(new(domain_article_repo.TagRepository)),
|
||
),
|
||
),
|
||
|
||
// API域仓储层
|
||
fx.Provide(
|
||
fx.Annotate(
|
||
api_repo.NewGormApiUserRepository,
|
||
fx.As(new(domain_api_repo.ApiUserRepository)),
|
||
),
|
||
fx.Annotate(
|
||
api_repo.NewGormApiCallRepository,
|
||
fx.As(new(domain_api_repo.ApiCallRepository)),
|
||
),
|
||
),
|
||
|
||
// 领域服务
|
||
fx.Provide(
|
||
fx.Annotate(
|
||
user_service.NewUserAggregateService,
|
||
),
|
||
user_service.NewUserAuthService,
|
||
user_service.NewSMSCodeService,
|
||
user_service.NewContractAggregateService,
|
||
product_service.NewProductManagementService,
|
||
product_service.NewProductSubscriptionService,
|
||
product_service.NewProductApiConfigService,
|
||
product_service.NewProductDocumentationService,
|
||
finance_service.NewWalletAggregateService,
|
||
finance_service.NewRechargeRecordService,
|
||
// 发票领域服务
|
||
fx.Annotate(
|
||
finance_service.NewInvoiceDomainService,
|
||
),
|
||
// 用户开票信息服务
|
||
fx.Annotate(
|
||
finance_service.NewUserInvoiceInfoService,
|
||
),
|
||
// 发票事件发布器 - 绑定到接口
|
||
fx.Annotate(
|
||
func(logger *zap.Logger, eventBus interfaces.EventBus) finance_service.EventPublisher {
|
||
return infra_events.NewInvoiceEventPublisher(logger, eventBus)
|
||
},
|
||
fx.As(new(finance_service.EventPublisher)),
|
||
),
|
||
// 发票聚合服务 - 需要用户开票信息仓储
|
||
fx.Annotate(
|
||
func(
|
||
applicationRepo domain_finance_repo.InvoiceApplicationRepository,
|
||
userInvoiceInfoRepo domain_finance_repo.UserInvoiceInfoRepository,
|
||
domainService finance_service.InvoiceDomainService,
|
||
qiniuStorageService *storage.QiNiuStorageService,
|
||
logger *zap.Logger,
|
||
eventPublisher finance_service.EventPublisher,
|
||
) finance_service.InvoiceAggregateService {
|
||
return finance_service.NewInvoiceAggregateService(
|
||
applicationRepo,
|
||
userInvoiceInfoRepo,
|
||
domainService,
|
||
qiniuStorageService,
|
||
logger,
|
||
eventPublisher,
|
||
)
|
||
},
|
||
),
|
||
// 发票事件处理器
|
||
infra_events.NewInvoiceEventHandler,
|
||
certification_service.NewCertificationAggregateService,
|
||
certification_service.NewEnterpriseInfoSubmitRecordService,
|
||
// 文章领域服务
|
||
article_service.NewArticleService,
|
||
),
|
||
|
||
// API域服务层
|
||
fx.Provide(
|
||
api_service.NewApiUserAggregateService,
|
||
api_service.NewApiCallAggregateService,
|
||
api_service.NewApiRequestService,
|
||
api_service.NewFormConfigService,
|
||
),
|
||
|
||
// API域应用服务
|
||
fx.Provide(
|
||
api_app.NewApiApplicationService,
|
||
),
|
||
|
||
// 任务系统
|
||
fx.Provide(
|
||
// Asynq 客户端
|
||
func(cfg *config.Config, logger *zap.Logger) *task.AsynqClient {
|
||
redisAddr := fmt.Sprintf("%s:%d", cfg.Redis.Host, cfg.Redis.Port)
|
||
return task.NewAsynqClient(redisAddr, logger)
|
||
},
|
||
),
|
||
|
||
// 应用服务
|
||
fx.Provide(
|
||
// 用户应用服务 - 绑定到接口
|
||
fx.Annotate(
|
||
user.NewUserApplicationService,
|
||
fx.As(new(user.UserApplicationService)),
|
||
),
|
||
// 认证应用服务 - 绑定到接口
|
||
fx.Annotate(
|
||
certification.NewCertificationApplicationService,
|
||
fx.As(new(certification.CertificationApplicationService)),
|
||
),
|
||
// 财务应用服务 - 绑定到接口
|
||
fx.Annotate(
|
||
finance.NewFinanceApplicationService,
|
||
fx.As(new(finance.FinanceApplicationService)),
|
||
),
|
||
// 发票应用服务 - 绑定到接口
|
||
fx.Annotate(
|
||
finance.NewInvoiceApplicationService,
|
||
fx.As(new(finance.InvoiceApplicationService)),
|
||
),
|
||
// 管理员发票应用服务 - 绑定到接口
|
||
fx.Annotate(
|
||
finance.NewAdminInvoiceApplicationService,
|
||
fx.As(new(finance.AdminInvoiceApplicationService)),
|
||
),
|
||
// 产品应用服务 - 绑定到接口
|
||
fx.Annotate(
|
||
product.NewProductApplicationService,
|
||
fx.As(new(product.ProductApplicationService)),
|
||
),
|
||
// 产品API配置应用服务 - 绑定到接口
|
||
fx.Annotate(
|
||
product.NewProductApiConfigApplicationService,
|
||
fx.As(new(product.ProductApiConfigApplicationService)),
|
||
),
|
||
// 分类应用服务 - 绑定到接口
|
||
fx.Annotate(
|
||
product.NewCategoryApplicationService,
|
||
fx.As(new(product.CategoryApplicationService)),
|
||
),
|
||
fx.Annotate(
|
||
product.NewDocumentationApplicationService,
|
||
fx.As(new(product.DocumentationApplicationServiceInterface)),
|
||
),
|
||
// 订阅应用服务 - 绑定到接口
|
||
fx.Annotate(
|
||
product.NewSubscriptionApplicationService,
|
||
fx.As(new(product.SubscriptionApplicationService)),
|
||
),
|
||
// 文章应用服务 - 绑定到接口
|
||
fx.Annotate(
|
||
article.NewArticleApplicationService,
|
||
fx.As(new(article.ArticleApplicationService)),
|
||
),
|
||
),
|
||
|
||
// HTTP处理器
|
||
fx.Provide(
|
||
// 用户HTTP处理器
|
||
handlers.NewUserHandler,
|
||
// 认证HTTP处理器
|
||
handlers.NewCertificationHandler,
|
||
// 财务HTTP处理器
|
||
handlers.NewFinanceHandler,
|
||
// 产品HTTP处理器
|
||
handlers.NewProductHandler,
|
||
// 产品管理员HTTP处理器
|
||
handlers.NewProductAdminHandler,
|
||
// API Handler
|
||
handlers.NewApiHandler,
|
||
// 文章HTTP处理器
|
||
func(
|
||
appService article.ArticleApplicationService,
|
||
responseBuilder interfaces.ResponseBuilder,
|
||
validator interfaces.RequestValidator,
|
||
logger *zap.Logger,
|
||
) *handlers.ArticleHandler {
|
||
return handlers.NewArticleHandler(appService, responseBuilder, validator, logger)
|
||
},
|
||
),
|
||
|
||
// 路由注册
|
||
fx.Provide(
|
||
// 用户路由
|
||
routes.NewUserRoutes,
|
||
// 认证路由
|
||
routes.NewCertificationRoutes,
|
||
// 财务路由
|
||
routes.NewFinanceRoutes,
|
||
// 产品路由
|
||
routes.NewProductRoutes,
|
||
// 产品管理员路由
|
||
routes.NewProductAdminRoutes,
|
||
// API路由
|
||
// 文章路由
|
||
routes.NewArticleRoutes,
|
||
routes.NewApiRoutes,
|
||
),
|
||
|
||
// 应用生命周期
|
||
fx.Invoke(
|
||
RegisterLifecycleHooks,
|
||
RegisterMiddlewares,
|
||
RegisterRoutes,
|
||
RegisterEventHandlers,
|
||
),
|
||
)
|
||
|
||
return &Container{App: app}
|
||
}
|
||
|
||
// Start 启动容器
|
||
func (c *Container) Start() error {
|
||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||
defer cancel()
|
||
|
||
return c.App.Start(ctx)
|
||
}
|
||
|
||
// Stop 停止容器
|
||
func (c *Container) Stop() error {
|
||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||
defer cancel()
|
||
|
||
return c.App.Stop(ctx)
|
||
}
|
||
|
||
// RegisterLifecycleHooks 注册生命周期钩子
|
||
func RegisterLifecycleHooks(
|
||
lifecycle fx.Lifecycle,
|
||
logger *zap.Logger,
|
||
) {
|
||
lifecycle.Append(fx.Hook{
|
||
OnStart: func(context.Context) error {
|
||
logger.Info("应用启动中...")
|
||
logger.Info("所有依赖注入完成,开始启动应用服务")
|
||
|
||
// 确保校验器最先初始化
|
||
validator.InitGlobalValidator()
|
||
logger.Info("全局校验器初始化完成")
|
||
|
||
return nil
|
||
},
|
||
OnStop: func(context.Context) error {
|
||
logger.Info("应用关闭中...")
|
||
return nil
|
||
},
|
||
})
|
||
}
|
||
|
||
// RegisterMiddlewares 注册中间件
|
||
func RegisterMiddlewares(
|
||
router *sharedhttp.GinRouter,
|
||
panicRecovery *middleware.PanicRecoveryMiddleware,
|
||
comprehensiveLogger *middleware.ComprehensiveLoggerMiddleware,
|
||
requestID *middleware.RequestIDMiddleware,
|
||
security *middleware.SecurityHeadersMiddleware,
|
||
responseTime *middleware.ResponseTimeMiddleware,
|
||
cors *middleware.CORSMiddleware,
|
||
rateLimit *middleware.RateLimitMiddleware,
|
||
dailyRateLimit *middleware.DailyRateLimitMiddleware,
|
||
requestLogger *middleware.RequestLoggerMiddleware,
|
||
traceIDMiddleware *middleware.TraceIDMiddleware,
|
||
errorTrackingMiddleware *middleware.ErrorTrackingMiddleware,
|
||
requestBodyLogger *middleware.RequestBodyLoggerMiddleware,
|
||
) {
|
||
// 注册所有中间件(按优先级顺序)
|
||
router.RegisterMiddleware(panicRecovery)
|
||
router.RegisterMiddleware(comprehensiveLogger)
|
||
router.RegisterMiddleware(requestID)
|
||
router.RegisterMiddleware(security)
|
||
router.RegisterMiddleware(responseTime)
|
||
router.RegisterMiddleware(cors)
|
||
router.RegisterMiddleware(rateLimit)
|
||
router.RegisterMiddleware(dailyRateLimit)
|
||
router.RegisterMiddleware(requestLogger)
|
||
router.RegisterMiddleware(traceIDMiddleware)
|
||
router.RegisterMiddleware(errorTrackingMiddleware)
|
||
router.RegisterMiddleware(requestBodyLogger)
|
||
}
|
||
|
||
// RegisterRoutes 注册路由
|
||
func RegisterRoutes(
|
||
router *sharedhttp.GinRouter,
|
||
userRoutes *routes.UserRoutes,
|
||
certificationRoutes *routes.CertificationRoutes,
|
||
financeRoutes *routes.FinanceRoutes,
|
||
productRoutes *routes.ProductRoutes,
|
||
productAdminRoutes *routes.ProductAdminRoutes,
|
||
articleRoutes *routes.ArticleRoutes,
|
||
apiRoutes *routes.ApiRoutes,
|
||
cfg *config.Config,
|
||
logger *zap.Logger,
|
||
) {
|
||
router.SetupDefaultRoutes()
|
||
|
||
// api域名路由
|
||
apiRoutes.Register(router)
|
||
|
||
// 所有域名路由路由
|
||
userRoutes.Register(router)
|
||
certificationRoutes.Register(router)
|
||
financeRoutes.Register(router)
|
||
productRoutes.Register(router)
|
||
productAdminRoutes.Register(router)
|
||
articleRoutes.Register(router)
|
||
|
||
// 打印注册的路由信息
|
||
router.PrintRoutes()
|
||
|
||
// 启动HTTP服务器
|
||
go func() {
|
||
addr := ":" + cfg.Server.Port
|
||
logger.Info("正在启动HTTP服务器", zap.String("addr", addr))
|
||
|
||
if err := router.Start(addr); err != nil {
|
||
logger.Error("HTTP服务器启动失败", zap.Error(err))
|
||
// 在goroutine中记录错误,但不会影响主程序
|
||
} else {
|
||
logger.Info("HTTP服务器启动成功", zap.String("addr", addr))
|
||
}
|
||
}()
|
||
|
||
logger.Info("路由注册完成,HTTP服务器启动中...")
|
||
}
|
||
|
||
// ================ 中间件包装函数 ================
|
||
|
||
// NewRequestLoggerMiddlewareWrapper 创建请求日志中间件包装器
|
||
func NewRequestLoggerMiddlewareWrapper(logger *zap.Logger, cfg *config.Config, tracer *tracing.Tracer) *middleware.RequestLoggerMiddleware {
|
||
return middleware.NewRequestLoggerMiddleware(logger, cfg.App.IsDevelopment(), tracer)
|
||
}
|
||
|
||
// NewRequestBodyLoggerMiddlewareWrapper 创建请求体日志中间件包装器
|
||
func NewRequestBodyLoggerMiddlewareWrapper(logger *zap.Logger, cfg *config.Config, tracer *tracing.Tracer) *middleware.RequestBodyLoggerMiddleware {
|
||
return middleware.NewRequestBodyLoggerMiddleware(logger, cfg.App.IsDevelopment(), tracer)
|
||
}
|
||
|
||
// ================ 辅助函数 ================
|
||
|
||
// convertLevelConfigs 转换级别配置
|
||
func convertLevelConfigs(configs map[string]config.LevelFileConfig) map[zapcore.Level]logger.LevelFileConfig {
|
||
result := make(map[zapcore.Level]logger.LevelFileConfig)
|
||
|
||
levelMap := map[string]zapcore.Level{
|
||
"debug": zapcore.DebugLevel,
|
||
"info": zapcore.InfoLevel,
|
||
"warn": zapcore.WarnLevel,
|
||
"error": zapcore.ErrorLevel,
|
||
"fatal": zapcore.FatalLevel,
|
||
"panic": zapcore.PanicLevel,
|
||
}
|
||
|
||
// 只转换配置文件中存在的级别
|
||
for levelStr, config := range configs {
|
||
if level, exists := levelMap[levelStr]; exists {
|
||
result[level] = logger.LevelFileConfig{
|
||
MaxSize: config.MaxSize,
|
||
MaxBackups: config.MaxBackups,
|
||
MaxAge: config.MaxAge,
|
||
Compress: config.Compress,
|
||
}
|
||
}
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
// ================ Redis相关工厂函数 ================
|
||
|
||
// NewRedisClient 创建Redis客户端
|
||
func NewRedisClient(cfg *config.Config, logger *zap.Logger) (*redis.Client, error) {
|
||
client := redis.NewClient(&redis.Options{
|
||
Addr: cfg.Redis.GetRedisAddr(),
|
||
Password: cfg.Redis.Password,
|
||
DB: cfg.Redis.DB,
|
||
PoolSize: cfg.Redis.PoolSize,
|
||
MinIdleConns: cfg.Redis.MinIdleConns,
|
||
DialTimeout: cfg.Redis.DialTimeout,
|
||
ReadTimeout: cfg.Redis.ReadTimeout,
|
||
WriteTimeout: cfg.Redis.WriteTimeout,
|
||
})
|
||
|
||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||
defer cancel()
|
||
|
||
_, err := client.Ping(ctx).Result()
|
||
if err != nil {
|
||
logger.Error("Redis连接失败", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
logger.Info("Redis连接已建立")
|
||
return client, nil
|
||
}
|
||
|
||
// NewRedisCache 创建Redis缓存服务
|
||
func NewRedisCache(client *redis.Client, logger *zap.Logger, cfg *config.Config) interfaces.CacheService {
|
||
return cache.NewRedisCache(client, logger, "app")
|
||
}
|
||
|
||
// NewTracedRedisCache 创建带追踪的Redis缓存服务
|
||
func NewTracedRedisCache(client *redis.Client, tracer *tracing.Tracer, logger *zap.Logger, cfg *config.Config) interfaces.CacheService {
|
||
return tracing.NewTracedRedisCache(client, tracer, logger, "app")
|
||
}
|
||
|
||
// RegisterEventHandlers 注册事件处理器
|
||
func RegisterEventHandlers(
|
||
eventBus interfaces.EventBus,
|
||
invoiceEventHandler *infra_events.InvoiceEventHandler,
|
||
logger *zap.Logger,
|
||
) {
|
||
// 启动事件总线
|
||
if err := eventBus.Start(context.Background()); err != nil {
|
||
logger.Error("启动事件总线失败", zap.Error(err))
|
||
return
|
||
}
|
||
|
||
// 注册发票事件处理器
|
||
for _, eventType := range invoiceEventHandler.GetEventTypes() {
|
||
if err := eventBus.Subscribe(eventType, invoiceEventHandler); err != nil {
|
||
logger.Error("注册发票事件处理器失败",
|
||
zap.String("event_type", eventType),
|
||
zap.String("handler", invoiceEventHandler.GetName()),
|
||
zap.Error(err),
|
||
)
|
||
} else {
|
||
logger.Info("发票事件处理器注册成功",
|
||
zap.String("event_type", eventType),
|
||
zap.String("handler", invoiceEventHandler.GetName()),
|
||
)
|
||
}
|
||
}
|
||
|
||
logger.Info("所有事件处理器已注册")
|
||
}
|