手把手带你从0到1封装Gin框架:03 配置初始化&全局变量

422 阅读3分钟

配置文件时每个项目中不可或缺的部分,我们平常用它来统一管理项目中redismysqljwt等所需要的基础配置。

配置文件有很多三方库支持,这里我们选择github.com/spf13/viper,viper支持JSON、 TOML、YAML、HCL、INI等多种格式的配置文件,并且还可以监听文件的变化进行热更新

安装viper

go get github.com/spf13/viper

新增配置文件

创建文件config.yaml

app: # 应用基本配置
  env: dev # 环境名称
  port: 8082 # 服务监听端口号
  name: eve # 应用名称

database:
  driver: mysql # 数据库驱动
  host: 127.0.0.1 # 域名
  port: 3306 # 端口号
  database: eve # 数据库名称
  username: root # 用户名
  password: 12345678 # 密码
  charset: utf8mb4 # 编码格式

以上是我们正常使用的一个配置文件的格式,内容可以根据自己后续使用来自行配置

编写配置文件对应的结构体

我们希望我们的配置文件在项目中是高可读性的,那我们就可以用结构体来承载配置文件的值,这样在后续的使用中就比较方便

新增internal/config/app.go

package config

type App struct {
	Name string
	Port string
	Env  string
}

新增 internal/config/database.go

package config

type Database struct {
	Driver   string
	Host     string
	Port     string
	User     string
	Password string
	Database string
	Charset  string
}

注意: 这里配置的名称需要跟配置文件中的名称一致,也可以通过给结构体新增tag来达到配置文件和结构体名称不一致的目的,如:

type App struct {
	AppName string `mapstructure:"name"`
	AppPort string `mapstructure:"port"`
	AppEnv  string `mapstructure:"env"`
}

这样写也可以,不过为了提高可读性,我们不提倡这种写法

然后我们再新增一个配置文件集合,新增文件internal/config/config.go

// Config 配置文件集合
type Config struct {
	App      App
	Database Database
}

配置文件载入方法

再修改internal/config/config.go文件,新增一个读取配置的GetConfig方法:

package config

import (
	"eve/internal/tool"
	"fmt"
	"github.com/spf13/viper"
)

// Config 配置文件集合
type Config struct {
	App      App
	Database Database
}

// GetConfig 读取配置文件
func GetConfig() (c *Config) {
	// 获取项目的根目录
	rootDir, _ := tool.GetRootDir()

	// 实例化viper,并根据地址读取配置文件
	v := viper.New()
	v.SetConfigFile(rootDir + "/config.yaml")
	err := v.ReadInConfig()
	if err != nil {
		fmt.Println("ReadInConfigError: ", err)
		return
	}

	// 将读取到的配置文件绑定到返回参数c
	err = v.Unmarshal(&c)
	if err != nil {
		fmt.Println("ConfigUnmarshalError: ", err)
		return
	}

	return
}

同时为了获取项目根目录,在eve/internal下新增了一个tool工具库,新增eve/internal/tool/tool.go文件:

package tool

import (
	"os"
	"path/filepath"
)

func GetRootDir() (string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", err
	}
	rootDir, err := filepath.Abs(wd)
	if err != nil {
		return "", err
	}
	return rootDir, nil
}

这样配置文件以及读取功能就完成了

全局变量

上边完成了配置文件的定义以及配置文件的读取,那在项目中如何使用呢?本次我们通过全局变量的形式给其他模块调用,创建internal/global/global.go文件:

package global

import (
	"eve/internal/config"
)

var (
	Config *config.Config
)

上边在global.go文件中创建了一个Config变量,但是还没有赋值,我们希望在项目启动时初始化配置文件以及其他基础模块(如mysqlredis),那就可以通过init方法,init方法在模块加载时会自动执行,创建internal/bootstrap/init.go文件:

package bootstrap

import (
	"eve/internal/config"
	"eve/internal/global"
)

func init() {
	// 初始化配置文件
	global.Config = config.GetConfig()
}

在这个文件中,定义了init方法,方法中初始化了global.Config变量,但是还没有执行,我们可以通过在入口文件中引入该文件的方式来让init方法执行,修改cmd/root.go文件:

// Package cmd /*
package cmd

import (
	_ "eve/internal/bootstrap"
	"github.com/spf13/cobra"
	"os"
)

...

注意看,这里只是在import中新增了一行_ "eve/internal/bootstrap",这样项目用到的初始化工作就会在入口文件处完成,其他模块在使用时可以通过引入eve/internal/global模块来直接使用

总结

  • 安装viper
  • 创建config.yaml配置文件
  • 配置文件载入
  • 新增工具模块
  • 全局变量定义和初始化

commit-hash: 249c1431b