介紹
- Gin是一個(gè)golang的微框架,封裝比較優(yōu)雅抖格,API友好,源碼注釋比較明確咕晋,具有快速靈活雹拄,容錯(cuò)方便等特點(diǎn)
- 對(duì)于golang而言,web框架的依賴要遠(yuǎn)比Python掌呜,Java之類的要小滓玖。自身的net/http足夠簡(jiǎn)單,性能也非常不錯(cuò)
- 借助框架開發(fā)质蕉,不僅可以省去很多常用的封裝帶來的時(shí)間势篡,也有助于團(tuán)隊(duì)的編碼風(fēng)格和形成規(guī)范
安裝
1.安裝Gin go get -u github.com/gin-gonic/gin 2.引入包 import "github.com/gin-gonic/gin" 3.(可選)導(dǎo)入net/http。例如模暗,如果使用常量禁悠,則需要這樣做http.StatusOK。 import "net/http" //示例 package main import ("github.com/gin-gonic/gin") func main(){ //創(chuàng)建路由 r:=gin.Default() r.GET("/",func(c *gin.Context){ c.String(http.StatusOK,"hello world") }) } //監(jiān)聽端口 //如果不指定端口則默認(rèn)為8080 c.run(":80")
基本路由
gin框架中采用的路由庫(kù)是基于httprouter做的
package main import( "net/http" "github.com/gin-gonic/gin" ) func main(){ r:=gin.Default() r.GET("/",func(c *gin.Context){ c.String(http.StatusOK,"hello word") }) r.POST("/delUser",DelUser) //監(jiān)聽80端口 r.run(":8000") }
API參數(shù)
可以通過Context的Param方法來獲取API參數(shù)
package main import( "net/http" "strings" "github.com/gin-gonic/gin" ) func main(){ r:=gin.Default() r.GET("/user/:name/*action",func(c *gin.Context){ name:=c.Param("name") action:=c.Param("acion") //截取 action=strings.Trim(action,"/") c.String(http.StatusOK,name+"is"+action) }) //默認(rèn)監(jiān)聽8080端口 c.Run(":8080") }
URL參數(shù)
URL參數(shù)可以通過
DefaultQuery()
或Query()
方法獲取DefaultQuery()若參數(shù)不存在兑宇,則返回默認(rèn)值碍侦,Query()若不存在則返回空字符串
package main import ( "net/http" "github.com/gin-gonic/gin" ) func main(){ r:=gin.Default() r.GET("/user",func(c *gin.Context){ name:= c.DefaultQuery("name","Nice") c.String(http.StatusOK,fmt.Sprintf("%s",name)) }) c.Run(":8000") }
表單參數(shù)
表單傳輸為post請(qǐng)求,http常見的傳輸格式為四種
- application/json
- application/x-www-form-urlencoded
- application/xml
- multipart/form-data
表單參數(shù)可以通過PostForm()方法獲取隶糕,該方法默認(rèn)解析的是x-www-form-urlencoded或form-data格式的參數(shù)
package main import( "fmt" "net/http" "github.com/gin-gonic/gin" ) func main(){ r:=gin.Default() r.POST("form",func(c *gin.Context){ types:=c.DefaultPostForm("type","post") username:=c.PostForm("userName") password:=c.PostForm("pwd") c.String(http.StatusOk,fmt.Sprintf("%v",username) }) c.Run(":8000") }
單個(gè)文件
multipart/form-data格式用于文件上傳
gin文件上傳與原生的net/http方法類似祝钢,不同于在gin把原生的request封裝到c.Request中
package main import ( "github.com/gin-gonic/gin" ) func main(){ r:=gin.Default() //限制上傳最大尺寸 r.MaxMultipartMemory=8<<20 r.POST("/upload",func(c *gin.Context){ file,err:=c.FormFile("file") if err!=nil{ c.String(500,"上傳出錯(cuò)") c.SaveUploadedFile(file,file.Filename) c.String(http.StatusOK,file.Filename) } }) c.Run(":800") }
上傳多個(gè)文件
import ( "fmt" "github.com/gin-gonic/gin" "net/http" ) func main() { // 1.創(chuàng)建路由 // 默認(rèn)使用了2個(gè)中間件Logger(), Recovery() r := gin.Default() // 限制表單上傳大小 8MB,默認(rèn)為32MB r.MaxMultipartMemory = 8 << 20 r.POST("/upload", func(c *gin.Context) { form, err := c.MultipartForm() if err != nil { c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error())) } // 獲取所有圖片 files := form.File["files"] // 遍歷所有圖片 for _, file := range files { // 逐個(gè)存 if err := c.SaveUploadedFile(file, file.Filename); err != nil { c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error())) return } } c.String(200, fmt.Sprintf("upload ok %d files", len(files))) }) //默認(rèn)端口號(hào)是8080 r.Run(":8000") }
routees group
routes group 是為了管理一些相同的URL
package main import ( "github.com/gin-gonic/gin" "net/http" "fmt" ) func main(){ r:=gin.Default() }
路由的拆分與注冊(cè)
- 基本的路由注冊(cè) 適用于路由條目較少的簡(jiǎn)單下面或者項(xiàng)目demo
package main import ( "net/http" "github.com/gin-gonic/gin" ) func helloHandler(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "Hello www.topgoer.com!", }) } func main() { r := gin.Default() r.GET("/topgoer", helloHandler) if err := r.Run(); err != nil { fmt.Println("startup service failed, err:%v\n", err) } }
- 路由拆分成單獨(dú)的文件或包
當(dāng)項(xiàng)目的規(guī)模增大后就不太適合繼續(xù)在項(xiàng)目的main.go文件中去實(shí)現(xiàn)注冊(cè)的相關(guān)邏輯若厚,所以更加偏向于抽出路由模塊的代碼出來拦英,形成單獨(dú)一個(gè)文件
package router import "github.com/gin-gonic/gin" import ( "net/http" ) func helloHandler(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "Hello www.topgoer.com", }) } // SetupRouter 配置路由信息 func SetupRouter() *gin.Engine { r := gin.Default() r.GET("/topgoer", helloHandler) return r } package main import ( "fmt" "router_example/router" ) func main() { r := router.SetupRouter() if err := r.Run(); err != nil { fmt.Println("err failed", err) } }
當(dāng)前目錄結(jié)構(gòu)如下
router_example ├── go.mod ├── main.go └── router └── routers.go
路由拆分成多個(gè)文件
當(dāng)業(yè)務(wù)規(guī)模繼續(xù)膨脹,單獨(dú)的一個(gè)routers文件或包已經(jīng)滿足不了需求测秸,所以可以分開定義多個(gè)路由文件
package router import "github.com/gin-gonic/gin" func LoadSystem(e *gin.Engine) { r := gin.Default() { r.GET("findSystemId", findSystemId) r.GET("findAll",findAll) } } package router import "github.com/gin-gonic/gin" func LoadUser(e *gin.Engine) { r := gin.Default() { r.GET("findByUserId", findByUserId) r.GET("findAllUser", findAllUser) } } main.go func main() { r := gin.Default() //加載系統(tǒng)路由 router.LoadSystem(r) //加載用戶路由 router.LoadUser(r) if err := r.Run(); err != nil { fmt.Println(err) } }
當(dāng)前目錄結(jié)構(gòu)如下
router_example ├── go.mod ├── main.go └── router └── user.go └── system.go
路由拆分到不同的APP
項(xiàng)目規(guī)模太大疤估,那么更傾向于把業(yè)務(wù)拆分的更詳細(xì)一些灾常,例如把不同的業(yè)務(wù)代碼拆分成不同的APP
router_example ├──app | ├──user | | ├──handle.go | | ├──router.go | ├──system | | ├──handle.go | | ├──router.go ├── go.mod ├── main.go └── router └── routers.go
system package system import ( "github.com/gin-gonic/gin" "net/http" ) func findBySystemId(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "findBySystemId", }) } package system import "github.com/gin-gonic/gin" func Routers(e *gin.Engine) { e.GET("findBySystemId", findBySystemId) } user package user import ( "github.com/gin-gonic/gin" "net/http" ) func findByUserId(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "findByUserId", }) } package user import ( "github.com/gin-gonic/gin" ) func Routers(e *gin.Engine) { e.GET("findByUserId", findByUserId) } package main import ( "fmt" "router_example/router" "router_example/service/system" "router_example/service/user" ) func main() { //加載多個(gè)路由 router.Include(user.Routers, system.Routers) //初始化 r := router.Init() if err := r.Run(); err != nil { fmt.Println(err) } }