golang經常使用庫:gorilla/mux-http路由庫使用
golang經常使用庫:配置文件解析庫-viper使用
golang經常使用庫:操做數據庫的orm框架-gorm基本使用
golang經常使用庫:字段參數驗證庫-validator使用html
viper 配置管理解析庫,是由大神 Steve Francia 開發,他在google領導着 golang 的產品開發,他也是 gohugo.io 的創始人之一,命令行解析庫 cobra 開發者。總之,他在golang領域是專家,很牛的一我的。java
他的github地址:https://github.com/spf13mysql
viper是一個配置管理的解決方案,它可以從 json,toml,ini,yaml,hcl,env 等多種格式文件中,讀取配置內容,它還能從一些遠程配置中心讀取配置文件,如consul,etcd等;它還可以監聽文件的內容變化。git
viper的 logo:
github
配置文件又能夠分爲不一樣的環境,好比dev,test,prod等。golang
viper 能夠幫助你專一配置文件管理。redis
viper 讀取配置文件的優先順序,從高到低,以下:sql
Viper 配置key是不區分大小寫的。數據庫
其實,上面的每一種文件格式,都有一些比較有名的解析庫,如:編程
可是爲啥子要用viper,由於它是一個綜合文件解析庫,包含了上面全部的文件格式解析,是一個集合體,少了配置多個庫的煩惱。
安裝viper命令:
go get github.com/spf13/viper
文檔: https://github.com/spf13/viper/blob/master/README.md#putting-values-into-viper
若是某個鍵經過viper.Set設置了值,那麼這個值讀取的優先級最高
viper.Set("mysql.info", "this is mysql info")
https://github.com/spf13/viper/blob/master/README.md#establishing-defaults
viper 支持默認值的設置。若是配置文件、環境變量、遠程配置中沒有設置鍵值,就能夠經過viper設置一些默認值。
Examples:
viper.SetDefault("ContentDir", "content") viper.SetDefault("LayoutDir", "layouts") viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})
https://github.com/spf13/viper/blob/master/README.md#reading-config-files
讀取配置文件要求:最少要知道從哪一個位置查找配置文件。用戶必定要設置這個路徑。
viper能夠從多個路徑搜索配置文件,單個viper實例只支持單個配置文件。
viper自己沒有設置默認的搜索路徑,須要用戶本身設置默認路徑。
viper搜索和讀取配置文件例子片斷:
viper.SetConfigName("config") // 配置文件的文件名,沒有擴展名,如 .yaml, .toml 這樣的擴展名 viper.SetConfigType("yaml") // 設置擴展名。在這裏設置文件的擴展名。另外,若是配置文件的名稱沒有擴展名,則須要配置這個選項 viper.AddConfigPath("/etc/appname/") // 查找配置文件所在路徑 viper.AddConfigPath("$HOME/.appname") // 屢次調用AddConfigPath,能夠添加多個搜索路徑 viper.AddConfigPath(".") // 還能夠在工做目錄中搜索配置文件 err := viper.ReadInConfig() // 搜索並讀取配置文件 if err != nil { // 處理錯誤 panic(fmt.Errorf("Fatal error config file: %s \n", err)) }
說明:
這裏執行viper.ReadInConfig()以後,viper才能肯定到底用哪一個文件,viper按照上面的AddConfigPath() 進行搜索,找到第一個名爲 config.ext (這裏的ext表明擴展名: 如 json,toml,yaml,yml,ini,prop 等擴展名) 的文件後即中止搜索。
若是有多個名稱爲config的配置文件,viper怎麼搜索呢?它會按照以下順序搜索
- config.json
- config.toml
- config.yaml
- config.yml
- config.properties (這種通常是java中的配置文件名)
- config.props (這種通常是java中的配置文件名)
你還能夠處理一些特殊狀況:
if err := viper.ReadInConfig(); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); ok { // 配置文件沒有找到; 若是須要能夠忽略 } else { // 查找到了配置文件可是產生了其它的錯誤 } } // 查找到配置文件並解析成功
注意[自1.6起]: 你也能夠有不帶擴展名的文件,並以編程方式指定其格式。對於位於用戶$HOME目錄中的配置文件沒有任何擴展名,如.bashrc。
config.toml 配置文件:
# this is a toml title = "toml exaples" redis = "127.0.0.1:3300" # redis [mysql] host = "192.168.1.1" ports = 3306 username = "root" password = "root123456"
viper_toml.go:
package main import( "fmt" "github.com/spf13/viper" ) // 讀取配置文件config type Config struct { Redis string MySQL MySQLConfig } type MySQLConfig struct { Port int Host string Username string Password string } func main() { // 把配置文件讀取到結構體上 var config Config viper.SetConfigName("config") viper.AddConfigPath(".") err := viper.ReadInConfig() if err != nil { fmt.Println(err) return } viper.Unmarshal(&config) //將配置文件綁定到config上 fmt.Println("config: ", config, "redis: ", config.Redis) }
在例子1基礎上多增長一個json的配置文件,config3.json 配置文件:
{ "redis": "127.0.0.1:33000", "mysql": { "port": 3306, "host": "127.0.0.1", "username": "root", "password": "123456" } }
viper_multi.go
package main import ( "fmt" "github.com/spf13/viper" ) type Config struct { Redis string MySQL MySQLConfig } type MySQLConfig struct { Port int Host string Username string Password string } func main() { // 讀取 toml 配置文件 var config1 Config vtoml := viper.New() vtoml.SetConfigName("config") vtoml.SetConfigType("toml") vtoml.AddConfigPath(".") if err := vtoml.ReadInConfig(); err != nil { fmt.Println(err) return } vtoml.Unmarshal(&config1) fmt.Println("read config.toml") fmt.Println("config: ", config1, "redis: ", config1.Redis) // 讀取 json 配置文件 var config2 Config vjson := viper.New() vjson.SetConfigName("config3") vjson.SetConfigType("json") vjson.AddConfigPath(".") if err := vjson.ReadInConfig(); err != nil { fmt.Println(err) return } vjson.Unmarshal(&config2) fmt.Println("read config3.json") fmt.Println("config: ", config1, "redis: ", config1.Redis) }
運行:
$ go run viper_multi.go
read config.toml
config: {127.0.0.1:33000 {0 192.168.1.1 root 123456}} redis: 127.0.0.1:33000
read config3.json
config: {127.0.0.1:33000 {0 192.168.1.1 root 123456}} redis: 127.0.0.1:33000
新建文件夾 item, 在裏面建立文件 config.json,內容以下:
{ "redis": "127.0.0.1:33000", "mysql": { "port": 3306, "host": "127.0.0.1", "username": "root", "password": "123456", "ports": [ 5799, 6029 ], "metric": { "host": "127.0.0.1", "port": 2112 } } }
item/viper_get_item.go 讀取配置項的值
package main import ( "fmt" "github.com/spf13/viper" ) func main() { viper.SetConfigName("config") viper.SetConfigType("json") viper.AddConfigPath(".") err := viper.ReadInConfig() //根據上面配置加載文件 if err != nil { fmt.Println(err) return } host := viper.Get("mysql.host") username := viper.GetString("mysql.username") port := viper.GetInt("mysql.port") portsSlice := viper.GetIntSlice("mysql.ports") metricPort := viper.GetInt("mysql.metric.port") redis := viper.Get("redis") mysqlMap := viper.GetStringMapString("mysql") if viper.IsSet("mysql.host") { fmt.Println("[IsSet()]mysql.host is set") } else { fmt.Println("[IsSet()]mysql.host is not set") } fmt.Println("mysql - host: ", host, ", username: ", username, ", port: ", port) fmt.Println("mysql ports :", portsSlice) fmt.Println("metric port: ", metricPort) fmt.Println("redis - ", redis) fmt.Println("mysqlmap - ", mysqlMap, ", username: ", mysqlMap["username"]) }
運行:
$ go run viper_get_item.go
[IsSet()]mysql.host is set
mysql - host: 127.0.0.1 , username: root , port: 3306
mysql ports : [5799 6029]
metric port: 2112
redis - 127.0.0.1:33000
mysqlmap - map[host:127.0.0.1 metric: password:123456 port:3306 ports: username:root] , username: root
若是把上面的文件config.json寫成toml格式,怎麼解析? 改爲config1.toml:
# toml toml = "toml example" redis = "127.0.0.1:33000" [mysql] port = 3306 host = "127.0.0.1" username = "root" password = "123456" ports = [5799,6029] [mysql.metric] host = "127.0.0.1" port = 2112
其實解析代碼差很少,只需修改2處,
viper.SetConfigName("config") 裏的 config 改爲 config1 ,
viper.SetConfigType("json")裏的 json 改爲 toml,其他代碼都同樣。解析的效果也同樣。
viper獲取值的方法:
新建文件夾 cmd,而後cmd文件夾裏新建config.json文件:
{ "redis":{ "port": 3301, "host": "127.0.0.1" }, "mysql": { "port": 3306, "host": "127.0.0.1", "username": "root", "password": "123456" } }
go解析文件,cmd/viper_pflag.go:
package main import ( "fmt" "github.com/spf13/pflag" "github.com/spf13/viper" ) func main() { pflag.Int("redis.port", 3302, "redis port") viper.BindPFlags(pflag.CommandLine) pflag.Parse() viper.SetConfigName("config") viper.SetConfigType("json") viper.AddConfigPath(".") err := viper.ReadInConfig() //根據上面配置加載文件 if err != nil { fmt.Println(err) return } host := viper.Get("mysql.host") username := viper.GetString("mysql.username") port := viper.GetInt("mysql.port") redisHost := viper.GetString("redis.host") redisPort := viper.GetInt("redis.port") fmt.Println("mysql - host: ", host, ", username: ", username, ", port: ", port) fmt.Println("redis - host: ", redisHost, ", port: ", redisPort) }
1.不加命令行參數運行:
$ go run viper_pflag.go
mysql - host: 127.0.0.1 , username: root , port: 3306
redis - host: 127.0.0.1 , port: 3301
說明:redis.port 的值是 3301,是 config.json 配置文件裏的值。
2.加命令行參數運行
$ go run viper_pflag.go --redis.port 6666
mysql - host: 127.0.0.1 , username: root , port: 3306
redis - host: 127.0.0.1 , port: 6666
說明:加了命令行參數 --redis.port 6666
,這時候redis.port輸出的值爲 6666
,讀取的是cmd命令行的值
viper_ioreader.go
package main import ( "bytes" "fmt" "github.com/spf13/viper" ) func main() { viper.SetConfigType("yaml") var yaml = []byte(` Hacker: true name: steve hobbies: - skateboarding - snowboarding - go clothing: jacket: leather trousers: denim age: 35 eyes : brown beard: true `) err := viper.ReadConfig(bytes.NewBuffer(yaml)) if err != nil { fmt.Println(err) return } hacker := viper.GetBool("Hacker") hobbies := viper.GetStringSlice("hobbies") jacket := viper.Get("clothing.jacket") age := viper.GetInt("age") fmt.Println("Hacker: ", hacker, ",hobbies: ", hobbies, ",jacket: ", jacket, ",age: ", age) }
新建文件 writer/viper_write_config.go:
package main import ( "fmt" "github.com/spf13/viper" ) func main() { viper.SetConfigName("config") viper.SetConfigType("yaml") viper.AddConfigPath(".") viper.Set("yaml", "this is a example of yaml") viper.Set("redis.port", 4405) viper.Set("redis.host", "127.0.0.1") viper.Set("mysql.port", 3306) viper.Set("mysql.host", "192.168.1.0") viper.Set("mysql.username", "root123") viper.Set("mysql.password", "root123") if err := viper.WriteConfig(); err != nil { fmt.Println(err) } }
運行:
$ go run viper_write_config.go
沒有任何輸出表示生成配置文件成功
mysql: host: 192.168.1.0 password: root123 port: 3306 username: root123 redis: host: 127.0.0.1 port: 4405 yaml: this is a example of yaml
若是待生成的文件已經存在,那麼SafeWriteConfig()就會報錯,
Config File "config.yaml" Already Exists
, 而WriteConfig()則會直接覆蓋同名文件。