基礎配置篇:我的博客項目配置文件數據和配置的讀寫處理

上一節,我們已經定義和創建了我們需要的目錄,和項目初始化。這一節我們就可以開始編寫博客配置功能了。

上面我們提到,我們的配置處理函數將存放在config目錄中。我們的項目還需要配置文件。配置文件我們就命名為config.json。它是一個json文件,里面將包含了博客網站的基本信息、數據庫配置信息等。

config.json 配置文件

為了方便查看和讀取config.json,我們將它放在項目的config目錄下。它里面將包含的字段信息有:

{
    "mysql": {
        "database": "irisweb",
        "user": "root",
        "password": "123456",
        "host": "localhost",
        "port": 3306
    },
    "server": {
        "site_name": "irisweb 博客",
        "env": "development",
        "port": 8001,
        "log_level": "debug"
    }
}

字段說明:

  • mysql 字段包含了連接mysql數據庫的信息。database 為數據庫名稱;user 為數據庫用戶名;password 為數據庫密碼;host 為數據庫域名或ip地址;port 為數據庫端口。
  • server 字段包含了博客網站的基本信息。site_name 為網站名稱,網站頁面會調用到;env 為博客網站的開發環境,值為development時,表示開發中,將會輸出一些開發信息供參考,值為production表示部署在生產環境中,程序將不輸出debug信息;port 為博客網站golang運行的端口,通過這個端口可以訪問到網站頁面;log_level 表示日志的記錄級別,值為debug的時候,表示記錄debug級別的信息。

讀取json文件

上面的配置文件config.json定義好并放到config目錄后,我們還需要編寫代碼,讓golang可以讀取它,才能在項目中調用配置文件中的信息。這些文件我們都放置在config文件夾中。

為了方便程序讀取,我們先給上面兩個字段創建兩個承載這些具體字段的結構體:

mysql.go

package config

type mysqlConfig struct {
    Database string `json:"database"`
    User     string `json:"user"`
    Password string `json:"password"`
    Host     string `json:"host"`
    Port     int    `json:"port"`
    Url      string `json:"-"`
}

它對應的是剛才我們定義的json文件中的mysql字段。

結構體的定義是使用關鍵字 type 和 struct 來聲明一個結構體,以關鍵字 type 開始,之后是新類型的名字,最后是關鍵字 struct。

結構體里的字段都有名字,比如上面例子中的 Database 和 User 等等。如果一個字段在代碼中從來不會被用到,那可以把它命名為 _,即空標識符。

結構體變量采用大寫可以從外部訪問到,中間的string、int為這個字段的字段類型,``包含的內容為結構體字段指定一個標記信息,上面的標記表示是json字段的對應字段名稱。

結構體中的字段可以是任何類型,甚至是結構體本身,也可以是函數或者接口。可以聲明結構體類型的一個變量。

同一個包中,不能出現同名的結構體,不同包不受限制。

server.go

package config

type serverConfig struct {
    SiteName string `json:"site_name"`
    Env      string `json:"env"`
    Port     int    `json:"port"`
    LogLevel string `json:"log_level"`
}

server.go對應的的是json文件的server字段。

config.go

package config

type configData struct {
    DB     mysqlConfig  `json:"mysql"`
    Server serverConfig `json:"server"`
}

這個表示config.json的整體結構。

用結構體解析json

解析json需要一些函數來支持,我們將這些函數都寫在config.go 里面。

定義變量

var ExecPath string
var JsonData configData
var ServerConfig serverConfig
var DB *gorm.DB

定義的這四個變量,將是后面我們博客項目中需要使用的變量。

定義執行目錄

func initPath() {
    sep := string(os.PathSeparator)
    //root := filepath.Dir(os.Args[0])
    //ExecPath, _ = filepath.Abs(root
    ExecPath, _ = os.Getwd()
    length := utf8.RuneCountInString(ExecPath)
    lastChar := ExecPath[length-1:]
    if lastChar != sep {
        ExecPath = ExecPath + sep
    }
}

上面主要是獲取運行環境的目錄,來確定項目目錄,它有2種處理方法,一種是使用執行文件所在的目錄,另一種是使用執行命令時所在的目錄。

執行文件所在目錄的獲取方式是:

root := filepath.Dir(os.Args[0])
ExecPath, _ := filepath.Abs(root)

執行命令時所在目錄的獲取方式是:

ExecPath, _ := os.Getwd()

他們的應用場景有所不同,根據實際選擇使用。
為了開發中測試方便,本項目暫時使用執行時目錄。

讀取json文件

func InitJSON() {
    rawConfig, err := ioutil.ReadFile("./config.json")
    if err != nil {
        //未初始化
        fmt.Println("Invalid Config: ", err.Error())
        os.Exit(-1)
    }

    if err := json.Unmarshal(rawConfig, &JsonData); err != nil {
        fmt.Println("Invalid Config: ", err.Error())
        os.Exit(-1)
    }
}

讀取json函數,我們使用ioutil包來將json文件讀取到字節變量中。這里增加了判斷,如果文件不存在,則返回錯誤。接著將內容解析到結構體中,如果是一個標準的json字符串,則這里可以解析成功,如果不成功,則要檢查config.json 是否配置正確了。

解析server

func initServer() {
    ServerConfig = JsonData.Server
}

將server的字段賦值給ServerConfig變量

解析mysql

func InitDB(setting *mysqlConfig) error {
    var db *gorm.DB
    var err error
    url := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
        setting.User, setting.Password, setting.Host, setting.Port, setting.Database)
    setting.Url = url
    db, err = gorm.Open(mysql.Open(url), &gorm.Config{})
    if err != nil {
        return err
    }

    sqlDB, err := db.DB()
    if err != nil {
        return err
    }

    sqlDB.SetMaxIdleConns(1000)
    sqlDB.SetMaxOpenConns(100000)
    sqlDB.SetConnMaxLifetime(-1)

    DB = db

    return nil
}

我們在解析mysql的時候,先組裝好mysql包連接所用的連接字符串,然后通過連接字符串,使用mysql包來打開鏈接,再將mysql連接交給gorm來管理,這樣子,最終我們就可以使用gorm的orm功能了。

在連接完了之后,我們還需要做一些檢測,比如,是否連接成功。
連接成功后,嘗試選擇獲取到連接對象,給連接對象設置空閑時的最大連接數、設置與數據庫的最大打開連接數,每一個連接的生命周期等信息。

在開始的時候執行

func init() {
  initPath()
    //讀取json
    initJSON()
    //讀取server
    initServer()
    //初始化數據庫
    err := InitDB(&JsonData.DB)
    if err != nil {
        fmt.Println("Failed To Connect Database: ", err.Error())
        os.Exit(-1)
    }
}

golang中的init函數是golang的一個特殊函數,它優先于golang的main函數執行,實現包級別的一些初始化操作。

所以,我們可以在這里初始化項目的基本信息,讓后續程序跑起來的時候可以得到設置好的配置信息。

完整的config.go

上面分步解釋了配置文件和配置文件的各個函數,這里將它組合起來成一個完整的文件。

package config

import (
    "encoding/json"
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "io/ioutil"
    "os"
    "unicode/utf8"
)

type configData struct {
    DB     mysqlConfig  `json:"mysql"`
    Server serverConfig `json:"server"`
}

func initPath() {
    sep := string(os.PathSeparator)
    //root := filepath.Dir(os.Args[0])
    //ExecPath, _ = filepath.Abs(root
    ExecPath, _ = os.Getwd()
    length := utf8.RuneCountInString(ExecPath)
    lastChar := ExecPath[length-1:]
    if lastChar != sep {
        ExecPath = ExecPath + sep
    }
}

func initJSON() {
    rawConfig, err := ioutil.ReadFile(fmt.Sprintf("%sconfig.json", ExecPath))
    if err != nil {
        //未初始化
        fmt.Println("Invalid Config: ", err.Error())
        os.Exit(-1)
    }

    if err := json.Unmarshal(rawConfig, &JsonData); err != nil {
        fmt.Println("Invalid Config: ", err.Error())
        os.Exit(-1)
    }
}

func InitDB(setting *mysqlConfig) error {
    var db *gorm.DB
    var err error
    url := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
        setting.User, setting.Password, setting.Host, setting.Port, setting.Database)
    setting.Url = url
    db, err = gorm.Open(mysql.Open(url), &gorm.Config{})
    if err != nil {
        return err
    }

    sqlDB, err := db.DB()
    if err != nil {
        return err
    }

    sqlDB.SetMaxIdleConns(1000)
    sqlDB.SetMaxOpenConns(100000)
    sqlDB.SetConnMaxLifetime(-1)

    DB = db

    return nil
}

func initServer() {
    ServerConfig = JsonData.Server
}

var ExecPath string
var JsonData configData
var ServerConfig serverConfig
var DB *gorm.DB

func init() {
    initPath()
    //讀取json
    initJSON()
    //讀取server
    initServer()
    //初始化數據庫
    err := InitDB(&JsonData.DB)
    if err != nil {
        fmt.Println("Failed To Connect Database: ", err.Error())
        os.Exit(-1)
    }
}

測試結果

config寫完了,我們還需要測試一下。
在根目錄執行go mod命令來將包下載下來

go mod tidy
go mod vendor

完整的項目示例代碼托管在GitHub上,需要查看完整的項目代碼可以到github.com/fesiong/goblog 上查看,也可以直接fork一份來在上面做修改。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容