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.gofunc 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的解析,可喜可贺,可口可乐!

如果觉得我的文章写的不错麻烦各位点个赞,你们的支持是我创作的动力

各位下次再见

作者:Chuan81原文地址:https://www.cnblogs.com/Chuan81/p/18820589

%s 个评论

要回复文章请先登录注册