package config import ( "log" "os" "github.com/spf13/viper" ) type Config struct { Server ServerConfig `mapstructure:"server"` Database DatabaseConfig `mapstructure:"database"` JWT JWTConfig `mapstructure:"jwt"` Redis RedisConfig `mapstructure:"redis"` App AppConfig `mapstructure:"app"` Log LogConfig `mapstructure:"log"` } type ServerConfig struct { Port string `mapstructure:"port"` Mode string `mapstructure:"mode"` } type DatabaseConfig struct { Host string `mapstructure:"host"` Port string `mapstructure:"port"` User string `mapstructure:"user"` Password string `mapstructure:"password"` DBName string `mapstructure:"dbname"` Charset string `mapstructure:"charset"` } type JWTConfig struct { Secret string `mapstructure:"secret"` AccessTokenTTL int `mapstructure:"access_token_ttl"` RefreshTokenTTL int `mapstructure:"refresh_token_ttl"` } type RedisConfig struct { Host string `mapstructure:"host"` Port string `mapstructure:"port"` Password string `mapstructure:"password"` DB int `mapstructure:"db"` } type AppConfig struct { Name string `mapstructure:"name"` Version string `mapstructure:"version"` Environment string `mapstructure:"environment"` LogLevel string `mapstructure:"log_level"` } type LogConfig struct { Level string `mapstructure:"level"` Format string `mapstructure:"format"` Output string `mapstructure:"output"` FilePath string `mapstructure:"file_path"` MaxSize int `mapstructure:"max_size"` MaxBackups int `mapstructure:"max_backups"` MaxAge int `mapstructure:"max_age"` Compress bool `mapstructure:"compress"` } var GlobalConfig *Config func LoadConfig() { // 获取环境变量,默认为 development env := os.Getenv("GO_ENV") if env == "" { env = "development" } // 根据环境选择配置文件 configName := getConfigName(env) viper.SetConfigName(configName) viper.SetConfigType("yaml") viper.AddConfigPath("./config") viper.AddConfigPath(".") // 设置环境变量前缀 viper.SetEnvPrefix("AI_ENGLISH") viper.AutomaticEnv() // 设置默认值 setDefaults() if err := viper.ReadInConfig(); err != nil { log.Printf("Warning: Config file '%s' not found, trying fallback...", configName) // 尝试加载默认配置文件 viper.SetConfigName("config") if err := viper.ReadInConfig(); err != nil { log.Printf("Warning: Default config file not found, using defaults and environment variables: %v", err) } } GlobalConfig = &Config{} if err := viper.Unmarshal(GlobalConfig); err != nil { log.Fatalf("Unable to decode config: %v", err) } // 从环境变量覆盖敏感配置 overrideFromEnv() log.Printf("Loaded configuration for environment: %s (file: %s.yaml)", env, configName) log.Printf("Server mode: %s, App environment: %s", GlobalConfig.Server.Mode, GlobalConfig.App.Environment) } // getConfigName 根据环境返回配置文件名 func getConfigName(env string) string { switch env { case "production", "prod": return "config.prod" case "development", "dev": return "config.dev" case "staging", "stage": return "config.staging" case "test": return "config.test" default: return "config" } } func setDefaults() { viper.SetDefault("server.port", "8080") viper.SetDefault("server.mode", "debug") viper.SetDefault("database.host", "localhost") viper.SetDefault("database.port", "3306") viper.SetDefault("database.charset", "utf8mb4") viper.SetDefault("jwt.access_token_ttl", 3600) viper.SetDefault("jwt.refresh_token_ttl", 604800) viper.SetDefault("redis.host", "localhost") viper.SetDefault("redis.port", "6379") viper.SetDefault("redis.db", 0) viper.SetDefault("app.name", "AI English Learning") viper.SetDefault("app.version", "1.0.0") viper.SetDefault("app.environment", "development") viper.SetDefault("app.log_level", "info") viper.SetDefault("log.level", "info") viper.SetDefault("log.format", "json") viper.SetDefault("log.output", "both") viper.SetDefault("log.file_path", "./logs/app.log") viper.SetDefault("log.max_size", 100) viper.SetDefault("log.max_backups", 10) viper.SetDefault("log.max_age", 30) viper.SetDefault("log.compress", true) } func overrideFromEnv() { if dbPassword := os.Getenv("DB_PASSWORD"); dbPassword != "" { GlobalConfig.Database.Password = dbPassword } if jwtSecret := os.Getenv("JWT_SECRET"); jwtSecret != "" { GlobalConfig.JWT.Secret = jwtSecret } if redisPassword := os.Getenv("REDIS_PASSWORD"); redisPassword != "" { GlobalConfig.Redis.Password = redisPassword } }