有梦想的鱼
写代码我得再认真点,当我最终放下键盘时,我实在不想仍有太多疑惑

1.介绍

Viper是一个配置管理库,支持多种格式的配置文件,并且可以从环境变量、命令行参数等读取配置。

1.下载viper

go get github.com/spf13/viper

2.基本使用

1.使用程序代码设置并且读取配置
  • 后面的会覆盖前面的设置, 但是不同的设置方式有一些优先级区别.
  • Get 函数如果找不到相应的配置,都将返回零值。要检查给定的 key 是否存在,使用IsSet()方法.
func WriteBasicUse() {
    viper.SetDefault("ip", "192.168.80.51")
    viper.Set("port", 10086)
    
    ip := viper.GetString("ip")
    port := viper.GetInt("port")
    
    fmt.Println("配置Ip是:", ip)
    fmt.Println("配置端口是:", port)
    
    // 会覆盖设置的192.168.80.51
    viper.SetDefault("ip", "192.168.80.59")
    fmt.Println("重新配置Ip是:", viper.GetString("ip"))
    
    // 不会覆盖,因为Set的优先级最高
     viper.SetDefault("port", 9999)
     fmt.Println("重新配置端口是:", viper.GetInt("port"))
}

2.优先级配置

对相同的配置key, 使用不同的api进行赋值设置, 会存在优先级问题,主要有下面几个

  • 显式调用 Set() 方法(最高优先级)

  • 命令行标志(Flags)(注意:必须启动时带了命令参数)

  • 环境变量

  • 配置文件

  • 默认值(最低优先级)

func UsePriority(){
    // 设置
    viper.SetDefault("ip", "192.168.80.59")
    var key string
    pflag.StringVar(&ip, "ip", "", "程序运行的ip")
    pflag.Parse()
    viper.BindPFlags(pflag.CommandLine)
    // 输出命令行设置ip ,因为优先级高
    fmt.Println("配置ip是:", viper.GetString("ip"))
}

// 运行命令 go run main.go 读取配置为192.168.80.59
// 运行命令 go run main.go --ip="127.0.0.1"  读取配置为127.0.0.1
3.将配置写到文件中

可以写入json yaml toml 类型文件

//定义结构体
type Cfg struct {
    Addr string
    No   string
}


func WriteConfigFile() {
    // 设置结构体配置
    viper.Set("info", Cfg{Addr: "湖北武汉", No: 1})
    // 单独设置一个名字
    viper.Set("name", "sa")
    // 设置配置类型
    viper.SetConfigType("json")

    // 写入json格式,文件存在就不写入
    err := viper.SafeWriteConfigAs("config.json")
    if err != nil {
       fmt.Println("写入json配置错误", err)
    } else {
       fmt.Println("写入json配置成功")
    }

    viper.SetConfigType("yaml")
    // 文件yaml存在就不写入
    yamlErr := viper.SafeWriteConfigAs("config.yaml")
    if yamlErr != nil {
       fmt.Println("写入yaml配置错误", yamlErr)
    } else {
       fmt.Println("写入yaml配置成功")
    }

    viper.SetConfigType("toml")
    // 文件toml存在就不写入
    tomlErr := viper.SafeWriteConfigAs("config.toml")
    if tomlErr != nil {
       fmt.Println("写入tomlErr配置错误", tomlErr)
    } else {
       fmt.Println("写入toml配置成功")
    }
}
{
  "info": {
    "Addr": "湖北武汉",
    "No": 1
  },
  "name": "sa"
}
info:
    addr: 湖北武汉
    "no": 1
name: sa
4.读取配置文件中的配置

思路:先设置配置类型,再设置具体文件

func ReadConfigFile() {
     // 设置类型 指定文件
    viper.SetConfigType("json")
    viper.SetConfigFile("config.json")


    readErr := viper.ReadInConfig()
    if readErr != nil {
       fmt.Println("读取配置文件失败", readErr)
       return
    }

    info := viper.Get("info")
    name := viper.Get("name")

    fmt.Println("读取内容为", info)
    fmt.Println("读取内容为", name)
}
5.监听配置文件变化
func MonitorConfigFile() {
    // 先读取旧的值
    ov := viper.New()
    ov.SetConfigType("json")
    ov.SetConfigFile("config.json")
    ov.ReadInConfig()


    // 解析配置
    var config Cfg{}
    if err := viper.Unmarshal(&config); err != nil {
        panic("Failed to unmarshal config: " + err.Error())
    }


    // 设置类型 指定文件
    viper.SetConfigType("json")
    viper.SetConfigFile("config.json")
    viper.WatchConfig()
    viper.OnConfigChange(func(e fsnotify.Event) {
       fmt.Println("配置文件发生变更", e.Name, e.Op)
       fmt.Println("配置文件发生变更前的值是:", ov.Get("info"))
       fmt.Println("配置文件发生变更后的值是:", viper.Get("info"))
    })

    fmt.Println("正在监听....")
    // time.After(5*time.Second)//5秒退出
    // for {

    // } //使用for阻塞
    select {}
}

6.读取环境变量
func ReadEnvVar() {
    viper.AutomaticEnv()
    // 读取全部
    viper.SetEnvPrefix("")
    ACSvcPort := viper.Get("ACSvcPort")
    USERNAME := viper.Get("USERNAME")
    fmt.Println("读取到系统环境变量为:", ACSvcPort, USERNAME)
    viper.SetEnvPrefix("ENV")
    fmt.Println(viper.Get("version"))
}
7.读取命令行
func ReadCmdLine() {
    var ip string
    var port int
    
    // pflag 等于前面加-- go run main.go --ip 192.168.0.1 --port 5020
    // go run main.go -h        查看所有参数
    pflag.StringVar(&ip, "ip", "", "程序运行的ip")
    pflag.IntVar(&port, "port", 0, "程序运行的端口")
    
    pflag.Parse()
    viper.BindPFlags(pflag.CommandLine)

    fmt.Println("程序运行读取ip为", viper.Get("ip"))
    fmt.Println("程序运行读取端口为", viper.Get("port"))
}

posted on 2025-07-27 12:11  yuyuyui  阅读(24)  评论(0)    收藏  举报