Go Gin 框架
<h2 id="简介">简介</h2><p>中文官网:https://gin-gonic.com/zh-cn/docs/introduction/</p>
<p>github:https://github.com/gin-gonic/gin</p>
<p>Gin 是一个用 Go (Golang) 编写的 Web 框架。 它具有类似 martini 的 API,性能要好得多,多亏了 httprouter,速度提高了 40 倍。 如果您需要性能和良好的生产力,您一定会喜欢 Gin</p>
<ul>
<li>Go 1.13 及以上版本</li>
</ul>
<h2 id="特性">特性</h2>
<p>1.快速</p>
<p>基于 Radix 树的路由,小内存占用。没有反射。可预测的 API 性能。</p>
<p>2.支持中间件</p>
<p>传入的 HTTP 请求可以由一系列中间件和最终操作来处理。 例如:Logger,Authorization,GZIP,最终操作 DB。</p>
<p>3.Crash 处理</p>
<p>Gin 可以 catch 一个发生在 HTTP 请求中的 panic 并 recover 它。这样,你的服务器将始终可用。例如,你可以向 Sentry 报告这个 panic!</p>
<p>4.JSON 验证</p>
<p>Gin 可以解析并验证请求的 JSON,例如检查所需值的存在。</p>
<p>5.路由组</p>
<p>更好地组织路由。是否需要授权,不同的 API 版本…… 此外,这些组可以无限制地嵌套而不会降低性能。</p>
<p>6.错误管理</p>
<p>Gin 提供了一种方便的方法来收集 HTTP 请求期间发生的所有错误。最终,中间件可以将它们写入日志文件,数据库并通过网络发送。</p>
<p>7.内置渲染</p>
<p>Gin 为 JSON,XML 和 HTML 渲染提供了易于使用的 API。</p>
<p>8.可扩展性</p>
<p>新建一个中间件非常简单,去查看示例代码吧。</p>
<h2 id="hello-world">hello world</h2>
<h3 id="初始化项目">初始化项目</h3>
<p>新建一个<code>gin_test</code> ,文件夹,使用vsocd打开在终端输入一下命令,初始化项目</p>
<pre><code># 初始化模块
go mod init gin_test
# 下载并安装
go get -u github.com/gin-gonic/gin
</code></pre>
<p><img src="https://img2023.cnblogs.com/blog/1652001/202302/1652001-20230208174739457-198491162.png" alt="image-20230207144445059" loading="lazy"></p>
<h3 id="maingo">main.go</h3>
<p>创建main.go,并写入下面的代码</p>
<pre><code class="language-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 上启动服务
}
</code></pre>
<h3 id="启动">启动</h3>
<pre><code># 运行 main.go 并且在浏览器中访问 HOST_IP:8080/ping
go run main.go
</code></pre>
<h3 id="访问">访问</h3>
<pre><code>http://localhost:8080/ping
</code></pre>
<p><img src="https://img2023.cnblogs.com/blog/1652001/202302/1652001-20230208174739410-1745217395.png" alt="image-20230207145048739" loading="lazy"></p>
<p>第一个例子完成</p>
<h2 id="自定义路由">自定义路由</h2>
<p>上面那个例子,路由定义和控制器处理都在main函数里面,在真实项目中显然是不可能的,难道你想看到一个文件两三万行?虽然我真的见过...,但是要尽量避免这种情况,所以我们一般把路由文件独立出来一个文件,甚至几个文件,那在Gin 里面要怎么做呢?往下看</p>
<h3 id="拆分成单个路由文件">拆分成单个路由文件</h3>
<p>新建<code>routes</code>文件夹,在此文件下新建<code>router1.go</code>文件,内容如下</p>
<h4 id="目录结构">目录结构</h4>
<pre><code>│go.mod
│go.sum
│main.go
└─routers
router1.go
</code></pre>
<h4 id="案例">案例</h4>
<p>文件:routes/router1.go</p>
<pre><code class="language-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
}
</code></pre>
<p>文件:main.go</p>
<pre><code class="language-go">package main
import (
"fmt"
// 引入自定义路由模块
routers "gin_test/routers"
)
func main() {
// 获取路由
router := routers.SetupRouter()
// 启动监听并打印错误
if err := router.Run(); err != nil {
fmt.Println(err)
return
}
}
</code></pre>
<p>启动</p>
<pre><code class="language-go">go run main.go
</code></pre>
<p>访问</p>
<pre><code>http://localhost:8080/router1
</code></pre>
<p><img src="https://img2023.cnblogs.com/blog/1652001/202302/1652001-20230208174739432-1731288779.png" alt="image-20230208160443833" loading="lazy"></p>
<p>到此将路由单独拆出来已经可以了</p>
<h3 id="支持多个路由文件">支持多个路由文件</h3>
<p>当我们的业务规模继续膨胀,单独的一个<code>router1.go</code>文件或包已经满足不了我们的需求了,我们需要按模块或者按业务拆分成多个路由文件,在Gin 中怎么实现?看下面</p>
<h4 id="目录结构-1">目录结构</h4>
<pre><code>│go.mod
│go.sum
│main.go
└─routes
router1.go
router2.go
</code></pre>
<p>这时候,多个路由文件我们看做不同的模块,为了防止两个不同模块之间有<code>同名路由</code>,我们最好加上路由组</p>
<p>官方文档:https://gin-gonic.com/zh-cn/docs/examples/grouping-routes/</p>
<p>我们就按文件名设置路由组吧,</p>
<ul>
<li>router1.go-> router1</li>
<li>router2.go-> router2</li>
</ul>
<p>这个时候我们就不能将路由初始化分到路由文件里了,而是在main函数中初始化路由,将路由器传入路由文件的方法里,也就是说路由文件只负责注册路由</p>
<h4 id="案例-1">案例</h4>
<p>文件:routes/router1.go</p>
<pre><code class="language-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)
}
}
</code></pre>
<p>文件:routes/router2.go</p>
<pre><code class="language-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)
}
}
</code></pre>
<p>文件:main.go</p>
<pre><code class="language-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
}
}
</code></pre>
<p>启动</p>
<pre><code class="language-go">go run main.go
</code></pre>
<p>访问</p>
<pre><code class="language-go">http://localhost:8080/router2/hello
</code></pre>
<p><img src="https://img2023.cnblogs.com/blog/1652001/202302/1652001-20230208174739371-2009629908.png" alt="image-20230208164417599" loading="lazy"></p>
<p>至此我们支持了多个路由文件,并且使用路由组避免了同路径路由注册失败的问题</p>
<h3 id="路由拆分到不同平台">路由拆分到不同平台</h3>
<p>上面我们已经支持了多个文件,并且支持路由分组,但是有时候项目规模实在太大,比如:</p>
<p>我们需要拆分成:</p>
<ul>
<li>web:web访问的路由</li>
<li>app:app访问的路由</li>
<li>common: 公共的基础路由,web和app都可以访问</li>
</ul>
<p>上面这种在项目体量大的时候,还是很常见的,那在Gin 中该怎么写</p>
<h4 id="目录结构-2">目录结构</h4>
<pre><code class="language-go">│go.mod
│go.sum
│main.go
├─app
│ router.go
├─common
│ router.go
├─routers
│ routers.go
└─web
router.go
</code></pre>
<p>文件:main.go</p>
<pre><code class="language-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
}
}
</code></pre>
<p>文件:routers/routers.go</p>
<pre><code class="language-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
}
</code></pre>
<p>文件:web/router.go</p>
<pre><code class="language-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)
}
}
</code></pre>
<p>文件:app/router.go</p>
<pre><code class="language-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)
}
}
</code></pre>
<p>文件:common/router.go</p>
<pre><code>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)
}
}
</code></pre>
<p>启动</p>
<pre><code class="language-go">go run main.go
</code></pre>
<p>路由</p>
<p><img src="https://img2023.cnblogs.com/blog/1652001/202302/1652001-20230208174739370-950744856.png" alt="image-20230208172855610" loading="lazy"></p>
<p>请求</p>
<pre><code>http://localhost:8080/App/hello
</code></pre>
<p><img src="https://img2023.cnblogs.com/blog/1652001/202302/1652001-20230208174739371-1538800637.png" alt="image-20230208172933664" loading="lazy"></p>
<h2 id="代码">代码</h2>
<p>这个demo 代码我放在了这里:</p>
<p>https://gitee.com/makalochen/go-test/tree/master/gin_test</p>
<h2 id="结语">结语</h2>
<p>其他什么参数获取,上传文件,自定义验证啥,在官方文档都可以找到,我就不写了,我只能说写的再好也没官方给的标准</p>
<p>官网中文文档地址:</p>
<p>https://gin-gonic.com/zh-cn/docs/examples/</p><br><br>
来源:https://www.cnblogs.com/makalochen/p/17102782.html
頁:
[1]