package factory import ( "context" "fmt" "io" "net/http" "strings" "time" "git.toowon.com/jimmy/go-common/config" "git.toowon.com/jimmy/go-common/email" commonhttp "git.toowon.com/jimmy/go-common/http" "git.toowon.com/jimmy/go-common/i18n" "git.toowon.com/jimmy/go-common/logger" "git.toowon.com/jimmy/go-common/middleware" "git.toowon.com/jimmy/go-common/migration" "git.toowon.com/jimmy/go-common/sms" "git.toowon.com/jimmy/go-common/storage" "git.toowon.com/jimmy/go-common/tools" "github.com/redis/go-redis/v9" "gorm.io/driver/mysql" "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" ) // ========== HTTP响应结构体(暴露给外部项目使用) ========== // Response 标准响应结构(暴露给外部项目使用) // 外部项目可以直接使用 factory.Response 创建响应对象 // // 示例: // // response := factory.Response{ // Code: 0, // Message: "success", // Data: data, // } type Response = commonhttp.Response // PageResponse 分页响应结构(暴露给外部项目使用) // 外部项目可以直接使用 factory.PageResponse 创建分页响应对象 type PageResponse = commonhttp.PageResponse // PageData 分页数据(暴露给外部项目使用) // 外部项目可以直接使用 factory.PageData 创建分页数据对象 // // 示例: // // pageData := &factory.PageData{ // List: users, // Total: 100, // Page: 1, // PageSize: 20, // } // fac.Success(w, pageData) type PageData = commonhttp.PageData // ========== HTTP请求结构体(暴露给外部项目使用) ========== // PaginationRequest 分页请求结构(暴露给外部项目使用) // 外部项目可以直接使用 factory.PaginationRequest 创建分页请求对象 // // 示例: // // type ListUserRequest struct { // Keyword string `json:"keyword"` // factory.PaginationRequest // 嵌入分页请求结构 // } type PaginationRequest = commonhttp.PaginationRequest // ========== Time工具结构体(暴露给外部项目使用) ========== // TimeInfo 详细时间信息结构(暴露给外部项目使用) // 外部项目可以直接使用 factory.TimeInfo 创建时间信息对象 type TimeInfo = tools.TimeInfo // Factory 工厂类 - 黑盒模式设计 // // 核心理念: // // 外部项目只需传递一个配置文件路径,即可直接使用所有功能, // 无需关心内部实现细节。 // // 推荐使用的黑盒方法: // - GetMiddlewareChain():获取配置好的中间件链 // - LogInfo(), LogError():记录日志 // - RedisSet(), RedisGet():操作Redis // - SendEmail(), SendSMS():发送邮件和短信 // - UploadFile(), GetFileURL():文件上传和访问 // // 需要获取客户端对象的场景(高级功能): // - GetDatabase():数据库操作(GORM已经是很好的抽象) // - GetRedisClient():Redis高级操作(Hash, List, Set, ZSet等) // - GetLogger():Logger高级功能(Close等) // // 使用示例: // // // 1. 创建工厂(传入配置文件路径) // fac, _ := factory.NewFactoryFromFile("config.json") // // // 2. 直接使用黑盒方法(推荐) // fac.LogInfo("用户登录成功") // fac.RedisSet(ctx, "session:123", "data", time.Hour) // fac.SendEmail([]string{"user@example.com"}, "主题", "内容") // chain := fac.GetMiddlewareChain() // chain.Append(yourAuthMiddleware) // 添加自定义中间件 // // // 3. 获取客户端对象(仅在需要高级功能时) // db, _ := fac.GetDatabase() // db.Find(&users) // // Factory 工厂类,用于从配置创建各种客户端对象 type Factory struct { cfg *config.Config storage storage.Storage // 存储实例(延迟初始化) logger *logger.Logger // 日志实例(延迟初始化) email *email.Email // 邮件客户端(延迟初始化) sms *sms.SMS // 短信客户端(延迟初始化) db *gorm.DB // 数据库连接(延迟初始化) redis *redis.Client // Redis客户端(延迟初始化) i18n *i18n.I18n // 国际化工具(延迟初始化) } // NewFactory 创建工厂实例 func NewFactory(cfg *config.Config) *Factory { return &Factory{ cfg: cfg, } } // NewFactoryFromFile 从配置文件创建工厂实例(便捷方法) // filePath: 配置文件路径 func NewFactoryFromFile(filePath string) (*Factory, error) { cfg, err := config.LoadFromFile(filePath) if err != nil { return nil, fmt.Errorf("failed to load config: %w", err) } return NewFactory(cfg), nil } // getEmailClient 获取邮件客户端(内部方法,延迟初始化) func (f *Factory) getEmailClient() (*email.Email, error) { if f.email != nil { return f.email, nil } f.email = email.NewEmail(f.cfg) return f.email, nil } // SendEmail 发送邮件(黑盒模式,推荐使用) // 自动使用配置文件中的SMTP配置发送邮件 // to: 收件人列表 // subject: 邮件主题 // body: 邮件正文(纯文本) // htmlBody: HTML正文(可选,如果设置了会优先使用) func (f *Factory) SendEmail(to []string, subject, body string, htmlBody ...string) error { e, err := f.getEmailClient() if err != nil { return err } return e.SendEmail(to, subject, body, htmlBody...) } // getSMSClient 获取短信客户端(内部方法,延迟初始化) func (f *Factory) getSMSClient() (*sms.SMS, error) { if f.sms != nil { return f.sms, nil } f.sms = sms.NewSMS(f.cfg) return f.sms, nil } // SendSMS 发送短信(黑盒模式,推荐使用) // 自动使用配置文件中的阿里云短信配置发送短信 // phoneNumbers: 手机号列表 // templateParam: 模板参数(map或JSON字符串) // templateCode: 模板代码(可选,如果为空使用配置中的模板代码) func (f *Factory) SendSMS(phoneNumbers []string, templateParam interface{}, templateCode ...string) (*sms.SendResponse, error) { s, err := f.getSMSClient() if err != nil { return nil, err } return s.SendSMS(phoneNumbers, templateParam, templateCode...) } // getLogger 获取日志记录器(内部方法,延迟初始化) func (f *Factory) getLogger() (*logger.Logger, error) { if f.logger != nil { return f.logger, nil } var l *logger.Logger var err error if f.cfg.Logger == nil { // 如果没有配置,使用默认配置创建 l, err = logger.NewLogger(nil) } else { l, err = logger.NewLogger(f.cfg.Logger) } if err != nil { return nil, fmt.Errorf("failed to create logger: %w", err) } f.logger = l return l, nil } // GetLogger 获取日志记录器对象(不推荐直接使用) // // ⚠️ 不推荐直接使用此方法,推荐使用黑盒方法: // - LogDebug, LogInfo, LogWarn, LogError(记录简单日志) // - LogDebugf, LogInfof, LogWarnf, LogErrorf(记录带字段的日志) // // 仅在以下高级场景时使用: // - 需要调用 Close() 方法关闭logger // - 需要使用logger的其他高级功能 // // 示例(不推荐): // // logger, _ := factory.GetLogger() // defer logger.Close() // // 示例(推荐): // // factory.LogInfo("用户登录成功") // factory.LogErrorf(map[string]interface{}{"user_id": 123}, "登录失败") func (f *Factory) GetLogger() (*logger.Logger, error) { return f.getLogger() } // LogDebug 记录调试日志(黑盒模式,推荐使用) // 自动使用配置文件中的logger配置 // message: 日志消息 // args: 格式化参数(可选) func (f *Factory) LogDebug(message string, args ...interface{}) { l, err := f.getLogger() if err != nil { // 如果日志初始化失败,使用标准输出 if len(args) > 0 { fmt.Printf("[DEBUG] "+message+"\n", args...) } else { fmt.Printf("[DEBUG] %s\n", message) } return } if len(args) > 0 { l.Debug(message, args...) } else { l.Debug(message) } } // LogDebugf 记录调试日志(带字段,黑盒模式,推荐使用) // 自动使用配置文件中的logger配置 // fields: 日志字段 // message: 日志消息 // args: 格式化参数(可选) func (f *Factory) LogDebugf(fields map[string]interface{}, message string, args ...interface{}) { l, err := f.getLogger() if err != nil { // 如果日志初始化失败,使用标准输出 if len(args) > 0 { fmt.Printf("[DEBUG] "+message+"\n", args...) } else { fmt.Printf("[DEBUG] %s\n", message) } return } l.Debugf(fields, message, args...) } // LogInfo 记录信息日志(黑盒模式,推荐使用) // 自动使用配置文件中的logger配置 // message: 日志消息 // args: 格式化参数(可选) func (f *Factory) LogInfo(message string, args ...interface{}) { l, err := f.getLogger() if err != nil { // 如果日志初始化失败,使用标准输出 if len(args) > 0 { fmt.Printf("[INFO] "+message+"\n", args...) } else { fmt.Printf("[INFO] %s\n", message) } return } if len(args) > 0 { l.Info(message, args...) } else { l.Info(message) } } // LogInfof 记录信息日志(带字段,黑盒模式,推荐使用) // 自动使用配置文件中的logger配置 // fields: 日志字段 // message: 日志消息 // args: 格式化参数(可选) func (f *Factory) LogInfof(fields map[string]interface{}, message string, args ...interface{}) { l, err := f.getLogger() if err != nil { // 如果日志初始化失败,使用标准输出 if len(args) > 0 { fmt.Printf("[INFO] "+message+"\n", args...) } else { fmt.Printf("[INFO] %s\n", message) } return } l.Infof(fields, message, args...) } // LogWarn 记录警告日志(黑盒模式,推荐使用) // 自动使用配置文件中的logger配置 // message: 日志消息 // args: 格式化参数(可选) func (f *Factory) LogWarn(message string, args ...interface{}) { l, err := f.getLogger() if err != nil { // 如果日志初始化失败,使用标准输出 if len(args) > 0 { fmt.Printf("[WARN] "+message+"\n", args...) } else { fmt.Printf("[WARN] %s\n", message) } return } if len(args) > 0 { l.Warn(message, args...) } else { l.Warn(message) } } // LogWarnf 记录警告日志(带字段,黑盒模式,推荐使用) // 自动使用配置文件中的logger配置 // fields: 日志字段 // message: 日志消息 // args: 格式化参数(可选) func (f *Factory) LogWarnf(fields map[string]interface{}, message string, args ...interface{}) { l, err := f.getLogger() if err != nil { // 如果日志初始化失败,使用标准输出 if len(args) > 0 { fmt.Printf("[WARN] "+message+"\n", args...) } else { fmt.Printf("[WARN] %s\n", message) } return } l.Warnf(fields, message, args...) } // LogError 记录错误日志(黑盒模式,推荐使用) // 自动使用配置文件中的logger配置 // message: 日志消息 // args: 格式化参数(可选) func (f *Factory) LogError(message string, args ...interface{}) { l, err := f.getLogger() if err != nil { // 如果日志初始化失败,使用标准输出 if len(args) > 0 { fmt.Printf("[ERROR] "+message+"\n", args...) } else { fmt.Printf("[ERROR] %s\n", message) } return } if len(args) > 0 { l.Error(message, args...) } else { l.Error(message) } } // LogErrorf 记录错误日志(带字段,黑盒模式,推荐使用) // 自动使用配置文件中的logger配置 // fields: 日志字段 // message: 日志消息 // args: 格式化参数(可选) func (f *Factory) LogErrorf(fields map[string]interface{}, message string, args ...interface{}) { l, err := f.getLogger() if err != nil { // 如果日志初始化失败,使用标准输出 if len(args) > 0 { fmt.Printf("[ERROR] "+message+"\n", args...) } else { fmt.Printf("[ERROR] %s\n", message) } return } l.Errorf(fields, message, args...) } // getDatabase 获取数据库连接对象(内部方法,延迟初始化) func (f *Factory) getDatabase() (*gorm.DB, error) { if f.db != nil { return f.db, nil } if f.cfg.Database == nil { return nil, fmt.Errorf("database config is nil") } // 获取DSN dsn, err := f.cfg.GetDatabaseDSN() if err != nil { return nil, fmt.Errorf("failed to get DSN: %w", err) } // 根据数据库类型创建连接 var db *gorm.DB switch f.cfg.Database.Type { case "mysql": db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) case "postgres": db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) case "sqlite": db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{}) default: return nil, fmt.Errorf("unsupported database type: %s", f.cfg.Database.Type) } if err != nil { return nil, fmt.Errorf("failed to connect to database: %w", err) } // 配置连接池 sqlDB, err := db.DB() if err != nil { return nil, fmt.Errorf("failed to get sql.DB: %w", err) } if f.cfg.Database.MaxOpenConns > 0 { sqlDB.SetMaxOpenConns(f.cfg.Database.MaxOpenConns) } if f.cfg.Database.MaxIdleConns > 0 { sqlDB.SetMaxIdleConns(f.cfg.Database.MaxIdleConns) } if f.cfg.Database.ConnMaxLifetime > 0 { sqlDB.SetConnMaxLifetime(time.Duration(f.cfg.Database.ConnMaxLifetime) * time.Second) } f.db = db return db, nil } // GetDatabase 获取数据库连接对象(推荐使用) // 返回已初始化的GORM数据库对象,可直接使用 // // ℹ️ 数据库操作保持使用 GORM 对象,因为: // - 数据库操作非常复杂多样(查询、插入、更新、删除、事务等) // - GORM 已经提供了很好的抽象和 API // - 无需在 factory 中重复封装所有数据库方法 // // 示例: // // db, _ := factory.GetDatabase() // db.Find(&users) // db.Create(&user) // db.Transaction(func(tx *gorm.DB) error { ... }) func (f *Factory) GetDatabase() (*gorm.DB, error) { return f.getDatabase() } // getRedisClient 获取Redis客户端对象(内部方法,延迟初始化) func (f *Factory) getRedisClient() (*redis.Client, error) { if f.redis != nil { return f.redis, nil } if f.cfg.Redis == nil { return nil, fmt.Errorf("redis config is nil") } // 获取Redis地址 addr := f.cfg.GetRedisAddr() if addr == "" { return nil, fmt.Errorf("redis address is empty") } // 设置默认值 redisConfig := f.cfg.Redis if redisConfig.PoolSize == 0 { redisConfig.PoolSize = 10 // 默认连接池大小 } if redisConfig.MinIdleConns == 0 { redisConfig.MinIdleConns = 5 // 默认最小空闲连接数 } if redisConfig.DialTimeout == 0 { redisConfig.DialTimeout = 5 // 默认连接超时5秒 } if redisConfig.ReadTimeout == 0 { redisConfig.ReadTimeout = 3 // 默认读取超时3秒 } if redisConfig.WriteTimeout == 0 { redisConfig.WriteTimeout = 3 // 默认写入超时3秒 } // 创建Redis客户端 client := redis.NewClient(&redis.Options{ Addr: addr, Password: redisConfig.Password, DB: redisConfig.Database, PoolSize: redisConfig.PoolSize, MinIdleConns: redisConfig.MinIdleConns, MaxRetries: redisConfig.MaxRetries, DialTimeout: time.Duration(redisConfig.DialTimeout) * time.Second, ReadTimeout: time.Duration(redisConfig.ReadTimeout) * time.Second, WriteTimeout: time.Duration(redisConfig.WriteTimeout) * time.Second, }) // 测试连接 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(redisConfig.DialTimeout)*time.Second) defer cancel() _, err := client.Ping(ctx).Result() if err != nil { client.Close() // 连接失败时关闭客户端 return nil, fmt.Errorf("failed to connect to redis: %w", err) } f.redis = client return client, nil } // GetRedisClient 获取Redis客户端对象(高级功能时使用) // 返回已初始化的Redis客户端对象 // // ℹ️ 推荐使用黑盒方法: // - RedisGet, RedisSet, RedisDelete, RedisExists(常用操作) // // 仅在需要使用高级功能时获取客户端: // - Hash 操作(HSet, HGet, HGetAll 等) // - List 操作(LPush, RPush, LRange 等) // - Set 操作(SAdd, SMembers 等) // - ZSet 操作(ZAdd, ZRange 等) // - 其他高级功能 // // 示例(常用操作,推荐): // // factory.RedisSet(ctx, "key", "value", time.Hour) // value, _ := factory.RedisGet(ctx, "key") // // 示例(高级功能): // // client, _ := factory.GetRedisClient() // client.HSet(ctx, "user:1", "name", "Alice") // client.LPush(ctx, "queue", "task1") func (f *Factory) GetRedisClient() (*redis.Client, error) { return f.getRedisClient() } // RedisGet 获取Redis值(黑盒模式,推荐使用) // 自动使用配置文件中的Redis配置 // key: Redis键 func (f *Factory) RedisGet(ctx context.Context, key string) (string, error) { client, err := f.getRedisClient() if err != nil { return "", err } result, err := client.Get(ctx, key).Result() if err == redis.Nil { return "", nil // key不存在,返回空字符串 } if err != nil { return "", fmt.Errorf("failed to get redis key: %w", err) } return result, nil } // RedisSet 设置Redis值(黑盒模式,推荐使用) // 自动使用配置文件中的Redis配置 // key: Redis键 // value: Redis值 // expiration: 过期时间(可选,0表示不过期) func (f *Factory) RedisSet(ctx context.Context, key string, value interface{}, expiration ...time.Duration) error { client, err := f.getRedisClient() if err != nil { return err } var exp time.Duration if len(expiration) > 0 { exp = expiration[0] } err = client.Set(ctx, key, value, exp).Err() if err != nil { return fmt.Errorf("failed to set redis key: %w", err) } return nil } // RedisDelete 删除Redis键(黑盒模式,推荐使用) // 自动使用配置文件中的Redis配置 // keys: Redis键列表 func (f *Factory) RedisDelete(ctx context.Context, keys ...string) error { if len(keys) == 0 { return nil } client, err := f.getRedisClient() if err != nil { return err } err = client.Del(ctx, keys...).Err() if err != nil { return fmt.Errorf("failed to delete redis keys: %w", err) } return nil } // RedisExists 检查Redis键是否存在(黑盒模式,推荐使用) // 自动使用配置文件中的Redis配置 // key: Redis键 func (f *Factory) RedisExists(ctx context.Context, key string) (bool, error) { client, err := f.getRedisClient() if err != nil { return false, err } count, err := client.Exists(ctx, key).Result() if err != nil { return false, fmt.Errorf("failed to check redis key existence: %w", err) } return count > 0, nil } // GetConfig 获取配置对象 func (f *Factory) GetConfig() *config.Config { return f.cfg } // getStorage 获取存储实例(内部方法,延迟初始化) func (f *Factory) getStorage() (storage.Storage, error) { if f.storage != nil { return f.storage, nil } // 根据配置自动选择存储类型 // 优先级:MinIO > OSS var storageType storage.StorageType if f.cfg.MinIO != nil { storageType = storage.StorageTypeMinIO } else if f.cfg.OSS != nil { storageType = storage.StorageTypeOSS } else { return nil, fmt.Errorf("no storage config found (OSS or MinIO)") } // 创建存储实例 s, err := storage.NewStorage(storageType, f.cfg) if err != nil { return nil, fmt.Errorf("failed to create storage: %w", err) } f.storage = s return s, nil } // UploadFile 上传文件(黑盒模式,推荐使用) // 自动根据配置选择存储类型(OSS 或 MinIO),无需关心内部实现 // ctx: 上下文 // objectKey: 对象键(文件路径) // reader: 文件内容 // contentType: 文件类型(可选) // 返回文件访问URL和错误 func (f *Factory) UploadFile(ctx context.Context, objectKey string, reader io.Reader, contentType ...string) (string, error) { s, err := f.getStorage() if err != nil { return "", err } // 上传文件 err = s.Upload(ctx, objectKey, reader, contentType...) if err != nil { return "", fmt.Errorf("failed to upload file: %w", err) } // 获取文件URL url, err := s.GetURL(objectKey, 0) if err != nil { return "", fmt.Errorf("failed to get file URL: %w", err) } return url, nil } // GetFileURL 获取文件访问URL(黑盒模式,推荐使用) // 自动根据配置选择存储类型,返回文件的访问URL // objectKey: 对象键(文件路径) // expires: 过期时间(秒),0表示永久有效 func (f *Factory) GetFileURL(objectKey string, expires int64) (string, error) { s, err := f.getStorage() if err != nil { return "", err } return s.GetURL(objectKey, expires) } // GetMiddlewareChain 获取配置好的中间件链(黑盒模式) // 自动包含:Recovery、Logging、RateLimit(如果配置了)、CORS(如果配置了)、Timezone // 返回已配置好的中间件链,可以通过 Append() 方法添加自定义中间件 // // 示例1:直接使用 // // chain := factory.GetMiddlewareChain() // http.Handle("/api/users", chain.ThenFunc(handleUsers)) // // 示例2:添加自定义中间件 // // chain := factory.GetMiddlewareChain() // chain.Append(yourCustomMiddleware1, yourCustomMiddleware2) // http.Handle("/api/users", chain.ThenFunc(handleUsers)) func (f *Factory) GetMiddlewareChain() *middleware.Chain { var middlewares []func(http.Handler) http.Handler // 1. Recovery 中间件(必需,防止panic导致服务崩溃) l, _ := f.getLogger() // 获取logger,如果失败会使用默认logger middlewares = append(middlewares, middleware.Recovery(&middleware.RecoveryConfig{ Logger: l, })) // 2. Logging 中间件(必需,记录所有请求) middlewares = append(middlewares, middleware.Logging(&middleware.LoggingConfig{ Logger: l, })) // 3. RateLimit 中间件(如果配置了限流) if f.cfg != nil && f.cfg.RateLimit != nil { if f.cfg.RateLimit.Enable { // 从配置创建限流中间件 limiter := middleware.NewTokenBucketLimiter( f.cfg.RateLimit.Rate, time.Duration(f.cfg.RateLimit.Period)*time.Second, ) var keyFunc func(r *http.Request) string if f.cfg.RateLimit.ByIP { keyFunc = func(r *http.Request) string { return middleware.GetClientIP(r) } } else if f.cfg.RateLimit.ByUserID { keyFunc = func(r *http.Request) string { return r.Header.Get("X-User-ID") } } middlewares = append(middlewares, middleware.RateLimit(&middleware.RateLimitConfig{ Limiter: limiter, KeyFunc: keyFunc, })) } } // 4. CORS 中间件(如果配置了) if f.cfg != nil && f.cfg.CORS != nil { corsConfig := &middleware.CORSConfig{ AllowedOrigins: f.cfg.CORS.AllowedOrigins, AllowedMethods: f.cfg.CORS.AllowedMethods, AllowedHeaders: f.cfg.CORS.AllowedHeaders, ExposedHeaders: f.cfg.CORS.ExposedHeaders, AllowCredentials: f.cfg.CORS.AllowCredentials, MaxAge: f.cfg.CORS.MaxAge, } middlewares = append(middlewares, middleware.CORS(corsConfig)) } // 5. Language 中间件(必需,处理语言) middlewares = append(middlewares, middleware.Language) // 6. Timezone 中间件(必需,处理时区) middlewares = append(middlewares, middleware.Timezone) return middleware.NewChain(middlewares...) } // RunMigrations 执行数据库迁移(黑盒模式,推荐使用) // 自动发现并执行指定目录下的所有迁移文件 // migrationsDir: 迁移文件目录(如 "migrations" 或 "scripts/sql") // // 支持的文件命名格式: // - 数字前缀: 01_init_schema.sql // - 时间戳: 20240101000001_create_users.sql // - 带.up后缀: 20240101000001_create_users.up.sql // // 示例: // // fac, _ := factory.NewFactoryFromFile("config.json") // err := fac.RunMigrations("migrations") // if err != nil { // log.Fatal(err) // } func (f *Factory) RunMigrations(migrationsDir string) error { // 获取数据库连接 db, err := f.getDatabase() if err != nil { return fmt.Errorf("failed to get database: %w", err) } // 创建迁移器(传入数据库类型,性能更好) dbType := "mysql" // 默认值 if f.cfg.Database != nil && f.cfg.Database.Type != "" { dbType = f.cfg.Database.Type } migrator := migration.NewMigratorWithType(db, dbType) // 自动发现并加载迁移文件 migrations, err := migration.LoadMigrationsFromFiles(migrationsDir, "*.sql") if err != nil { return fmt.Errorf("failed to load migrations: %w", err) } if len(migrations) == 0 { f.LogInfo("在目录 '%s' 中没有找到迁移文件", migrationsDir) return nil } migrator.AddMigrations(migrations...) // 执行迁移 if err := migrator.Up(); err != nil { return fmt.Errorf("failed to run migrations: %w", err) } f.LogInfo("迁移执行成功: %d 个迁移文件", len(migrations)) return nil } // GetMigrationStatus 获取迁移状态(黑盒模式,推荐使用) // migrationsDir: 迁移文件目录 // 返回迁移状态列表,包含版本、描述、是否已应用等信息 // // 示例: // // fac, _ := factory.NewFactoryFromFile("config.json") // status, err := fac.GetMigrationStatus("migrations") // if err != nil { // log.Fatal(err) // } // for _, s := range status { // fmt.Printf("Version: %s, Applied: %v\n", s.Version, s.Applied) // } func (f *Factory) GetMigrationStatus(migrationsDir string) ([]migration.MigrationStatus, error) { // 获取数据库连接 db, err := f.getDatabase() if err != nil { return nil, fmt.Errorf("failed to get database: %w", err) } // 创建迁移器(传入数据库类型,性能更好) dbType := "mysql" // 默认值 if f.cfg.Database != nil && f.cfg.Database.Type != "" { dbType = f.cfg.Database.Type } migrator := migration.NewMigratorWithType(db, dbType) // 加载迁移文件 migrations, err := migration.LoadMigrationsFromFiles(migrationsDir, "*.sql") if err != nil { return nil, fmt.Errorf("failed to load migrations: %w", err) } migrator.AddMigrations(migrations...) // 获取状态 status, err := migrator.Status() if err != nil { return nil, fmt.Errorf("failed to get migration status: %w", err) } return status, nil } // ========== HTTP响应方法(黑盒模式,推荐使用) ========== // // 这些方法直接调用 http 包的公共方法,保持低耦合。 // 推荐直接使用 factory.Success() 等方法,而不是通过 handler。 // Success 成功响应(黑盒模式,推荐使用) // w: ResponseWriter // data: 响应数据,可以为nil // message: 响应消息(可选),如果为空则使用默认消息 "success" // // 示例: // // fac, _ := factory.NewFactoryFromFile("config.json") // http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) { // fac.Success(w, user) // 只有数据 // fac.Success(w, user, "查询成功") // 数据+消息 // }) func (f *Factory) Success(w http.ResponseWriter, data interface{}, message ...string) { commonhttp.Success(w, data, message...) } // SuccessPage 分页成功响应(黑盒模式,推荐使用) // w: ResponseWriter // list: 数据列表 // total: 总记录数 // page: 当前页码 // pageSize: 每页大小 // message: 响应消息(可选),如果为空则使用默认消息 "success" func (f *Factory) SuccessPage(w http.ResponseWriter, list interface{}, total int64, page, pageSize int, message ...string) { commonhttp.SuccessPage(w, list, total, page, pageSize, message...) } // Error 错误响应(黑盒模式,推荐使用) // w: ResponseWriter // r: HTTP请求(用于获取语言信息和i18n处理) // code: 业务错误码(如果message是消息代码,此参数会被语言文件中的code覆盖) // message: 错误消息或消息代码(如果i18n已初始化且message是消息代码格式,会自动获取国际化消息和业务code) // args: 可选参数,用于格式化消息(类似 fmt.Sprintf,仅在message是消息代码时使用) // // 使用逻辑: // 1. 如果i18n已初始化,且message看起来是消息代码(包含点号,如 "user.not_found"), // 则从请求context中获取语言,并尝试从语言文件中获取国际化消息和业务code // 2. 如果获取到国际化消息,使用语言文件中的code作为响应code,使用国际化消息作为响应message // 3. 如果未获取到或i18n未初始化,使用传入的code和message // // 示例: // // // 方式1:直接传入消息代码(推荐,自动国际化) // fac.Error(w, r, 0, "user.not_found") // // 如果请求语言是 zh-CN,且语言文件中 "user.not_found" 的 code 是 1001, // // 返回: {"code": 1001, "message": "用户不存在"} // // 如果请求语言是 en-US,返回: {"code": 1001, "message": "User not found"} // // // 方式2:带参数的消息代码 // fac.Error(w, r, 0, "user.welcome", "Alice") // // 如果消息内容是 "欢迎,%s",返回: {"code": 0, "message": "欢迎,Alice"} // // // 方式3:直接传入消息文本(不使用国际化) // fac.Error(w, r, 500, "系统错误") // // 返回: {"code": 500, "message": "系统错误"} func (f *Factory) Error(w http.ResponseWriter, r *http.Request, code int, message string, args ...interface{}) { // 判断message是否是消息代码(简单判断:包含点号) isMessageCode := strings.Contains(message, ".") var finalCode int var finalMessage string if isMessageCode { // 尝试从i18n获取国际化消息和业务code if i, err := f.getI18n(); err == nil { // i18n已初始化,获取语言并查找消息 lang := f.GetLanguage(r) if lang == "" { lang = i.GetDefaultLang() } msgInfo := i.GetMessageInfo(lang, message, args...) // 如果获取到了国际化消息(不是返回code本身),使用国际化消息和业务code if msgInfo.Message != message { finalCode = msgInfo.Code finalMessage = msgInfo.Message } else { // 消息代码不存在,使用传入的code和消息代码作为消息 finalCode = code finalMessage = message } } else { // i18n未初始化,使用传入的code和消息代码作为消息 finalCode = code finalMessage = message } } else { // 不是消息代码格式,使用传入的code和消息 finalCode = code finalMessage = message } commonhttp.Error(w, finalCode, finalMessage) } // SystemError 系统错误响应(返回HTTP 500)(黑盒模式,推荐使用) // w: ResponseWriter // message: 错误消息 func (f *Factory) SystemError(w http.ResponseWriter, message string) { commonhttp.SystemError(w, message) } // ========== HTTP请求解析方法(黑盒模式,推荐使用) ========== // // 这些方法直接调用 http 包的公共方法,保持低耦合。 // 推荐直接使用 factory.ParseJSON()、factory.ConvertInt() 等方法。 // ParseJSON 解析JSON请求体(黑盒模式,推荐使用) // r: HTTP请求 // v: 目标结构体指针 // // 示例: // // var req struct { // Name string `json:"name"` // } // if err := fac.ParseJSON(r, &req); err != nil { // fac.Error(w, 400, "请求参数解析失败") // return // } func (f *Factory) ParseJSON(r *http.Request, v interface{}) error { return commonhttp.ParseJSON(r, v) } // ParsePaginationRequest 从请求中解析分页参数(黑盒模式,推荐使用) // r: HTTP请求 // 支持从查询参数和form表单中解析 // 优先级:查询参数 > form表单 // // 示例: // // pagination := fac.ParsePaginationRequest(r) // page := pagination.GetPage() // pageSize := pagination.GetSize() func (f *Factory) ParsePaginationRequest(r *http.Request) *PaginationRequest { return commonhttp.ParsePaginationRequest(r) } // ConvertInt 将字符串转换为int类型(黑盒模式,推荐使用) // value: 待转换的字符串 // defaultValue: 转换失败或字符串为空时返回的默认值 func (f *Factory) ConvertInt(value string, defaultValue int) int { return tools.ConvertInt(value, defaultValue) } // ConvertInt64 将字符串转换为int64类型(黑盒模式,推荐使用) // value: 待转换的字符串 // defaultValue: 转换失败或字符串为空时返回的默认值 func (f *Factory) ConvertInt64(value string, defaultValue int64) int64 { return tools.ConvertInt64(value, defaultValue) } // ConvertUint64 将字符串转换为uint64类型(黑盒模式,推荐使用) // value: 待转换的字符串 // defaultValue: 转换失败或字符串为空时返回的默认值 func (f *Factory) ConvertUint64(value string, defaultValue uint64) uint64 { return tools.ConvertUint64(value, defaultValue) } // ConvertUint32 将字符串转换为uint32类型(黑盒模式,推荐使用) // value: 待转换的字符串 // defaultValue: 转换失败或字符串为空时返回的默认值 func (f *Factory) ConvertUint32(value string, defaultValue uint32) uint32 { return tools.ConvertUint32(value, defaultValue) } // ConvertBool 将字符串转换为bool类型(黑盒模式,推荐使用) // value: 待转换的字符串 // defaultValue: 转换失败或字符串为空时返回的默认值 func (f *Factory) ConvertBool(value string, defaultValue bool) bool { return tools.ConvertBool(value, defaultValue) } // ConvertFloat64 将字符串转换为float64类型(黑盒模式,推荐使用) // value: 待转换的字符串 // defaultValue: 转换失败或字符串为空时返回的默认值 func (f *Factory) ConvertFloat64(value string, defaultValue float64) float64 { return tools.ConvertFloat64(value, defaultValue) } // GetTimezone 从请求的context中获取时区(黑盒模式,推荐使用) // r: HTTP请求 // 如果使用了middleware.Timezone中间件,可以从context中获取时区信息 // 如果未设置,返回默认时区 AsiaShanghai func (f *Factory) GetTimezone(r *http.Request) string { return commonhttp.GetTimezone(r) } // GetLanguage 从请求的context中获取语言(黑盒模式,推荐使用) // r: HTTP请求 // 如果使用了middleware.Language中间件,可以从context中获取语言信息 // 如果未设置,返回默认语言 zh-CN func (f *Factory) GetLanguage(r *http.Request) string { return commonhttp.GetLanguage(r) } // ========== Tools工具方法(黑盒模式,推荐使用) ========== // // 这些方法直接调用 tools 包的公共方法,保持低耦合。 // factory 只负责方法暴露,具体业务在 tools 包中实现。 // ========== Version 版本工具 ========== // GetVersion 获取版本号(黑盒模式,推荐使用) // 优先从环境变量 DOCKER_TAG 或 VERSION 中读取 // 如果没有设置环境变量,则使用默认版本号 func (f *Factory) GetVersion() string { return tools.GetVersion() } // ========== Money 金额工具 ========== // GetMoneyCalculator 获取金额计算器(黑盒模式,推荐使用) // 返回金额计算器实例,可用于金额计算操作 func (f *Factory) GetMoneyCalculator() *tools.MoneyCalculator { return tools.NewMoneyCalculator() } // YuanToCents 元转分(黑盒模式,推荐使用) func (f *Factory) YuanToCents(yuan float64) int64 { return tools.YuanToCents(yuan) } // CentsToYuan 分转元(黑盒模式,推荐使用) func (f *Factory) CentsToYuan(cents int64) float64 { return tools.CentsToYuan(cents) } // FormatYuan 格式化显示金额(分转元,保留2位小数)(黑盒模式,推荐使用) func (f *Factory) FormatYuan(cents int64) string { return tools.FormatYuan(cents) } // ========== DateTime 日期时间工具 ========== // Now 获取当前时间(使用指定时区)(黑盒模式,推荐使用) func (f *Factory) Now(timezone ...string) time.Time { return tools.Now(timezone...) } // ParseDateTime 解析日期时间字符串(2006-01-02 15:04:05)(黑盒模式,推荐使用) func (f *Factory) ParseDateTime(value string, timezone ...string) (time.Time, error) { return tools.ParseDateTime(value, timezone...) } // ParseDate 解析日期字符串(2006-01-02)(黑盒模式,推荐使用) func (f *Factory) ParseDate(value string, timezone ...string) (time.Time, error) { return tools.ParseDate(value, timezone...) } // FormatDateTime 格式化日期时间(2006-01-02 15:04:05)(黑盒模式,推荐使用) func (f *Factory) FormatDateTime(t time.Time, timezone ...string) string { return tools.FormatDateTime(t, timezone...) } // FormatDate 格式化日期(2006-01-02)(黑盒模式,推荐使用) func (f *Factory) FormatDate(t time.Time, timezone ...string) string { return tools.FormatDate(t, timezone...) } // FormatTime 格式化时间(15:04:05)(黑盒模式,推荐使用) func (f *Factory) FormatTime(t time.Time, timezone ...string) string { return tools.FormatTime(t, timezone...) } // ToUnix 转换为Unix时间戳(黑盒模式,推荐使用) func (f *Factory) ToUnix(t time.Time) int64 { return tools.ToUnix(t) } // FromUnix 从Unix时间戳创建时间(黑盒模式,推荐使用) func (f *Factory) FromUnix(sec int64, timezone ...string) time.Time { return tools.FromUnix(sec, timezone...) } // ToUnixMilli 转换为Unix毫秒时间戳(黑盒模式,推荐使用) func (f *Factory) ToUnixMilli(t time.Time) int64 { return tools.ToUnixMilli(t) } // FromUnixMilli 从Unix毫秒时间戳创建时间(黑盒模式,推荐使用) func (f *Factory) FromUnixMilli(msec int64, timezone ...string) time.Time { return tools.FromUnixMilli(msec, timezone...) } // AddDays 添加天数(黑盒模式,推荐使用) func (f *Factory) AddDays(t time.Time, days int) time.Time { return tools.AddDays(t, days) } // AddMonths 添加月数(黑盒模式,推荐使用) func (f *Factory) AddMonths(t time.Time, months int) time.Time { return tools.AddMonths(t, months) } // AddYears 添加年数(黑盒模式,推荐使用) func (f *Factory) AddYears(t time.Time, years int) time.Time { return tools.AddYears(t, years) } // StartOfDay 获取一天的开始时间(00:00:00)(黑盒模式,推荐使用) func (f *Factory) StartOfDay(t time.Time, timezone ...string) time.Time { return tools.StartOfDay(t, timezone...) } // EndOfDay 获取一天的结束时间(23:59:59.999999999)(黑盒模式,推荐使用) func (f *Factory) EndOfDay(t time.Time, timezone ...string) time.Time { return tools.EndOfDay(t, timezone...) } // StartOfMonth 获取月份的开始时间(黑盒模式,推荐使用) func (f *Factory) StartOfMonth(t time.Time, timezone ...string) time.Time { return tools.StartOfMonth(t, timezone...) } // EndOfMonth 获取月份的结束时间(黑盒模式,推荐使用) func (f *Factory) EndOfMonth(t time.Time, timezone ...string) time.Time { return tools.EndOfMonth(t, timezone...) } // StartOfYear 获取年份的开始时间(黑盒模式,推荐使用) func (f *Factory) StartOfYear(t time.Time, timezone ...string) time.Time { return tools.StartOfYear(t, timezone...) } // EndOfYear 获取年份的结束时间(黑盒模式,推荐使用) func (f *Factory) EndOfYear(t time.Time, timezone ...string) time.Time { return tools.EndOfYear(t, timezone...) } // DiffDays 计算两个时间之间的天数差(黑盒模式,推荐使用) func (f *Factory) DiffDays(t1, t2 time.Time) int { return tools.DiffDays(t1, t2) } // DiffHours 计算两个时间之间的小时差(黑盒模式,推荐使用) func (f *Factory) DiffHours(t1, t2 time.Time) int64 { return tools.DiffHours(t1, t2) } // DiffMinutes 计算两个时间之间的分钟差(黑盒模式,推荐使用) func (f *Factory) DiffMinutes(t1, t2 time.Time) int64 { return tools.DiffMinutes(t1, t2) } // DiffSeconds 计算两个时间之间的秒数差(黑盒模式,推荐使用) func (f *Factory) DiffSeconds(t1, t2 time.Time) int64 { return tools.DiffSeconds(t1, t2) } // ========== Time 时间工具(黑盒模式,推荐使用) ========== // // 这些方法提供基础时间操作、时间戳、时间判断等功能。 // 与 DateTime 工具的区别: // - DateTime: 专注于时区相关、格式化、解析、UTC转换 // - Time: 专注于基础时间操作、时间戳、时间判断、时间信息生成 // ========== 时间戳方法 ========== // GetTimestamp 获取当前时间戳(秒)(黑盒模式,推荐使用) func (f *Factory) GetTimestamp() int64 { return tools.GetTimestamp() } // GetMillisTimestamp 获取当前时间戳(毫秒)(黑盒模式,推荐使用) func (f *Factory) GetMillisTimestamp() int64 { return tools.GetMillisTimestamp() } // GetUTCTimestamp 获取UTC时间戳(秒)(黑盒模式,推荐使用) func (f *Factory) GetUTCTimestamp() int64 { return tools.GetUTCTimestamp() } // GetUTCTimestampFromTime 从指定时间获取UTC时间戳(秒)(黑盒模式,推荐使用) func (f *Factory) GetUTCTimestampFromTime(t time.Time) int64 { return tools.GetUTCTimestampFromTime(t) } // ========== 格式化方法(自定义格式) ========== // FormatTimeWithLayout 格式化时间(自定义格式)(黑盒模式,推荐使用) // layout: 时间格式,如 "2006-01-02 15:04:05",如果为空则使用默认格式 func (f *Factory) FormatTimeWithLayout(t time.Time, layout string) string { return tools.FormatTimeWithLayout(t, layout) } // FormatTimeUTC 格式化时间为UTC字符串(ISO 8601格式)(黑盒模式,推荐使用) func (f *Factory) FormatTimeUTC(t time.Time) string { return tools.FormatTimeUTC(t) } // GetCurrentTime 获取当前时间字符串(黑盒模式,推荐使用) // 使用默认格式 "2006-01-02 15:04:05" func (f *Factory) GetCurrentTime() string { return tools.GetCurrentTime() } // ========== 解析方法(自定义格式) ========== // ParseTime 解析时间字符串(自定义格式)(黑盒模式,推荐使用) // timeStr: 时间字符串 // layout: 时间格式,如 "2006-01-02 15:04:05",如果为空则使用默认格式 func (f *Factory) ParseTime(timeStr, layout string) (time.Time, error) { return tools.ParseTime(timeStr, layout) } // ========== 时间计算(补充 DateTime 的 Add 系列) ========== // AddHours 增加小时数(黑盒模式,推荐使用) func (f *Factory) AddHours(t time.Time, hours int) time.Time { return tools.AddHours(t, hours) } // AddMinutes 增加分钟数(黑盒模式,推荐使用) func (f *Factory) AddMinutes(t time.Time, minutes int) time.Time { return tools.AddMinutes(t, minutes) } // ========== 时间范围(周相关) ========== // GetBeginOfWeek 获取某周的开始时间(周一)(黑盒模式,推荐使用) func (f *Factory) GetBeginOfWeek(t time.Time) time.Time { return tools.GetBeginOfWeek(t) } // GetEndOfWeek 获取某周的结束时间(周日)(黑盒模式,推荐使用) func (f *Factory) GetEndOfWeek(t time.Time) time.Time { return tools.GetEndOfWeek(t) } // ========== 时间判断 ========== // IsToday 判断是否为今天(黑盒模式,推荐使用) func (f *Factory) IsToday(t time.Time) bool { return tools.IsToday(t) } // IsYesterday 判断是否为昨天(黑盒模式,推荐使用) func (f *Factory) IsYesterday(t time.Time) bool { return tools.IsYesterday(t) } // IsTomorrow 判断是否为明天(黑盒模式,推荐使用) func (f *Factory) IsTomorrow(t time.Time) bool { return tools.IsTomorrow(t) } // ========== 时间信息生成 ========== // GenerateTimeInfoWithTimezone 生成详细时间信息(指定时区)(黑盒模式,推荐使用) // 返回包含UTC时间、本地时间、时间戳、时区信息等的完整时间信息结构 func (f *Factory) GenerateTimeInfoWithTimezone(t time.Time, timezone string) TimeInfo { return tools.GenerateTimeInfoWithTimezone(t, timezone) } // ========== Crypto 加密工具(黑盒模式,推荐使用) ========== // // 这些方法提供密码加密、哈希计算、随机字符串生成等功能。 // ========== 密码加密 ========== // HashPassword 使用bcrypt加密密码(黑盒模式,推荐使用) // password: 原始密码 // 返回: 加密后的密码哈希值 func (f *Factory) HashPassword(password string) (string, error) { return tools.HashPassword(password) } // CheckPassword 验证密码(黑盒模式,推荐使用) // password: 原始密码 // hash: 加密后的密码哈希值 // 返回: 密码是否正确 func (f *Factory) CheckPassword(password, hash string) bool { return tools.CheckPassword(password, hash) } // ========== 哈希计算 ========== // MD5 计算MD5哈希值(黑盒模式,推荐使用) // text: 要计算哈希的文本 // 返回: MD5哈希值(十六进制字符串) func (f *Factory) MD5(text string) string { return tools.MD5(text) } // SHA256 计算SHA256哈希值(黑盒模式,推荐使用) // text: 要计算哈希的文本 // 返回: SHA256哈希值(十六进制字符串) func (f *Factory) SHA256(text string) string { return tools.SHA256(text) } // ========== 随机字符串生成 ========== // GenerateRandomString 生成指定长度的随机字符串(黑盒模式,推荐使用) // length: 字符串长度 // 返回: 随机字符串(包含大小写字母和数字) func (f *Factory) GenerateRandomString(length int) string { return tools.GenerateRandomString(length) } // GenerateRandomNumber 生成指定长度的随机数字字符串(黑盒模式,推荐使用) // length: 字符串长度 // 返回: 随机数字字符串 func (f *Factory) GenerateRandomNumber(length int) string { return tools.GenerateRandomNumber(length) } // ========== 业务相关随机码生成 ========== // GenerateSMSCode 生成短信验证码(黑盒模式,推荐使用) // 返回: 6位数字验证码 func (f *Factory) GenerateSMSCode() string { return tools.GenerateSMSCode() } // GenerateOrderNo 生成订单号(黑盒模式,推荐使用) // prefix: 订单号前缀 // 返回: 订单号(格式:前缀+时间戳+6位随机数) func (f *Factory) GenerateOrderNo(prefix string) string { return tools.GenerateOrderNo(prefix) } // GeneratePaymentNo 生成支付单号(黑盒模式,推荐使用) // 返回: 支付单号(格式:PAY+时间戳+6位随机数) func (f *Factory) GeneratePaymentNo() string { return tools.GeneratePaymentNo() } // GenerateRefundNo 生成退款单号(黑盒模式,推荐使用) // 返回: 退款单号(格式:RF+时间戳+6位随机数) func (f *Factory) GenerateRefundNo() string { return tools.GenerateRefundNo() } // GenerateTransferNo 生成调拨单号(黑盒模式,推荐使用) // 返回: 调拨单号(格式:TF+时间戳+6位随机数) func (f *Factory) GenerateTransferNo() string { return tools.GenerateTransferNo() } // ========== I18n 国际化工具(黑盒模式,推荐使用) ========== // // 这些方法提供多语言内容管理功能,支持从文件加载语言内容,通过语言代码和消息代码获取对应语言的内容。 // getI18n 获取国际化工具实例(内部方法,延迟初始化) func (f *Factory) getI18n() (*i18n.I18n, error) { if f.i18n != nil { return f.i18n, nil } // 如果没有配置,返回错误 return nil, fmt.Errorf("i18n not initialized, please call InitI18n first") } // InitI18n 初始化国际化工具(黑盒模式,推荐使用) // defaultLang: 默认语言代码(如 "zh-CN", "en-US") // 初始化后可以调用 LoadI18nFromDir 或 LoadI18nFromFile 加载语言文件 // // 示例: // // fac, _ := factory.NewFactoryFromFile("config.json") // fac.InitI18n("zh-CN") // fac.LoadI18nFromDir("locales") func (f *Factory) InitI18n(defaultLang string) { f.i18n = i18n.NewI18n(defaultLang) } // LoadI18nFromDir 从目录加载多个语言文件(黑盒模式,推荐使用) // dirPath: 语言文件目录路径 // 文件命名规则:{语言代码}.json(如 zh-CN.json, en-US.json) // // 文件格式示例(zh-CN.json): // // { // "user.not_found": "用户不存在", // "user.login_success": "登录成功", // "user.welcome": "欢迎,%s" // } // // 示例: // // fac.InitI18n("zh-CN") // fac.LoadI18nFromDir("locales") func (f *Factory) LoadI18nFromDir(dirPath string) error { i, err := f.getI18n() if err != nil { return err } return i.LoadFromDir(dirPath) } // LoadI18nFromFile 从单个语言文件加载内容(黑盒模式,推荐使用) // filePath: 语言文件路径(JSON格式) // lang: 语言代码(如 "zh-CN", "en-US") // // 示例: // // fac.InitI18n("zh-CN") // fac.LoadI18nFromFile("locales/zh-CN.json", "zh-CN") // fac.LoadI18nFromFile("locales/en-US.json", "en-US") func (f *Factory) LoadI18nFromFile(filePath, lang string) error { i, err := f.getI18n() if err != nil { return err } return i.LoadFromFile(filePath, lang) } // GetMessage 获取指定语言和代码的消息内容(黑盒模式,推荐使用) // lang: 语言代码(如 "zh-CN", "en-US") // code: 消息代码(如 "user.not_found") // args: 可选参数,用于格式化消息(类似 fmt.Sprintf) // // 返回逻辑: // 1. 如果指定语言存在该code,返回对应内容 // 2. 如果指定语言不存在,尝试使用默认语言 // 3. 如果默认语言也不存在,返回code本身(作为fallback) // // 示例: // // // 简单消息 // msg := fac.GetMessage("zh-CN", "user.not_found") // // 返回: "用户不存在" // // // 带参数的消息 // msg := fac.GetMessage("zh-CN", "user.welcome", "Alice") // // 如果消息内容是 "欢迎,%s",返回: "欢迎,Alice" func (f *Factory) GetMessage(lang, code string, args ...interface{}) string { i, err := f.getI18n() if err != nil { // 如果未初始化,返回code本身 return code } return i.GetMessage(lang, code, args...) } // GetI18n 获取国际化工具对象(高级功能时使用) // 返回已初始化的国际化工具对象 // // ℹ️ 推荐使用黑盒方法: // - GetMessage():获取消息内容 // - LoadI18nFromDir():加载语言文件目录 // - LoadI18nFromFile():加载单个语言文件 // // 仅在需要使用高级功能时获取对象: // - HasLang():检查语言是否存在 // - GetSupportedLangs():获取所有支持的语言 // - ReloadFromFile():重新加载语言文件 // - SetDefaultLang():动态设置默认语言 // // 示例(常用操作,推荐): // // fac.InitI18n("zh-CN") // fac.LoadI18nFromDir("locales") // msg := fac.GetMessage("zh-CN", "user.not_found") // // 示例(高级功能): // // i18n, _ := fac.GetI18n() // langs := i18n.GetSupportedLangs() // hasLang := i18n.HasLang("en-US") func (f *Factory) GetI18n() (*i18n.I18n, error) { return f.getI18n() }