This is the 8th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Author: lomtom

Personal website: Lomtom.top,

Personal public account: Bosiao Yuan

Your support is my biggest motivation.

The Go series:

  1. Go (1) Basic introduction
  2. Go (ii) structure
  3. Go (3) Go configuration file
  4. Go (4) Redis operation

Those of you who are familiar with SpringBoot and then use Go will find that SpringBoot configuration files are really convenient

At Go, he doesn’t support this, so we’ll have to implement something like a SpringBoot profile ourselves.

Train of thought

Configuration files come in many forms, such as JSON, XML, YML, TOML, or key-value pairs.

Although there are various configuration files, the overall processing steps are generally the same

  1. Writing configuration files
  2. Write structures that correspond to configuration files
  3. Read the configuration file and load it into the appropriate structure

implementation

Because SpringBoot is used, YML files are convenient and concise, so yML files are used as an example here

Writing configuration files

Create a configuration file, name it as you wish, and ensure that the suffix is yML.

server:
  port: 8000
  runMode: debug # release debug
  logLevel: debug # debug info warn error

database:
  type: mysql
  host: localhost
  port: 32306
  username: root
  password: 123456
  dbname: test
  max_idle_conn: 10
  max_open_conn: 30
  conn_max_lifetime: 300

redis:
  host: localhost
  port: 32307
  password:
  db: 0
Copy the code

Here is similar to SpringBoot common configuration, set mysql, redis related Settings

Write structure

The structure needs to correspond to the hierarchy of YML and add YAML :”server” to facilitate system identification

var Server *server
var Database *database
var Redis *myRedis

type conf struct {
	Svc         server   `yaml:"server"`
	DB          database `yaml:"database"`
	RedisConfig myRedis  `yaml:"redis"`
}

type server struct {
	Port     int    `yaml:"port"`
	RunMode  string `yaml:"runMode"`
	LogLevel string `yaml:"logLevel"`
}

type database struct {
	Type            string `yaml:"type"`
	Host            string `yaml:"host"`
	Port            string `yaml:"port"`
	UserName        string `yaml:"username"`
	Password        string `yaml:"password"`
	DbName          string `yaml:"dbname"`
	MaxIdleConn     int    `yaml:"max_idle_conn"`
	MaxOpenConn     int    `yaml:"max_open_conn"`
	ConnMaxLifetime int    `yaml:"conn_max_lifetime"`
}

type myRedis struct {
	Host     string `yaml:"host"`
	Port     string `yaml:"port"`
	Password string `yaml:"password"`
	DB       int    `yaml:"db"`
}
Copy the code

Of course, they can also rewrite their String method, so that when the project starts, it can be ordered to print, and also easier to see if the configuration file has been loaded successfully

func (c conf) String(a) string {
	return fmt.Sprintf("%v\n%v\n%v", c.Svc, c.DB, c.RedisConfig)
}

func (s server) String(a) string {
	return fmt.Sprintf("server : \n"+
		"\tport : %v \n"+
		"\tRunMode : %v", s.Port, s.RunMode)
}

func (m database) String(a) string {
	return fmt.Sprintf("database : \n"+
		"\ttype : %v \n"+
		"\thost : %v \n"+
		"\tport : %v \n"+
		"\tusername : %v \n"+
		"\tpassword : %v \n"+
		"\tdbname : %v \n"+
		"\tmax_idle_conn : %v \n"+
		"\tmax_open_conn : %v \n"+
		"\tconn_max_lifetime : %v",
		m.Type, m.Host, m.Port, m.UserName, m.Password, m.DbName, m.MaxOpenConn, m.MaxIdleConn, m.ConnMaxLifetime)
}
func (r myRedis) String(a) string {
	return fmt.Sprintf("redis : \n"+
		"\thost : %v \n"+
		"\tport : %v \n"+
		"\tPassword : %v \n"+
		"\tdb : %v",
		r.Host, r.Port, r.Password, r.DB)
}
Copy the code

Read the file

Big time!!

Premise: Introduce dependencies

go get gopkg.in/yaml.v2
Copy the code

All you need to do is read the information from the configuration file and bind it to the appropriate structure.

func InitConf(dataFile string) {
	// Resolve the problem that the configuration file cannot be obtained in the relative path
	_, filename, _, _ := runtime.Caller(0)
	filePath := path.Join(path.Dir(filename), dataFile)
	_, err := os.Stat(filePath)
	iferr ! =nil {
		log.Printf("config file path %s not exist", filePath)
	}
	yamlFile, err := ioutil.ReadFile(filePath)
	iferr ! =nil {
		log.Printf("yamlFile.Get err #%v ", err)
	}
	c := new(conf)
	err = yaml.Unmarshal(yamlFile, &c)
	iferr ! =nil {
		log.Printf("Unmarshal: %v", err)
	}
	log.Printf("load conf success\n %v", c)
	// Bind to externally accessible variables
	Server = &c.Svc
	Database = &c.DB
	Redis = &c.RedisConfig
}
Copy the code

If the file cannot be read using relative path, you can add the following code

_, filename, _, _ := runtime.Caller(0)
	filePath := path.Join(path.Dir(filename), dataFile)
Copy the code

use

Load the configuration file, which can be loaded in the init method (the project starts automatically without calling)

func init(a) {
	// Load the configuration file
	config.InitConf(".. /.. /config/app-dev.yaml")}Copy the code

Note that the path is the path of the reading configuration file tool relative to the configuration file, not the path of the init method relative to the configuration file

├ ─ config │ └ ─ app - dev. Yaml └ ─ util │ └ ─ config │ └ ─ ConfigUtil. Go └ ─ main. GoCopy the code

Call the structure directly when using it

For example, you need to specify gin mode, which corresponds to server. RunMode, and so on

func InitRouters(a) *gin.Engine {
	r := gin.Default()
	gin.SetMode(config.Server.RunMode)
	return r
}
Copy the code