3.2 Gin搭建Blog API's (一)

项目地址:https://github.com/EDDYCJY/go-gin-example

思考

首先,在一个初始项目开始前,大家都要思考一下

  • 程序的文本配置写在代码中,好吗?

  • API 的错误码硬编码在程序中,合适吗?

  • db句柄谁都去Open,没有统一管理,好吗?

  • 获取分页等公共参数,谁都自己写一套逻辑,好吗?

显然在较正规的项目中,这些问题的答案都是不可以,为了解决这些问题,我们挑选一款读写配置文件的库,目前比较火的有 viper,有兴趣你未来可以简单了解一下,没兴趣的话等以后接触到再说。

但是本系列选用 go-ini/ini ,它的 中文文档。大家是必须需要要简单阅读它的文档,再接着完成后面的内容。

本文目标

  • 编写一个简单的API错误码包。

  • 完成一个 Demo 示例。

  • 讲解 Demo 所涉及的知识点。

介绍和初始化项目

初始化项目目录

在前一章节中,我们初始化了一个 go-gin-example 项目,接下来我们需要继续新增如下目录结构:

  • conf:用于存储配置文件

  • middleware:应用中间件

  • models:应用数据库模型

  • pkg:第三方包

  • routers 路由逻辑处理

  • runtime:应用运行时数据

添加 Go Modules Replace

打开 go.mod 文件,新增 replace 配置项,如下:

可能你会不理解为什么要特意跑来加 replace 配置项,首先你要看到我们使用的是完整的外部模块引用路径(github.com/EDDYCJY/go-gin-example/xxx),而这个模块还没推送到远程,是没有办法下载下来的,因此需要用 replace 将其指定读取本地的模块路径,这样子就可以解决本地模块读取的问题。

注:后续每新增一个本地应用目录,你都需要主动去 go.mod 文件里新增一条 replace(我不会提醒你),如果你漏了,那么编译时会出现报错,找不到那个模块。

初始项目数据库

新建 blog 数据库,编码为utf8_general_ci,在 blog 数据库下,新建以下表

1、 标签表

2、 文章表

3、 认证表

编写项目配置包

go-gin-example 应用目录下,拉取 go-ini/ini 的依赖包,如下:

接下来我们需要编写基础的应用配置文件,在 go-gin-exampleconf目录下新建app.ini文件,写入内容:

建立调用配置的setting模块,在go-gin-examplepkg目录下新建setting目录(注意新增 replace 配置),新建 setting.go 文件,写入内容:

当前的目录结构:

编写API错误码包

建立错误码的e模块,在go-gin-examplepkg目录下新建e目录(注意新增 replace 配置),新建code.gomsg.go文件,写入内容:

1、 code.go:

2、 msg.go:

编写工具包

go-gin-examplepkg目录下新建util目录(注意新增 replace 配置),并拉取com的依赖包,如下:

编写分页页码的获取方法

util目录下新建pagination.go,写入内容:

编写models init

拉取gorm的依赖包,如下:

拉取mysql驱动的依赖包,如下:

完成后,在go-gin-examplemodels目录下新建models.go,用于models的初始化使用

编写项目启动、路由文件

最基础的准备工作完成啦,让我们开始编写Demo吧!

编写Demo

go-gin-example下建立main.go作为启动文件(也就是main包),我们先写个Demo,帮助大家理解,写入文件内容:

执行go run main.go,查看命令行是否显示

在本机执行curl 127.0.0.1:8000/test,检查是否返回{"message":"test"}

知识点

那么,我们来延伸一下Demo所涉及的知识点!

标准库

  • fmt:实现了类似C语言printf和scanf的格式化I/O。格式化动作('verb')源自C语言但更简单

  • net/http:提供了HTTP客户端和服务端的实现

Gin

  • gin.Default():返回Gin的type Engine struct{...},里面包含RouterGroup,相当于创建一个路由Handlers,可以后期绑定各类的路由规则和函数、中间件等

  • router.GET(...){...}:创建不同的HTTP方法绑定到Handlers中,也支持POST、PUT、DELETE、PATCH、OPTIONS、HEAD 等常用的Restful方法

  • gin.H{...}:就是一个map[string]interface{}

  • gin.ContextContextgin中的上下文,它允许我们在中间件之间传递变量、管理流、验证JSON请求、响应JSON请求等,在gin中包含大量Context的方法,例如我们常用的DefaultQueryQueryDefaultPostFormPostForm等等

&http.Server 和 ListenAndServe?

1、http.Server:

  • Addr:监听的TCP地址,格式为:8000

  • Handler:http句柄,实质为ServeHTTP,用于处理程序响应HTTP请求

  • TLSConfig:安全传输层协议(TLS)的配置

  • ReadTimeout:允许读取的最大时间

  • ReadHeaderTimeout:允许读取请求头的最大时间

  • WriteTimeout:允许写入的最大时间

  • IdleTimeout:等待的最大时间

  • MaxHeaderBytes:请求头的最大字节数

  • ConnState:指定一个可选的回调函数,当客户端连接发生变化时调用

  • ErrorLog:指定一个可选的日志记录器,用于接收程序的意外行为和底层系统错误;如果未设置或为nil则默认以日志包的标准日志记录器完成(也就是在控制台输出)

2、 ListenAndServe:

开始监听服务,监听TCP网络地址,Addr和调用应用程序处理连接上的请求。

我们在源码中看到Addr是调用我们在&http.Server中设置的参数,因此我们在设置时要用&,我们要改变参数的值,因为我们ListenAndServe和其他一些方法需要用到&http.Server中的参数,他们是相互影响的。

3、 http.ListenAndServe连载一r.Run()有区别吗?

我们看看r.Run的实现:

通过分析源码,得知本质上没有区别,同时也得知了启动gin时的监听debug信息在这里输出。

4、 为什么Demo里会有WARNING

首先我们可以看下Default()的实现

大家可以看到默认情况下,已经附加了日志、恢复中间件的引擎实例。并且在开头调用了debugPrintWARNINGDefault(),而它的实现就是输出该行日志

而另外一个Running in "debug" mode. Switch to "release" mode in production.,是运行模式原因,并不难理解,已在配置文件的管控下 :-),运维人员随时就可以修改它的配置。

5、 Demo的router.GET等路由规则可以不写在main包中吗?

我们发现router.GET等路由规则,在Demo中被编写在了main包中,感觉很奇怪,我们去抽离这部分逻辑!

go-gin-examplerouters目录新建router.go文件,写入内容:

修改main.go的文件内容:

当前目录结构:

重启服务,执行 curl 127.0.0.1:8000/test查看是否正确返回。

下一节,我们将以我们的 Demo 为起点进行修改,开始编码!

参考

本系列示例代码

关于

修改记录

  • 第一版:2018年02月16日发布文章

  • 第二版:2019年10月01日修改文章

如果有任何疑问或错误,欢迎在 issues 进行提问或给予修正意见,如果喜欢或对你有所帮助,欢迎 Star,对作者是一种鼓励和推进。

我的公众号

image

Last updated

Was this helpful?