用gin写一个练手项目时,始终没找到中意的配置管理包,读取.env环境文件也没找到比较好用的,决定自己写个简单的玩玩!
发现的包如下:
https://github.com/caarlos0/env
https://github.com/joho/godotenv
目录结构,项目根目录创建config文件夹,用于存放所有相关的配置文件
结构
配置内容如下
大概思路,先把.env拆分成map, 再读取相关结构体tag配置对应的值, app.go文件内容如下
package config
import (
"bufio"
"fmt"
"io"
"os"
"reflect"
"regexp"
"strconv"
"strings"
)
type AppConfig struct {
// 版本号
Version string `env:"VERSION"`
// 运行模式
RunMode string `env:"RUN_MODE"`
// 服务端口
HTTPPort int `env:"HTTP_PORT"`
// 读写超时
ReadTimeout int64 `env:"READ_TIMEOUT"`
WriteTimeout int64 `env:"WRITE_TIMEOUT"`
// 分页每一页数量
PageSize int `env:"PAGE_SIZE" default:"10"`
}
var (
App AppConfig
Mysql MysqlConfig
Redis RedisConfig
Jwt JwtConfig
Qiniu QiniuConfig
)
var config = make(map[string]string)
func init() {
inputFile, inputError := os.Open("./.env")
if inputError != nil {
fmt.Printf("open env file error: %s!", inputError.Error())
return
}
defer inputFile.Close()
inputReader := bufio.NewReader(inputFile)
var reg *regexp.Regexp
for {
inputString, readerError := inputReader.ReadString('\n')
if readerError == io.EOF {
break
}
reg = regexp.MustCompile("\\s+")
if reg.ReplaceAllString(inputString, "") == "" {
continue
}
s := strings.Split(inputString, "=")
s[1] = strings.Trim(s[1], "\r\n")
s[1] = strings.Trim(s[1], "\"")
config[s[0]] = s[1]
}
reflectParse(&App)
reflectParse(&Mysql)
reflectParse(&Redis)
reflectParse(&Jwt)
reflectParse(&Qiniu)
}
func reflectParse(c interface{}) {
rValue := reflect.ValueOf(c)
rType := reflect.TypeOf(c)
if rType.Kind() != reflect.Ptr {
fmt.Print("Can only be pointer type")
return
}
rValue = rValue.Elem()
rType = rType.Elem()
for i := 0; i < rType.NumField(); i++ {
envValue := ""
tField := rType.Field(i)
vField := rValue.Field(i)
env := tField.Tag.Get("env")
dValue := tField.Tag.Get("default")
if env != "" {
configValue, ok := config[env]
if ok {
envValue = configValue
} else {
envValue = dValue
}
} else if dValue != "" {
envValue = dValue
}
rFieldType := tField.Type.Kind()
if rFieldType == reflect.String {
vField.Set(reflect.ValueOf(envValue))
} else if rFieldType == reflect.Int {
tmpEnvValue, _ := strconv.Atoi(envValue)
vField.Set(reflect.ValueOf(tmpEnvValue))
} else if rFieldType == reflect.Int64 {
tmpEnvValue, _ := strconv.ParseInt(envValue, 10, 64)
vField.Set(reflect.ValueOf(tmpEnvValue))
} else if rFieldType == reflect.Float64 {
tmpEnvValue, _ := strconv.ParseFloat(envValue, 64)
vField.Set(reflect.ValueOf(tmpEnvValue))
} else if rFieldType == reflect.Float32 {
tmpEnvValue, _ := strconv.ParseFloat(envValue, 32)
vField.Set(reflect.ValueOf(float32(tmpEnvValue)))
}
}
}
使用
例如: gin main.go
package main
import (
"fmt"
"github.com/putyy/ai-share-server/config"
"github.com/putyy/ai-share-server/router"
"net/http"
"time"
)
func main() {
s := &http.Server{
Addr: fmt.Sprintf(":%d", config.App.HTTPPort),
Handler: router.InitRouter(),
ReadTimeout: time.Duration(config.App.ReadTimeout) * time.Second,
WriteTimeout: time.Duration(config.App.WriteTimeout) * time.Second,
MaxHeaderBytes: 1 << 20,
}
s.ListenAndServe()
}