Go组件学习——Web框架Gin
以前学Java的时候,和Spring全家桶打好关系就行了,从Spring、Spring MVC到SpringBoot,一脉相承。
对于一个Web项目,使用Spring MVC,就可以基于MVC的思想开发项目了,不管是应对前后端分离还是不分离的场景,你都可以轻松驾驭。因为你只要知道,你用的是一个Web开发框架就行了。
相比于Spring在Java一家独大的局面,Go生态中的Web框架还在百家争鸣的阶段。从今天开始学习一款基于Go语言开发的Web开发框架Gin。
简介
Github:https://github.com/gin-gonic/gin
语言:Go语言
官网:https://gin-gonic.com/
环境搭建
Go版本:1.12.4
系统:macOS
依赖管理工具:go mod
IDE:Goland
因为我使用了go mod,所以引用gin的依赖算是很方便了。
如何创建一个go mod管理的新项目以及如何将老项目改造为go mod,可以参见这篇文章:https://juejin.im/post/5c8e503a6fb9a070d878184a,写的很详细了。
这就是我的go-demo:https://github.com/DMinerJackie/go-demo项目的所有第三方依赖了。
那么如何添加gin的依赖呢?有以下三种方式
-
直接新建一个基于gin的example程序文件,然后执行
go build xxx.go
或者go run xxx.go
命令,go mod就会自动帮你下载gin依赖并更新go.mod文件。 -
同上,还是新建一个example程序文件,然后在项目根目录下执行
go mod tidy
命令,go mod会帮你安排上。这个命令可以帮助你移除不需要的依赖,并拉取引用你需要的依赖。 -
在go.mod文件中手动添加依赖类似
github.com/gin-gonic/gin v1.4.0
这种。
几乎不用什么繁琐的步骤,就完成了环境搭建。下面开始写第一个基于Gin的demo
第一个Demo
1、新建文件helloworld.go
1 2 3 4 5 6 7 8 9 10 11 12 13 | package main import "github.com/gin-gonic/gin" 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 上启动服务 } |
2、点击执行该程序
从控制台程序可以看出服务已经启动,并且开始监听8080端口
3、访问接口
接下来我们在浏览器输入localhost:8080/ping即可看到程序返回的结果
一个极简的Web服务器就这样搭建完成并对外访问了。
上面的代码中
通过 r:=gin.Default()
声明一个gin的引擎,后续的操作都是基于这个引擎的。
通过 r.GET
申明一个可以访问的路由,定义的HTTP请求方式为GET请求。同时定义了请求后对应的处理方式,即一个闭包函数声明以JSON格式返回的键值对。
通过 r.Run()
监听指定端口并启动服务
其他Demo
1、渲染HTML
虽然现在很多都倡导并实行前后端分离了,即后端只提供HTTP接口,前端负责调用HTTP接口以及页面渲染。
但还是有前后端揉在一起的使用场景,gin就提供了这种能力。
具体的做法是提供一个HTML模板,服务端将得到的数据填充到模板中实现页面的渲染。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import ( "github.com/gin-gonic/gin" "net/http" ) func main() { router := gin.Default() router.LoadHTMLGlob( "main/src/gin-example/examples/templates/**/*" ) router.GET( "/posts/index" , func (c *gin.Context) { c.HTML(http.StatusOK, "posts/index.tmpl" , gin.H{ "title" : "Posts" , }) }) router.GET( "/users/index" , func (c *gin.Context) { c.HTML(http.StatusOK, "users/index.tmpl" , gin.H{ "title" : "Users" , }) }) router.Run( ":8080" ) } |
index.tmpl
1 2 3 4 5 6 7 | {{ define "posts/index.tmpl" }} < html >< h1 > {{ .title }} </ h1 > < p >Using posts/index.tmpl</ p > </ html > {{ end }} |
user.tmpl
1 2 3 4 5 6 7 | {{ define "users/index.tmpl" }} < html >< h1 > {{ .title }} </ h1 > < p >Using users/index.tmpl</ p > </ html > {{ end }} |
对应的HTML模板文件目录结构如下
代码部分
router.LoadHTMLGlob
用于指明HTML模板文件的路径
router.GET
同上,定义访问路由和返回结果,不同于第一个Demo的是,这里有赋值填充的过程,比如
1 2 3 | c.HTML(http.StatusOK, "posts/index.tmpl" , gin.H{ "title" : "Posts" , }) |
将index.tmpl中定义的 .title
替换为"Posts"
执行结果如下
2、PureJSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | func main() { r := gin.Default() // 提供 unicode 实体 r.GET( "/json" , func (c *gin.Context) { c.JSON(200, gin.H{ "html" : "<b>Hello, 世界!</b>" , }) }) // 提供字面字符 r.GET( "/purejson" , func (c *gin.Context) { c.PureJSON(200, gin.H{ "html" : "<b>Hello, 世界!</b>" , }) }) // 监听并在 0.0.0.0:8080 上启动服务 r.Run( ":8080" ) } |
这里两个GET方法唯一不同的就是要渲染的内容一个使用JSON()方法一个使用PureJSON()方法。
启动程序后,我们看下访问结果有什么不同
可以看出JSON()渲染的会有中文以及标签转为unicode编码,但是使用PureJSON()渲染就是原样输出(我的浏览器装了插件,会自动解码,所以不点击右边的”RAW“两个接口返回的结果是一样的)。
这个问题,本周我们服务端在和客户端对接的时候还遇到了,因为框架返回的JSON串就是经过编码的,但是单独请求放到浏览器是没有问题的,客户端收到的却是经过编码的,最后排查发现是浏览器插件解码了。
3、渲染多种数据交换格式的数据
gin支持渲染XML、JSON、YAML和ProtoBuf等多种数据格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | import ( "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/testdata/protoexample" "net/http" ) func main() { r := gin.Default() // gin.H 是 map[string]interface{} 的一种快捷方式 r.GET( "/someJSON" , func (c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message" : "hey" , "status" : http.StatusOK}) }) r.GET( "/moreJSON" , func (c *gin.Context) { // 你也可以使用一个结构体 var msg struct { Name string `json: "user" ` Message string Number int } msg.Name = "Lena" msg.Message = "hey" msg.Number = 123 // 注意 msg.Name 在 JSON 中变成了 "user" // 将输出:{"user": "Lena", "Message": "hey", "Number": 123} c.JSON(http.StatusOK, msg) }) r.GET( "/someXML" , func (c *gin.Context) { c.XML(http.StatusOK, gin.H{ "message" : "hey" , "status" : http.StatusOK}) }) r.GET( "/someYAML" , func (c *gin.Context) { c.YAML(http.StatusOK, gin.H{ "message" : "hey" , "status" : http.StatusOK}) }) r.GET( "/someProtoBuf" , func (c *gin.Context) { reps := []int64{int64(1), int64(2)} label := "test" // protobuf 的具体定义写在 testdata/protoexample 文件中。 data := &protoexample.Test{ Label: &label, Reps: reps, } // 请注意,数据在响应中变为二进制数据 // 将输出被 protoexample.Test protobuf 序列化了的数据 c.ProtoBuf(http.StatusOK, data) }) // 监听并在 0.0.0.0:8080 上启动服务 r.Run( ":8080" ) } |
今天先到这,后面再看看gin的源码。
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架