目录
Viper是什么
Viper是一个用于Go语言应用程序的配置管理库。它提供了一种简单而灵活的方式来处理应用程序的配置,支持多种格式的配置文件,并提供了一组API来读取和使用这些配置。
Viper支持多种配置文件格式,包括JSON、TOML、YAML和HCL等。它还支持环境变量和命令行标志等配置方式。这使得Viper非常适合需要在不同环境中运行(如开发、测试和生产环境)的应用程序,因为可以使用不同的配置文件和设置来管理应用程序的行为。 优点:使用Viper,可以轻松地将配置信息加载到应用程序中,并在需要时获取这些信息。Viper还提供了一些方便的功能,例如默认值、类型转换和键名重映射等,使得配置管理变得更加简单和灵活。
实现Viper的封装
interalinterfaceGetFileGetFilesembed
interal文件夹代码实现
core/interal/viper_interface.go
type IViper interface { // GetFile 获取文件信息 GetFile(path, filename string) io.Reader // GetFiles 获取配置文件夹信息 GetFiles(dir string) ([]fs.DirEntry, error) }
core/interal/viper.go
var Viper = new(viper) type viper struct{} func (v *viper) GetFile(path, filename string) io.Reader { file, err := os.Open(filepath.Join(path, filename)) if err != nil { return nil } defer func() { _ = file.Close() }() all, err := io.ReadAll(file) if err != nil { return nil } return bytes.NewReader(all) } func (v *viper) GetFiles(dir string) ([]os.DirEntry, error) { entries, err := os.ReadDir(dir) if err != nil { return nil, errors.Wrapf(err, "[viper][path:%s]获取配置文件夹信息失败!", dir) } return entries, nil }
core/interal/vuper_embed.go (实现本地embed标记,当然推荐使用下面本地实现的方法)
var Viper = new(viper) type viper struct{} func (v *viper) GetFile(path, filename string) io.Reader { file, err := global.Configs.Open(filepath.Join(path, filename)) if err != nil { fmt.Printf("[viper][path:%s][filename:%s]文件不存在!\n", path, filename) return nil } return file } func (v *viper) GetFiles(dir string) ([]fs.DirEntry, error) { entries, err := global.Configs.ReadDir(dir) if err != nil { return nil, errors.Wrapf(err, "[viper][embed][dir:%s]获取配置文件夹信息失败!", dir) } return entries, nil }
core/viper.go
我这里的config文件夹中的配置yaml格式如:gorm.debug.yaml
var Viper = new(_viper) type _viper struct{} // Initialization . // 优先级: 命令行 > 环境变量 > 默认值 func (c *_viper) Initialization(path ...string) { var configs string if len(path) == 0 { flag.StringVar(&configs, "c", "", "choose configs dir.") flag.Parse() if configs == "" { env := os.Getenv(internal.ConfigsEnv) if env == "" { // 判断 internal.ConfigEnv 常量存储的环境变量是否为空 configs = internal.ConfigsPath fmt.Printf("您正在使用配置默认文件夹:%s,configs的文件夹路径为%s\n", internal.ConfigsPath, configs) } else { configs = env fmt.Printf("您正在使用%s环境变量,configs的文件夹路径为%s\n", internal.ConfigsEnv, configs) } } else { // 命令行参数不为空 将值赋值于configs fmt.Printf("您正在使用命令行的-c参数传递的值,configs的文件夹路径为%s\n", configs) } } else { // path 这个切片大于0,取第一个值赋值到configs configs = path[0] } v := viper.New() v.AddConfigPath(configs) entries, err := internal.Viper.GetFiles(configs) if err != nil { fmt.Printf("%+v\n", err) return } for i := 0; i < len(entries); i++ { if entries[i].IsDir() { // 忽略配置文件夹里的文件夹 continue } filename := entries[i].Name() // 分割文件名 names := strings.Split(filename, ".") if len(names) == 3 { config := names[0] // 文件名 mode := names[1] // 模式 yaml := names[2] // 文件后缀 if mode != gin.Mode() { continue } // 拼接 v.SetConfigName(strings.Join([]string{config, mode}, ".")) v.SetConfigType(yaml) reader := internal.Viper.GetFile(configs, filename) err = v.MergeConfig(reader) if err != nil { fmt.Printf("[viper][filename:%s][err:%v]配置文件读取失败!\n", filename, err) return } // 读取配置文件 err = v.ReadInConfig() if err != nil { fmt.Printf("[viper][filename:%s][err:%v]配置文件读取失败!\n", filename, err) continue } // 反序列化config err = v.Unmarshal(&global.Config) if err != nil { fmt.Printf("[viper][err:%v]反序列化失败!\n", err) continue } v.OnConfigChange(func(in fsnotify.Event) { fmt.Printf("[viper][filename:%s]配置文件更新\n", in.Name) err = v.Unmarshal(&global.Config) if err != nil { fmt.Printf("[viper][err:%v]反序列化失败!\n", err) } }) v.WatchConfig() } } // 注册到全局 global.Viper = v }
根目录下创建embed.go
viper_embed.goviper_embed.go
package main // 这些有import导报 // import (......) func init() { global.Configs = configs } var ( //go:embed configs configs embed.FS )
global中引入结构体
global/global.go
var ( Viper *viper.Viper )
您可能感兴趣的文章: