Go viper包处理JSON笔记

第一部分 前景提要

一、背景
用Go搭一个小项目, 按传统的套路把开发环境和生产环境配置信息写在配置文件config.json中, 初始化加载配置,解析出数据。看着是解析一个JSON的小事,过程中却发生了3次演进:

1、定义一个配置文件对应的结构体。
2、递归加载配置的全部节点。
3、使用viper

思路1: 是最初的想法,考虑到动态加配置的话,还需要改结构体,这就有点low了,故而并没有实施,仅停留在思考层面;
思路2: 参考网上的一个实现,拿来简单调整了下,发现挺好用,但是发现不能获取一个子节点下的全部key, 要自己实现的话,看看项目的排期,是肯定来不及的;
思路3: 是用现有的开源包viper, 确实好用。

本文就把没有实现和实现了的方案都在这里模拟实现下,希望顺便解释了为什么读个JOSN文件还要用包viper

config.json内容大致如下

{
    "dev": {
        "dockerAddr": "xxx",
        "appName":    "office",
        "version":    "20210315115158",
        "tag":        "1",
        "etcdEnv": {
            "endpoint": "https://xxx,https://xxx",
            "namespace": "v10",
            "prefix": "v10",
            "user": "xxx",
            "password": "xxx"
        }
    },
    "online": {
        "dockerAddr": "xxx",
        "appName":    "office",
        "version":    "20210315115158",
        "tag":        "1",
        "etcdEnv": {
            "endpoint": "https://xxx,https://xxx",
            "namespace": "v10",
            "prefix": "v10",
            "user": "xxx",
            "password": "xxx"
        }
    },
}

第二部分 定义结构体

一、Go 处理JSON标准库
Go内置处理JSON标准库是encoding/json

其中,两个常用的方法为Marshal和Unmarshal, 分别实现数据的序列号和反序列化。

1、Marshal

func Marshal(v interface{}) ([]byte, error)

2、Unmarshal

func Unmarshal(data []byte, v interface{}) error

二、具体实现
为什么要定义一个结构体,定义一个map不行咩
1、map可转json
https://www.jianshu.com/p/f7f930152482

2、json转map
https://blog.csdn.net/lanyang123456/article/details/78930071

3、struct转json
https://www.cnblogs.com/liuhe688/p/10971327.html

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
)

type EtcdConfig struct {
	Endpoint  string
	Namespace string
	Prefix    string
	User      string
	Password  string
}

type BaseConfig struct {
	DockerAddr string
	AppName    string
	Version    int
	Tag        string
	EtcdEnv    EtcdConfig
}

// Dev和Online必须和json中同名,不然返回空
type Config struct {
	Dev    BaseConfig
	Online BaseConfig
}

func main() {
	var config Config
	data, err := ioutil.ReadFile("conf/config.json")
	if err != nil {
		panic(err)
	}

	err = json.Unmarshal(data, &config)
	if err != nil {
		panic(err)
	}
	fmt.Println(config) /
}

以上输出

{{xxx office-dev 101 20210315115158 {https://xxx,https://xxx v10 v10 xxx xxx}} {xxx office-online 1001 20210315115158 {https://xxx,https://xxx v10 v10 xxx xxx}}}

第三部分 递归加载配置

1、加载配置的config包

package config

import (
	"encoding/json"
	"os"
)

const (
	defaultConfigPath = "conf/config.json"
)

var (
	raw    map[string]interface{}
	config = make(map[string]interface{})
)

func loadConfigs(prefix string, o interface{}) {
	if m, ok := o.(map[string]interface{}); ok {
		if len(prefix) > 0 {
			prefix = prefix + ":"
		}

		for k, v := range m {
			key := prefix + k
			loadConfigs(key, v)
		}
	} else {
		config[prefix] = o
	}
}

func LoadConfigs() (err error) {
	file, err := os.Open(defaultConfigPath)
	if err != nil {
		panic(err)
		return
	}

	decoder := json.NewDecoder(file)
	err = decoder.Decode(&raw)
	loadConfigs("", raw)
	return
}

func String(key string, defaultValue string) (value string) {
	value, _ = getString(key, defaultValue)
	return
}

func getString(key string, defaultValue string) (value string, found bool) {
	v, found := config[key]
	if !found {
		return defaultValue, false
	}
	if value, ok := v.(string); ok {
		return value, ok
	} else {
		return defaultValue, false
	}
}

完整内容参考:Go 项目如何加载 config.json 格式的配置文件

2、用法
用冒号分割key, 直接取值即可

func init() {
	config.LoadConfigs()
	addr := config.String("dev:dockerAddr", "")
	fmt.Println(addr)
}

第四部分 使用包viper

一、关于viper
1、一个优秀的读取配置Go包
2、github地址:https://github.com/spf13/viper

二、用法

viper.AddConfigPath("./conf/")
	viper.SetConfigName("server")
	err := viper.ReadInConfig() // 读取配置数据
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

三、其他详细用法参考
在 Go 中使用 Viper 加载配置文件
Go语言配置管理神器——Viper中文教程
Go 每日一库之 viper

Go Struct超详细讲解
细说Golang的JSON解析

发表评论

电子邮件地址不会被公开。 必填项已用*标注