文件结构
本节将完全按照 ginvueadmin 中配置 viper 的方式作为详解,同时分析 config.yaml
本小节用到的所有文件及其对应作用
路径起点为项目根目录
路径及文件名 | 作用 |
---|---|
main.go | 主入口 |
config.yaml | 配置文件 |
global\global.go | 全局变量 |
core\viper.go | 初始化 viper |
core\constant.go | 常量定义 |
config\config.go | 管理全部的配置 |
config\jwt.go | config 下辖 jwt 对象 |
config\local.go | config 下辖 local 对象 |
config\system.go | config 下辖 system 对象 |
config.yaml
根目录下新建文件 config.yaml
没什么可说的,编写配置文件
这里写了三个对象,这三个对象也是我们后续需要定义的三个结构体
jwt:
signing-key: signJwt
expires-time: 2d
buffer-time: 1d
issuer: zhiller
system:
port: 10086
local:
path: uploads/file
store-path: uploads/file
global.go
新建文件 global/global.go
在这定义全部的全局变量,后续将在主入口中执行对应初始化过程
这里定义了三个全局变量,我们此次仅需要使用 G_VIPER
import (
"ginlogin/config"
"github.com/spf13/viper"
"gorm.io/gorm"
"sync"
)
var (
G_DB *gorm.DB // 数据库
G_VIPER *viper.Viper // viper原始对象
G_CONFIG config.Server // 序列化后的对象,之后存取变量都用它
lock sync.RWMutex
)
定义结构体
以下四个文件存放于 config 文件夹下
我们注意到之前在 config.yaml
中定义了四个对象 jwt、local、system
当我们使用 viper 实例进行数据读取时,一般都会指定数据类型(比如 viper.GetString(“xxx”)),非常麻烦
而为每一个配置项都定义一个结构体,在结构体内就把类型都定义好,使用 viper 的 unmarshal 方法将 config.yaml 中的配置项一一映射到结构体内,之后随取随用即可
接下来我们就需要为这三个对象定义对应的结构体,除此之外 config.yaml 还需要配置一个单独的总结构体
结构体之间是嵌套的,不可以缺少任意一个,否则 unmarshal 会报错
首先是 config.yaml 整体的结构
// 文件 config.go
type Server struct {
JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"`
System System `mapstructure:"system" json:"system" yaml:"system"`
Local Local `mapstructure:"local" json:"local" yaml:"local"`
}
接下来就是三个对象
// 文件 jwt.go
type JWT struct {
SigningKey string `mapstructure:"signing-key" json:"signing-key" yaml:"signing-key"` // jwt签名
ExpiresTime string `mapstructure:"expires-time" json:"expires-time" yaml:"expires-time"` // 过期时间
BufferTime string `mapstructure:"buffer-time" json:"buffer-time" yaml:"buffer-time"` // 缓冲时间
Issuer string `mapstructure:"issuer" json:"issuer" yaml:"issuer"` // 签发者
}
// 文件 local.go
type Local struct {
Path string `mapstructure:"path" json:"path" yaml:"path"` // 本地文件访问路径
StorePath string `mapstructure:"store-path" json:"store-path" yaml:"store-path"` // 本地文件存储路径
}
// 文件 system.go
type System struct {
PORT int `mapstructure:"port" json:"port" yaml:"port"`
}
常量域
新建存储常量的文件 core/constant.go
由于 config.yaml 本来就在根目录,所以路径直接写文件名即可
const (
CONFIG_PATH = "config.yaml"
)
viper.go
import (
"fmt"
"ginlogin/global"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
)
func Viper() *viper.Viper {
// 实例化viper对象,指定文件路径以及对应的文件类型
v := viper.New()
v.SetConfigFile(CONFIG_PATH)
v.SetConfigType("yaml")
// 读配置文件
err := v.ReadInConfig()
if err != nil {
fmt.Errorf("发生错误:%s \n", err)
}
// 监听配置文件的变化
v.WatchConfig()
// 每次修改配置文件中的配置项,都重新unmarshal一次
v.OnConfigChange(func(evt fsnotify.Event) {
fmt.Println("配置文件发生改变", evt.Name)
// 注意使用 & 引用
if err = v.Unmarshal(&global.G_CONFIG); err != nil {
fmt.Println(err)
}
})
// 首次unmarshal
if err = v.Unmarshal(&global.G_CONFIG); err != nil {
fmt.Println(err)
}
// viper配置完毕后我们说一句话,证明成功配置了
fmt.Println("当前服务器运行端口:", global.G_CONFIG.System.PORT)
// 返回viper实例
return v
}
主入口
根目录下 main.go
为 viper 全局变量赋予指定实例
import (
"ginlogin/core"
"ginlogin/global"
)
func main() {
global.G_VIPER = core.Viper()
...
}