Go Gin 框架

简介

中文官网:https://gin-gonic.com/zh-cn/docs/introduction/

github:https://github.com/gin-gonic/gin

Gin 是一个用 Go (Golang) 编写的 Web 框架。 它具有类似 martini 的 API,性能要好得多,多亏了 httprouter,速度提高了 40 倍。 如果您需要性能和良好的生产力,您一定会喜欢 Gin

  • Go 1.13 及以上版本

特性

1.快速

基于 Radix 树的路由,小内存占用。没有反射。可预测的 API 性能。

2.支持中间件

传入的 HTTP 请求可以由一系列中间件和最终操作来处理。 例如:Logger,Authorization,GZIP,最终操作 DB。

3.Crash 处理

Gin 可以 catch 一个发生在 HTTP 请求中的 panic 并 recover 它。这样,你的服务器将始终可用。例如,你可以向 Sentry 报告这个 panic!

4.JSON 验证

Gin 可以解析并验证请求的 JSON,例如检查所需值的存在。

5.路由组

更好地组织路由。是否需要授权,不同的 API 版本…… 此外,这些组可以无限制地嵌套而不会降低性能。

6.错误管理

Gin 提供了一种方便的方法来收集 HTTP 请求期间发生的所有错误。最终,中间件可以将它们写入日志文件,数据库并通过网络发送。

7.内置渲染

Gin 为 JSON,XML 和 HTML 渲染提供了易于使用的 API。

8.可扩展性

新建一个中间件非常简单,去查看示例代码吧。

hello world

初始化项目

新建一个gin_test ,文件夹,使用vsocd打开在终端输入一下命令,初始化项目

# 初始化模块
go mod init gin_test
# 下载并安装
go get -u github.com/gin-gonic/gin

image-20230207144445059

main.go

创建main.go,并写入下面的代码

package main

// 将 gin 引入到代码中
import "github.com/gin-gonic/gin"

// (可选)如果使用诸如 http.StatusOK 之类的常量,则需要引入 net/http 包
// import "net/http"

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

启动

# 运行 main.go 并且在浏览器中访问 HOST_IP:8080/ping
go run main.go

访问

http://localhost:8080/ping

image-20230207145048739

第一个例子完成

自定义路由

上面那个例子,路由定义和控制器处理都在main函数里面,在真实项目中显然是不可能的,难道你想看到一个文件两三万行?虽然我真的见过...,但是要尽量避免这种情况,所以我们一般把路由文件独立出来一个文件,甚至几个文件,那在Gin 里面要怎么做呢?往下看

拆分成单个路由文件

新建routes文件夹,在此文件下新建router1.go文件,内容如下

目录结构

│  go.mod
│  go.sum
│  main.go
└─routers
        router1.go

案例

文件:routes/router1.go

package gin_test

import "github.com/gin-gonic/gin"

// 控制器方法
func helloHandler(context *gin.Context) {
	context.JSON(200, "这是路由文件1")
}

// 设置路由
func SetupRouter() *gin.Engine {
	// 配置路由信息
	router := gin.Default()
	router.GET("/router1", helloHandler)
	return router
}

文件:main.go

package main

import (
	"fmt"

	// 引入自定义路由模块
	routers "gin_test/routers"
)

func main() {
	// 获取路由
	router := routers.SetupRouter()
	// 启动监听并打印错误
	if err := router.Run(); err != nil {
		fmt.Println(err)
		return
	}
}

启动

go run main.go

访问

http://localhost:8080/router1

image-20230208160443833

到此将路由单独拆出来已经可以了

支持多个路由文件

当我们的业务规模继续膨胀,单独的一个router1.go文件或包已经满足不了我们的需求了,我们需要按模块或者按业务拆分成多个路由文件,在Gin 中怎么实现?看下面

目录结构

│  go.mod
│  go.sum
│  main.go
└─routes
        router1.go
        router2.go

这时候,多个路由文件我们看做不同的模块,为了防止两个不同模块之间有同名路由,我们最好加上路由组

官方文档:https://gin-gonic.com/zh-cn/docs/examples/grouping-routes/

我们就按文件名设置路由组吧,

  • router1.go -> router1
  • router2.go -> router2

这个时候我们就不能将路由初始化分到路由文件里了,而是在main函数中初始化路由,将路由器传入路由文件的方法里,也就是说路由文件只负责注册路由

案例

文件:routes/router1.go

package gin_test

import "github.com/gin-gonic/gin"

// 控制器方法
func helloHandler1(context *gin.Context) {
	context.JSON(200, "这是路由文件1")
}

// 设置路由
func Router1(router *gin.Engine) {
	// 设置路由组
	router1 := router.Group("/router1")
	{
		// 注册模块1的路由
		router1.GET("/hello", helloHandler1)
	}
}

文件:routes/router2.go

package gin_test

import "github.com/gin-gonic/gin"

// 控制器方法
func helloHandler2(context *gin.Context) {
	context.JSON(200, "这是路由文件2")
}

// 设置路由
func Router2(router *gin.Engine) {
	// 设置路由组
	router2 := router.Group("/router2")
	{
		// 注册模块2的路由
		router2.GET("/hello", helloHandler2)
	}
}

文件:main.go

package main

import (
	"fmt"

	// 引入自定义路由模块
	routers "gin_test/routers"

	"github.com/gin-gonic/gin"
)

func main() {
	// 获取路由
	router := gin.Default()
	routers.Router1(router)
	routers.Router2(router)
	// 启动监听并打印错误
	if err := router.Run(); err != nil {
		fmt.Println(err)
		return
	}
}

启动

go run main.go

访问

http://localhost:8080/router2/hello

image-20230208164417599

至此我们支持了多个路由文件,并且使用路由组避免了同路径路由注册失败的问题

路由拆分到不同平台

上面我们已经支持了多个文件,并且支持路由分组,但是有时候项目规模实在太大,比如:

我们需要拆分成:

  • web:web访问的路由
  • app:app访问的路由
  • common: 公共的基础路由,web和app都可以访问

上面这种在项目体量大的时候,还是很常见的,那在Gin 中该怎么写

目录结构

│  go.mod
│  go.sum
│  main.go
├─app
│      router.go
├─common
│      router.go
├─routers
│      routers.go
└─web
       router.go

文件:main.go

package main

import (
	"fmt"

	// 引入自定义路由模块
	app "gin_test/app"
	common "gin_test/common"
	routers "gin_test/routers"
	web "gin_test/web"
)

func main() {
	// 加载所有模块的路由配置
	routers.Include(app.Routers, web.Routers, common.Routers)
	// 初始化路由
	router := routers.Init()
	// 启动监听并打印错误
	if err := router.Run(); err != nil {
		fmt.Println(err)
		return
	}
}

文件:routers/routers.go

package routers

import (
	"github.com/gin-gonic/gin"
)

// 定义单个路由model
type RouterModel func(router *gin.Engine)

// 路由model 切片
var routerModels = make([]RouterModel, 0)

// 注册路由model配置
func Include(models ...RouterModel) {
	// 塞到路由模块切片中
	routerModels = append(routerModels, models...)
}

// 初始化路由
func Init() *gin.Engine {
	router := gin.Default()
	for _, model := range routerModels {
		model(router)
	}
	return router
}

文件:web/router.go

package gin_test

import "github.com/gin-gonic/gin"

// 控制器方法
func hello(context *gin.Context) {
	context.JSON(200, "这是 Web 模块")
}

// 设置路由
func Routers(router *gin.Engine) {
	// 设置路由组
	Web := router.Group("/Web")
	{
		// 注册路由
		Web.GET("/hello", hello)
	}
}

文件:app/router.go

package gin_test

import "github.com/gin-gonic/gin"

// 控制器方法
func hello(context *gin.Context) {
	context.JSON(200, "这是app模块")
}

// 设置路由
func Routers(router *gin.Engine) {
	// 设置路由组
	App := router.Group("/App")
	{
		// 注册路由
		App.GET("/hello", hello)
	}
}

文件:common/router.go

package gin_test

import "github.com/gin-gonic/gin"

// 控制器方法
func hello(context *gin.Context) {
	context.JSON(200, "这是 Common 模块")
}

// 设置路由
func Routers(router *gin.Engine) {
	// 设置路由组
	Common := router.Group("/Common")
	{
		// 注册路由
		Common.GET("/hello", hello)
	}
}

启动

go run main.go

路由

image-20230208172855610

请求

http://localhost:8080/App/hello

image-20230208172933664

代码

这个demo 代码我放在了这里:

https://gitee.com/makalochen/go-test/tree/master/gin_test

结语

其他什么参数获取,上传文件,自定义验证啥,在官方文档都可以找到,我就不写了,我只能说写的再好也没官方给的标准

官网中文文档地址:

https://gin-gonic.com/zh-cn/docs/examples/

posted @ 2023-02-08 17:47  makalo  阅读(1057)  评论(0编辑  收藏  举报