Reading configuration Files

1. Add the configuration initialization entry to the main function

  1. Import the viper package first
import(..."github.com/spf13/pflag"
	"github.com/spf13/viper"
	"log"
	
)
Copy the code
  1. Config.init (* CFG) was added to the main function to initialize the configuration. The CFG variable value is passed in from the command line flag, such as./apiserver -c config.yaml, or can be null. If null, conf/config.yaml is read by default.
	iferr:=config.Init(*cfg) ; err ! =nil {
		panic(err)
	}
Copy the code
  1. Change the corresponding configuration to read from the configuration file config.yaml(configuration contents are as follows), such as the program port number, IP address, operation mode,
runmode: debug                 Debug, release, test
addr: : 8080                  # HTTP binding port
name: apiserver              # API Server name
url: http://127.0.0.1:8080   The API server IP address requested by the # pingServer function :port
max_ping_count: 10           The number of times the function try is pingServer
Copy the code

The complete code is as follows:

import(..."github.com/spf13/pflag"
	"github.com/spf13/viper"
	"log"
	
)
var (
	cfg = pflag.StringP("config"."c".""."apiserver config file path."))func main(a) {
	pflag.Parse()

	iferr:=config.Init(*cfg) ; err ! =nil {
		panic(err)
	}
	// Create the Gin engine.
	g := gin.New()
     gin.SetMode(viper.GetString("runmode"))

	middlewares := []gin.HandlerFunc{}

	// Routes.
	router.Load(
		// Cores.
		g,

		// Middlwares.
		middlewares...,
	)

	// Ping the server to make sure the router is working.
	go func(a) {
		iferr := pingServer(); err ! =nil {
			log.Fatal("The router has no response, or it might took too long to start up.", err)
		}
		log.Print("The router has been deployed successfully.")
	}()

	log.Printf("Start to listening the incoming requests on http address: %s", viper.GetString("addr"))
	log.Printf(http.ListenAndServe(viper.GetString("addr"), g).Error())
}
Copy the code

2. Parse the configured functions

  1. Func Init(CFG string) If CFG is not empty, load the specified configuration file. Otherwise, load the default configuration file and call the function that monitors the configuration file.
func Init(cfg string) error {
	c := Config {
		Name: cfg,
	}

	// Initialize the configuration file
	iferr := c.initConfig(); err ! =nil {
		return err
	}

	// Monitor configuration file changes and hot load programs
	c.watchConfig()

	return nil
}
Copy the code
  1. Func (c *Config) watchConfig The viper setting of this function enables viper to monitor configuration file changes and hot update the program if there are changes. Hot update means that the API can load the value of the latest configuration item without restarting the API process.
func (c *Config) watchConfig(a) {
	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		log.Printf("Config file changed: %s", e.Name)
	})
}
Copy the code
  1. Func (c *Config) initConfig() error calls the methods provided by the Viper package to read the required configuration
func (c *Config) initConfig(a) error {
	ifc.Name ! ="" {
		viper.SetConfigFile(c.Name) // If a profile is specified, the specified profile is parsed
	} else {
		viper.AddConfigPath("conf") // If no profile is specified, the default profile is parsed
		viper.SetConfigName("config")
	}
	viper.SetConfigType("yaml") // Set the configuration file format to YAML
	viper.AutomaticEnv() // Read the matching environment variable
	viper.SetEnvPrefix("APISERVER") // Read environment variables prefixed with APISERVER
	replacer := strings.NewReplacer("."."_") 
	viper.SetEnvKeyReplacer(replacer)
	iferr := viper.ReadInConfig(); err ! =nil { // Viper parses the configuration file
		return err
	}

	return nil
}
Copy the code

The complete code is as follows:

package config

import (
	"log"
	"strings"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
)

type Config struct {
	Name string
}

func Init(cfg string) error {
	c := Config {
		Name: cfg,
	}

	// Initialize the configuration file
	iferr := c.initConfig(); err ! =nil {
		return err
	}

	// Monitor configuration file changes and hot load programs
	c.watchConfig()

	return nil
}

func (c *Config) initConfig(a) error {
	ifc.Name ! ="" {
		viper.SetConfigFile(c.Name) // If a profile is specified, the specified profile is parsed
	} else {
		viper.AddConfigPath("conf") // If no profile is specified, the default profile is parsed
		viper.SetConfigName("config")
	}
	viper.SetConfigType("yaml") // Set the configuration file format to YAML
	viper.AutomaticEnv() // Read the matching environment variable
	viper.SetEnvPrefix("APISERVER") // Read environment variables prefixed with APISERVER
	replacer := strings.NewReplacer("."."_") 
	viper.SetEnvKeyReplacer(replacer)
	iferr := viper.ReadInConfig(); err ! =nil { // Viper parses the configuration file
		return err
	}

	return nil
}

// Monitor configuration file changes and hot load programs
func (c *Config) watchConfig(a) {
	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		log.Printf("Config file changed: %s", e.Name)
	})
}

Copy the code

Database connection

1. The ORM framework

Apiserver’s ORM is the gorM with the most stars on GitHub. It is easier to use, more stable, and has a more active community than any other ORM. Gorm has the following features:

  • Fully functional ORM (Infinite Proximity)
  • (Has One, Has Many, Belongs To, Many To Many, polymorphism)
  • Hooks (before or after creating/saving/updating/deleting/finding)
  • preload
  • The transaction
  • Composite primary key
  • SQL generator
  • Automatic database migration
  • Custom Logs
  • Extensible, plug-ins can be written based on GORM callbacks
  • All features are covered by tests
  • Developer friendly

2. Establish a data connection

1. In the configuration file, set database parameters

db:
  name: db_apiserver
  addr: 127.0. 01.: 3306
  username: root
  password: root
docker_db:
  name: db_apiserver
  addr: 127.0. 01.: 3306
  username: root
  password: root
Copy the code
  1. Create the database connection structure and initialize the connection
type Database struct {
	Self *gorm.DB
	Docker *gorm.DB
}
func (db *Database) Init(a) {
	DB = &Database{
		Self:   GetSelfDB(),
		Docker: GetDockerDB(),
	}
}
Copy the code

3. Open the connection based on the user name and password

func openDB(username,password,addr,name string) *gorm.DB  {
	config :=fmt.Sprintf("%s:%s@tcp(%s)/%s? charset=utf8&parseTime=%t&loc=%s",
		username,
		password,
		addr,
		name,
		true.//"Asia/Shanghai"),
		"Local")
	db, err := gorm.Open("mysql", config)
	iferr! =nil{
		log.Printf("Database connection failed. Database name: %s", name)
	}
	setupDB(db)
	return db
}
Copy the code