package config import ( "fmt" "time" "github.com/fsnotify/fsnotify" "github.com/spf13/viper" ) const ( EnvDevelopment = "development" EnvProduction = "production" ) type DataBaseConfig struct { Prefix string Driver string DSN string MaxConns int `mapstructure:"max_conns"` } type Project struct { StaticUrlMapPath []interface{} TemplateGlob string MediaFilePath string CurrentTheme string } type ServerConfig struct { Port string EnableGzip bool `mapstructure:"enable_gzip"` CSRFSecret string `mapstructure:"csrf_secret"` ReadTimeout time.Duration WriteTimeout time.Duration } type ThemeConfig struct { Current string AllowUpload bool `mapstructure:"allow_upload"` } type SecurityConfig struct { CORSAllowedOrigins []string `mapstructure:"cors_allowed_origins"` } type Config struct { Env string Server ServerConfig DataBase DataBaseConfig Theme ThemeConfig Project Project Security SecurityConfig } var globalConfig *Config func LoadConfig(configPath string) (*Config, error) { // 1. 基础配置 viper.SetConfigFile(configPath) // 设置配置文件的名称(不包括扩展名) viper.SetConfigName("config") // 设置配置文件所在的目录 viper.AddConfigPath("./config") // 设置配置文件的类型为YAML viper.SetConfigType("yaml") // 3. 自动读取环境变量(自动转换大写和下划线) viper.AutomaticEnv() viper.SetEnvPrefix("BLOG") // 环境变量前缀 BLOG_xxx // 2. 设置默认值 viper.SetDefault("server.port", 3000) viper.SetDefault("database.max_conns", 10) viper.SetDefault("theme.allow_upload", false) // 读取配置文件 if err := viper.ReadInConfig(); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); ok { return nil, fmt.Errorf("配置文件未找到: %s", configPath) } return nil, fmt.Errorf("读取配置文件失败: %w", err) } // 监控配置文件变更 viper.WatchConfig() viper.OnConfigChange(func(e fsnotify.Event) { fmt.Println("Config file changed:", e.Name) }) // 5. 反序列化到结构体 var cfg Config if err := viper.Unmarshal(&cfg); err != nil { return nil, fmt.Errorf("配置解析失败: %w", err) } globalConfig = &cfg // 保存配置到全局变量 return &cfg, nil } // GetGlobalConfig 获取全局配置 func GetGlobalConfig() *Config { return globalConfig }