Gin入门(3)-解构项目,从viper和配置文件开始
起因
跟着UP敲完代码之后感觉什么都没搞懂,只得其型不得其意,这样的学习结果毋庸置疑是没有用的,只会陷入教程地狱的困境,所以我决定从头阅读一遍源码,结合文档和大模型,来学习一遍
准备工作
由于跟写的时候是有边用git进行版本控制的,在完工之后我便将云服务器上的工程上传到我的仓库里了:该项目仓库链接
现在我将其拉到GoLand里,因为个人觉得GoLand阅读源码要比Vscode来得更轻松一些
项目结构
可以看到整个项目结构其实很简洁,其本身就是一个很轻量级的后端项目而已
点击查看结构
|_config: 端口、数据库配置文件和代码
|_controller: 控制器代码
|_global: 全局变量管理代码
|_middlewaves: 中间件(登录验证等)
|_models: 数据模型代码
|_router: 路由管理代码
|_utils: 工具和辅助代码
|_go.mod: go包管理
|_go.sum: go包管理
|_main.go: 程序启动入口
|_README.md: 文档
第一份代码main.go
毫无疑问这份代码的入口是main.go
程序,想要查看代码我们就从这里开始
点击查看main.go
package main
import (
"context"
"exchangeapp/config"
"exchangeapp/router"
"log"
"net/http"
"os"
"os/signal"
"time"
)
func main() {
config.InitConfig()
r := router.SteupRouter()
port := config.AppConfig.App.Port
if port == "" {
port = ":8080"
}
srv := &http.Server{
Addr: port,
Handler: r,
}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s\n", err)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt)
<-quit
log.Println("Shutdown Server ...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal("Server Shutdown:", err)
}
log.Println("Server exiting")
}
除去包管理的部分,整个main.go
里也就放了一个仅三十来行的func main
,如果不是有些编码基础加上亲手敲了一遍的话,我可能真会摸不着头脑:为什么这么简短的代码能支撑起Web服务器的响应呢?
当然,光是知道这些代码后面还套娃封装着一堆代码这一概念还不够,我们需要深入它们的实现!
预热之后的第一件事
如果把敲出包管理和func main(){}
当做预热,那预热之后的第一行代码才代表着我们分析的真正开始
WTH is it?
Ctrl+左键点进去呗
嗖的一下很快啊,我们进到了/config/config.go
的func InitConfig()
但是傻眼了,怎么又蹦出了这么多代码?
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath("./config")
先看这三行,来自"github.com/spf13/viper"
包,我们直接去官方文档看
翻译来自智谱清言GLM翻译
懂了,就是能把配置文件什么的读取然后提取成GOLANG能处理的变量什么的,也就是能看作是一种翻译,只不过我们需要按照特定格式
接着看
很简单的解释,我觉得没什么好讲的
重头戏来了
没在我们代码中看到,跳了
兄弟们我们找到了,对照着文档我们马上就能看懂这三行的代码在干嘛了
viper.SetConfigName("config") //配置文件的命名,以便viper定位(不含后缀)
viper.SetConfigType("yaml") //指定读取哪类文件作为配置文件呢?我们这里选择了YAML文件(不写的话也是可以的,viper就会读取文件夹下所有命名为config的文件,不分后缀)
viper.AddConfigPath("./config") //将./config文件夹设置为viper需要读取的配置文件的定位(可以通过多次Add添加更多指定路径)
(关于YAML文件,在这里不再赘述,请自行查阅文档)
错误处理是肯定要有的 经典GOLANG面向if err != nil
编程
if err := viper.ReadInConfig(); err != nil {
log.Fatalf("Error reading config file: %v", err)
}
viper也提供了另一种错误处理方式
关于版本新特性,在这里我们用不到
OK接着看代码
一段莫名其妙的赋值?Ctrl左键看看左边AppConfig
哦,就在上边一点点
Config结构体的具体参数我们留到后边再来回头看,既然没用到的东西我们就先不纠结
不过我们这里要对比一下/config/config.yaml
文件
可以看到一一对应
所以我们这里创建了一个空Config
变量,等待我们用viper读取配置文件为其进行赋值
接着看
还是viper
文档
好嘛,config
结构体文档有教啊 那我不是白敲字了
不过越细的文档越适合新手学习,这真的夸
viper.Unmarshal()
方法能让把我们的config.yaml
配置文件里的「配置信息」“反序列”(我喜欢用“转化”理解它)到AppConfig
这个Config
结构体中的,转化成我们需要操作的变量
最后两行,很明显又是套娃,不过我们从字面上就能理解这是数据库和Redis的初始化
具体实现,之后再讲吧
结语
本篇我们从main
函数的第一句开始,完成了对于config/config.go
的解析,可喜可贺,可口可乐!
如果觉得我的文章写的不错麻烦各位点个赞,你们的支持是我创作的动力
各位下次再见