上一節(jié)柳骄,我們已經(jīng)定義和創(chuàng)建了我們需要的目錄团赏,和項目初始化。這一節(jié)我們就可以開始編寫博客配置功能了耐薯。
上面我們提到舔清,我們的配置處理函數(shù)將存放在config
目錄中。我們的項目還需要配置文件曲初。配置文件我們就命名為config.json
体谒。它是一個json文件,里面將包含了博客網(wǎng)站的基本信息臼婆、數(shù)據(jù)庫配置信息等抒痒。
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數(shù)據(jù)庫的信息评汰。database
為數(shù)據(jù)庫名稱;user
為數(shù)據(jù)庫用戶名痢虹;password
為數(shù)據(jù)庫密碼被去;host
為數(shù)據(jù)庫域名或ip地址;port
為數(shù)據(jù)庫端口奖唯。 -
server
字段包含了博客網(wǎng)站的基本信息惨缆。site_name
為網(wǎng)站名稱,網(wǎng)站頁面會調(diào)用到;env
為博客網(wǎng)站的開發(fā)環(huán)境坯墨,值為development時寂汇,表示開發(fā)中,將會輸出一些開發(fā)信息供參考捣染,值為production表示部署在生產(chǎn)環(huán)境中骄瓣,程序?qū)⒉惠敵鰀ebug信息;port
為博客網(wǎng)站golang運行的端口耍攘,通過這個端口可以訪問到網(wǎng)站頁面榕栏;log_level
表示日志的記錄級別,值為debug的時候蕾各,表示記錄debug級別的信息扒磁。
讀取json文件
上面的配置文件config.json
定義好并放到config目錄后,我們還需要編寫代碼式曲,讓golang可以讀取它妨托,才能在項目中調(diào)用配置文件中的信息。這些文件我們都放置在config
文件夾中吝羞。
為了方便程序讀取兰伤,我們先給上面兩個字段創(chuàng)建兩個承載這些具體字段的結(jié)構(gòu)體:
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:"-"`
}
它對應(yīng)的是剛才我們定義的json文件中的mysql字段。
結(jié)構(gòu)體的定義是使用關(guān)鍵字 type 和 struct 來聲明一個結(jié)構(gòu)體钧排,以關(guān)鍵字 type 開始医清,之后是新類型的名字,最后是關(guān)鍵字 struct卖氨。
結(jié)構(gòu)體里的字段都有名字,比如上面例子中的 Database 和 User 等等负懦。如果一個字段在代碼中從來不會被用到筒捺,那可以把它命名為 _,即空標識符纸厉。
結(jié)構(gòu)體變量采用大寫可以從外部訪問到系吭,中間的string、int為這個字段的字段類型颗品,``包含的內(nèi)容為結(jié)構(gòu)體字段指定一個標記信息肯尺,上面的標記表示是json字段的對應(yīng)字段名稱。
結(jié)構(gòu)體中的字段可以是任何類型躯枢,甚至是結(jié)構(gòu)體本身则吟,也可以是函數(shù)或者接口〕澹可以聲明結(jié)構(gòu)體類型的一個變量氓仲。
同一個包中,不能出現(xiàn)同名的結(jié)構(gòu)體,不同包不受限制敬扛。
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對應(yīng)的的是json文件的server字段晰洒。
config.go
package config
type configData struct {
DB mysqlConfig `json:"mysql"`
Server serverConfig `json:"server"`
}
這個表示config.json的整體結(jié)構(gòu)。
用結(jié)構(gòu)體解析json
解析json需要一些函數(shù)來支持啥箭,我們將這些函數(shù)都寫在config.go 里面谍珊。
定義變量
var ExecPath string
var JsonData configData
var ServerConfig serverConfig
var DB *gorm.DB
定義的這四個變量,將是后面我們博客項目中需要使用的變量急侥。
定義執(zhí)行目錄
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
}
}
上面主要是獲取運行環(huán)境的目錄砌滞,來確定項目目錄,它有2種處理方法缆巧,一種是使用執(zhí)行文件所在的目錄布持,另一種是使用執(zhí)行命令時所在的目錄。
執(zhí)行文件所在目錄的獲取方式是:
root := filepath.Dir(os.Args[0])
ExecPath, _ := filepath.Abs(root)
執(zhí)行命令時所在目錄的獲取方式是:
ExecPath, _ := os.Getwd()
他們的應(yīng)用場景有所不同陕悬,根據(jù)實際選擇使用题暖。
為了開發(fā)中測試方便,本項目暫時使用執(zhí)行時目錄捉超。
讀取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函數(shù)胧卤,我們使用ioutil包來將json文件讀取到字節(jié)變量中。這里增加了判斷拼岳,如果文件不存在枝誊,則返回錯誤。接著將內(nèi)容解析到結(jié)構(gòu)體中惜纸,如果是一個標準的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功能了。
在連接完了之后亭引,我們還需要做一些檢測绎速,比如,是否連接成功痛侍。
連接成功后朝氓,嘗試選擇獲取到連接對象魔市,給連接對象設(shè)置空閑時的最大連接數(shù)、設(shè)置與數(shù)據(jù)庫的最大打開連接數(shù)赵哲,每一個連接的生命周期等信息待德。
在開始的時候執(zhí)行
func init() {
initPath()
//讀取json
initJSON()
//讀取server
initServer()
//初始化數(shù)據(jù)庫
err := InitDB(&JsonData.DB)
if err != nil {
fmt.Println("Failed To Connect Database: ", err.Error())
os.Exit(-1)
}
}
golang中的init函數(shù)是golang的一個特殊函數(shù),它優(yōu)先于golang的main函數(shù)執(zhí)行枫夺,實現(xiàn)包級別的一些初始化操作将宪。
所以,我們可以在這里初始化項目的基本信息橡庞,讓后續(xù)程序跑起來的時候可以得到設(shè)置好的配置信息较坛。
完整的config.go
上面分步解釋了配置文件和配置文件的各個函數(shù),這里將它組合起來成一個完整的文件扒最。
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()
//初始化數(shù)據(jù)庫
err := InitDB(&JsonData.DB)
if err != nil {
fmt.Println("Failed To Connect Database: ", err.Error())
os.Exit(-1)
}
}
測試結(jié)果
config寫完了丑勤,我們還需要測試一下。
在根目錄執(zhí)行g(shù)o mod命令來將包下載下來
go mod tidy
go mod vendor
完整的項目示例代碼托管在GitHub上吧趣,需要查看完整的項目代碼可以到github.com/fesiong/goblog 上查看法竞,也可以直接fork一份來在上面做修改。