如何读取.env到结构体?

2022-07-05 11:08:15

用gin写一个练手项目时,始终没找到中意的配置管理包,读取.env环境文件也没找到比较好用的,决定自己写个简单的玩玩!

发现的包如下:

https://github.com/caarlos0/env

https://github.com/joho/godotenv

https://github.com/go-ini/ini

 

目录结构,项目根目录创建config文件夹,用于存放所有相关的配置文件

结构

image.png

配置内容如下

image.png

 

大概思路,先把.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()
}

本文由"putyy"原创,转载无需和我联系,但请注明来自putyy
您的浏览器不支持canvas标签,请您更换浏览器