以前學(xué)Java的時(shí)候龟虎,和Spring全家桶打好關(guān)系就行了锋勺,從Spring变丧、Spring MVC到SpringBoot芽狗,一脈相承。
對于一個(gè)Web項(xiàng)目痒蓬,使用Spring MVC童擎,就可以基于MVC的思想開發(fā)項(xiàng)目了,不管是應(yīng)對前后端分離還是不分離的場景攻晒,你都可以輕松駕馭顾复。因?yàn)槟阒灰溃阌玫氖且粋€(gè)Web開發(fā)框架就行了鲁捏。
相比于Spring在Java一家獨(dú)大的局面芯砸,Go生態(tài)中的Web框架還在百家爭鳴的階段。從今天開始學(xué)習(xí)一款基于Go語言開發(fā)的Web開發(fā)框架Gin。
簡介
Github:https://github.com/gin-gonic/gin
語言:Go語言
官網(wǎng):https://gin-gonic.com/
環(huán)境搭建
Go版本:1.12.4
系統(tǒng):macOS
依賴管理工具:go mod
IDE:Goland
因?yàn)槲沂褂昧薵o mod假丧,所以引用gin的依賴算是很方便了双揪。
如何創(chuàng)建一個(gè)go mod管理的新項(xiàng)目以及如何將老項(xiàng)目改造為go mod,可以參見這篇文章:https://juejin.im/post/5c8e503a6fb9a070d878184a包帚,寫的很詳細(xì)了渔期。
這就是我的go-demo:https://github.com/DMinerJackie/go-demo項(xiàng)目的所有第三方依賴了。
那么如何添加gin的依賴呢婴噩?有以下三種方式
直接新建一個(gè)基于gin的example程序文件擎场,然后執(zhí)行
go build xxx.go
或者go run xxx.go
命令,go mod就會自動幫你下載gin依賴并更新go.mod文件几莽。同上迅办,還是新建一個(gè)example程序文件,然后在項(xiàng)目根目錄下執(zhí)行
go mod tidy
命令章蚣,go mod會幫你安排上站欺。這個(gè)命令可以幫助你移除不需要的依賴,并拉取引用你需要的依賴纤垂。在go.mod文件中手動添加依賴類似
github.com/gin-gonic/gin v1.4.0
這種矾策。
幾乎不用什么繁瑣的步驟,就完成了環(huán)境搭建峭沦。下面開始寫第一個(gè)基于Gin的demo
第一個(gè)Demo
1贾虽、新建文件helloworld.go
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() // 監(jiān)聽并在 0.0.0.0:8080 上啟動服務(wù)
}
2、點(diǎn)擊執(zhí)行該程序
從控制臺程序可以看出服務(wù)已經(jīng)啟動吼鱼,并且開始監(jiān)聽8080端口
3蓬豁、訪問接口
接下來我們在瀏覽器輸入localhost:8080/ping即可看到程序返回的結(jié)果
一個(gè)極簡的Web服務(wù)器就這樣搭建完成并對外訪問了。
上面的代碼中
通過r := gin.Default()
聲明一個(gè)gin的引擎菇肃,后續(xù)的操作都是基于這個(gè)引擎的地粪。
通過r.GET
申明一個(gè)可以訪問的路由,定義的HTTP請求方式為GET請求琐谤。同時(shí)定義了請求后對應(yīng)的處理方式蟆技,即一個(gè)閉包函數(shù)聲明以JSON格式返回的鍵值對。
通過r.Run()
監(jiān)聽指定端口并啟動服務(wù)
其他Demo
1斗忌、渲染HTML
雖然現(xiàn)在很多都倡導(dǎo)并實(shí)行前后端分離了质礼,即后端只提供HTTP接口,前端負(fù)責(zé)調(diào)用HTTP接口以及頁面渲染织阳。
但還是有前后端揉在一起的使用場景眶蕉,gin就提供了這種能力。
具體的做法是提供一個(gè)HTML模板陈哑,服務(wù)端將得到的數(shù)據(jù)填充到模板中實(shí)現(xiàn)頁面的渲染泳桦。
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
{{ define "posts/index.tmpl" }}
<html><h1>
{{ .title }}
</h1>
<p>Using posts/index.tmpl</p>
</html>
{{ end }}
user.tmpl
{{ define "users/index.tmpl" }}
<html><h1>
{{ .title }}
</h1>
<p>Using users/index.tmpl</p>
</html>
{{ end }}
對應(yīng)的HTML模板文件目錄結(jié)構(gòu)如下
代碼部分
router.LoadHTMLGlob
用于指明HTML模板文件的路徑
router.GET
同上,定義訪問路由和返回結(jié)果透典,不同于第一個(gè)Demo的是,這里有賦值填充的過程厘贼,比如
c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "Posts",
})
將index.tmpl中定義的.title
替換為"Posts"
執(zhí)行結(jié)果如下
2、PureJSON
func main() {
r := gin.Default()
// 提供 unicode 實(shí)體
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>",
})
})
// 監(jiān)聽并在 0.0.0.0:8080 上啟動服務(wù)
r.Run(":8080")
}
這里兩個(gè)GET方法唯一不同的就是要渲染的內(nèi)容一個(gè)使用JSON()方法一個(gè)使用PureJSON()方法圣拄。
啟動程序后嘴秸,我們看下訪問結(jié)果有什么不同
可以看出JSON()渲染的會有中文以及標(biāo)簽轉(zhuǎn)為unicode編碼,但是使用PureJSON()渲染就是原樣輸出(我的瀏覽器裝了插件庇谆,會自動解碼岳掐,所以不點(diǎn)擊右邊的”RAW“兩個(gè)接口返回的結(jié)果是一樣的)。
這個(gè)問題饭耳,本周我們服務(wù)端在和客戶端對接的時(shí)候還遇到了串述,因?yàn)榭蚣芊祷氐腏SON串就是經(jīng)過編碼的,但是單獨(dú)請求放到瀏覽器是沒有問題的寞肖,客戶端收到的卻是經(jīng)過編碼的纲酗,最后排查發(fā)現(xiàn)是瀏覽器插件解碼了。
3新蟆、渲染多種數(shù)據(jù)交換格式的數(shù)據(jù)
gin支持渲染XML觅赊、JSON、YAML和ProtoBuf等多種數(shù)據(jù)格式
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) {
// 你也可以使用一個(gè)結(jié)構(gòu)體
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,
}
// 請注意吮螺,數(shù)據(jù)在響應(yīng)中變?yōu)槎M(jìn)制數(shù)據(jù)
// 將輸出被 protoexample.Test protobuf 序列化了的數(shù)據(jù)
c.ProtoBuf(http.StatusOK, data)
})
// 監(jiān)聽并在 0.0.0.0:8080 上啟動服務(wù)
r.Run(":8080")
}
今天先到這,后面再看看gin的源碼帕翻。