golang yaml解析添加默认值与校验

2,416 阅读1分钟

gopkg.in/yaml.v3 是golang中最常用的yaml工具包,用此包解析yaml文件到结构体存在三个问题。

  1. yaml文件中的配置项首字母不能大写,配置项名字要求比较严格。
  2. 没有默认值。
  3. 没有数值校验。

解决思路

  1. 把yaml文件解析成map对象在通过json转成struct,利用json的的特性来控制yaml文件中字段名字。
  2. 通过github.com/creasty/def… 这个工具添加默认配置。
  3. 通过github.com/dealancer/v… 这个工具添加校验。 站在巨人肩上干活就是好又快。

代码实现


import (
	"encoding/json"
	"io/ioutil"
	"reflect"

	"github.com/creasty/defaults"
	"gopkg.in/dealancer/validate.v2"
	"gopkg.in/yaml.v3"
)

type YamlConfig struct {
	mapdata map[string]interface{}
	cfg     interface{} //指针类型
}

func NewYamlConfig(cfg interface{}) (*YamlConfig, error) {
	rfv := reflect.ValueOf(cfg)
	if err := ValidatePtr(&rfv); err != nil {
		return nil, err
	}
	return &YamlConfig{cfg: cfg}, nil

}

// read and yaml unmarshal
func (this *YamlConfig) read(in string) error {
	bytes, err := ioutil.ReadFile(in)
	if err != nil {
		return err
	}

	if err := yaml.Unmarshal(bytes, &this.mapdata); err != nil {
		return err
	}
	return nil
}

// json to config obj
// use json tag not yaml
func (this *YamlConfig) jsonDecode() error {
	bytes, err := json.Marshal(this.mapdata)
	if err != nil {
		return err
	}
	// fmt.Println(string(bt), err)
	if err := json.Unmarshal(bytes, this.cfg); err != nil {
		return err
	}
	return nil
}


func (this *YamlConfig) doDefault() error {
	return defaults.Set(this.cfg)
}

func (this *YamlConfig) doValide() error {
	return validate.Validate(this.cfg)
}

func Load(configFile string, in interface{}) error {
	cfg, err := NewYamlConfig(in)
	if err != nil {
		return err
	}

	if err := cfg.read(configFile); err != nil {
		return err
	}

	if err := cfg.jsonDecode(); err != nil {
		return err
	}

	if err := cfg.doDefault(); err != nil {
		return err
	}

	if err := cfg.doValide(); err != nil {
		return err
	}
	return nil
}