基础配置篇:我的博客项目配置文件数据和配置的读写处理

上一节,我们已经定义和创建了我们需要的目录,和项目初始化。这一节我们就可以开始编写博客配置功能了。

上面我们提到,我们的配置处理函数将存放在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一份来在上面做修改。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容