1.什麼是Gin
Gin是go編寫的一個web應用框架。git
2.Gin安裝github
go get github.com/gin-gonic/gin
3.Gin使用示例web
package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { // 初始化引擎 engine := gin.Default() // 註冊一個路由和處理函數 engine.Any("/", WebRoot) // 綁定端口,而後啓動應用 engine.Run(":9205") } /** * 根請求處理函數 * 全部本次請求相關的方法都在 context 中,完美 * 輸出響應 hello, world */ func WebRoot(context *gin.Context) { context.String(http.StatusOK, "hello, world") }
運行結果:
json
4.路由(Router)
1)restful api
註冊路由方法有GET,POST,PUT,PATCH,DELETE,OPTIONSapi
// 省略的代碼 ... func main() { router := gin.Default() router.GET("/someGet", getting) router.POST("/somePost", posting) router.PUT("/somePut", putting) router.DELETE("/someDelete", deleting) router.PATCH("/somePatch", patching) router.HEAD("/someHead", head) router.OPTIONS("/someOptions", options) // 默認綁定 :8080 router.Run() }
2)動態路由(參數路由)
如/user/:idrestful
// 省略的代碼 ... func main() { router := gin.Default() // 註冊一個動態路由 // 能夠匹配 /user/joy // 不能匹配 /user 和 /user/ router.GET("/user/:name", func(c *gin.Context) { // 使用 c.Param(key) 獲取 url 參數 name := c.Param("name") c.String(http.StatusOK, "Hello %s", name) }) // 註冊一個高級的動態路由 // 該路由會匹配 /user/john/ 和 /user/john/send // 若是沒有任何路由匹配到 /user/john, 那麼他就會重定向到 /user/john/,從而被該方法匹配到 router.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") message := name + " is " + action c.String(http.StatusOK, message) }) router.Run(":8080") } // 省略的代碼 ...
3)路由組
url統一前綴app
// 省略的代碼 ... func main() { router := gin.Default() // 定義一個組前綴 // /v1/login 就會匹配到這個組 v1 := router.Group("/v1") { v1.POST("/login", loginEndpoint) v1.POST("/submit", submitEndpoint) v1.POST("/read", readEndpoint) } // 定義一個組前綴 // 不用花括號包起來也是能夠的。上面那種只是看起來會統一一點。看你我的喜愛 v2 := router.Group("/v2") v2.POST("/login", loginEndpoint) v2.POST("/submit", submitEndpoint) v2.POST("/read", readEndpoint) router.Run(":8080") } // 省略的代碼 ...
5.中間件(middleware)
如驗證Auth,身份鑑別,集中處理返回的數據等等。
1)單個路由中間件框架
// 省略的代碼 ... func main() { router := gin.Default() // 註冊一個路由,使用了 middleware1,middleware2 兩個中間件 router.GET("/someGet", middleware1, middleware2, handler) // 默認綁定 :8080 router.Run() } func handler(c *gin.Context) { log.Println("exec handler") } func middleware1(c *gin.Context) { log.Println("exec middleware1") //你能夠寫一些邏輯代碼 // 執行該中間件以後的邏輯 c.Next() } // 省略的代碼 ...
c.Next()控制調用邏輯curl
2)路由組使用中間件
中間件放到路由組Group中函數
// 省略的代碼 ... func main() { router := gin.Default() // 定義一個組前綴, 並使用 middleware1 中間件 // 訪問 /v2/login 就會執行 middleware1 函數 v2 := router.Group("/v2", middleware1) v2.POST("/login", loginEndpoint) v2.POST("/submit", submitEndpoint) v2.POST("/read", readEndpoint) router.Run(":8080") } // 省略的代碼 ...
6.參數
1)Url查詢參數
使用c.Query方法,該方法始終返回一個string類型的數據。
// 省略的代碼 ... func main() { router := gin.Default() // 註冊路由和Handler // url爲 /welcome?firstname=Jane&lastname=Doe router.GET("/welcome", func(c *gin.Context) { // 獲取參數內容 // 獲取的全部參數內容的類型都是 string // 若是不存在,使用第二個當作默認內容 firstname := c.DefaultQuery("firstname", "Guest") // 獲取參數內容,沒有則返回空字符串 lastname := c.Query("lastname") c.String(http.StatusOK, "Hello %s %s", firstname, lastname) }) router.Run(":8080") }
2)表單和body參數(Multipart/Urlencoded Form)
對於POST請求,不管是multipart/form-data,仍是application/x-www-form-urlencoded格式,均可以使用c.PostForm獲取到參數,該方法始終返回一個string類型的數據
// 省略的代碼 ... func main() { router := gin.Default() router.POST("/form_post", func(c *gin.Context) { // 獲取post過來的message內容 // 獲取的全部參數內容的類型都是 string message := c.PostForm("message") // 若是不存在,使用第二個當作默認內容 nick := c.DefaultPostForm("nick", "anonymous") c.JSON(200, gin.H{ "status": "posted", "message": message, "nick": nick, }) }) router.Run(":8080") }
3)上傳文件
使用c.FormFile獲取文件
// 省略的代碼 ... func main() { router := gin.Default() // 設置文件上傳大小 router.MaxMultipartMemory = 8 << 20 // 8 MiB // 處理單一的文件上傳 router.POST("/upload", func(c *gin.Context) { // 拿到這個文件 file, _ := c.FormFile("file") log.Println(file.Filename) c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) }) // 處理多個文件的上傳 router.POST("/uploads", func(c *gin.Context) { form, _ := c.MultipartForm() // 拿到集合 files := form.File["upload[]"] for _, file := range files { log.Println(file.Filename) } c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files))) }) router.Run(":8080") }
使用curl工具測試一下:
# 單一文件上傳 $ curl -X POST http://localhost:8080/upload \ -F "file=@/Users/appleboy/test.zip" \ -H "Content-Type: multipart/form-data" # 多文件上傳 $ curl -X POST http://localhost:8080/uploads \ -F "upload[]=@/Users/appleboy/test1.zip" \ -F "upload[]=@/Users/appleboy/test2.zip" \ -H "Content-Type: multipart/form-data"
4)JSON參數(application/json)
使用c.GetRawData
// 省略的代碼 ... func main() { router := gin.Default() router.POST("/post", func(c *gin.Context) { // 獲取原始字節 d, err := c.GetRawData() if err!=nil { log.Fatalln(err) } log.Println(string(d)) c.String(200, "ok") }) router.Run(":8080") }
curl請求示例:
$ curl -v -X POST \ http://localhost:8080/post \ -H 'content-type: application/json' \ -d '{ "user": "manu" }'
7.數據綁定
將用戶傳來的參數自動跟咱們定義的結構體綁定在一塊兒
1)綁定Url查詢參數
使用c.ShouldBindQuery方法
package main import ( "log" "github.com/gin-gonic/gin" ) // 定義一個 Person 結構體,用來綁定 url query type Person struct { Name string `form:"name"` // 使用成員變量標籤訂義對應的參數名 Address string `form:"address"` } func main() { route := gin.Default() route.Any("/testing", startPage) route.Run(":8085") } func startPage(c *gin.Context) { var person Person // 將 url 查詢參數和person綁定在一塊兒 if c.ShouldBindQuery(&person) == nil { log.Println("====== Only Bind By Query String ======") log.Println(person.Name) log.Println(person.Address) } c.String(200, "Success") }
2)綁定url查詢參數和POST參數
使用c.ShouldBind方法,該方法會檢查url查詢參數和POST參數,而且會根據content-type類型,優先匹配JSON或XML,以後纔是Form
package main import "log" import "github.com/gin-gonic/gin" import "time" // 定義一個 Person 結構體,用來綁定數據 type Person struct { Name string `form:"name"` Address string `form:"address"` Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"` } func main() { route := gin.Default() route.GET("/testing", startPage) route.Run(":8085") } func startPage(c *gin.Context) { var person Person // 綁定到 person if c.ShouldBind(&person) == nil { log.Println(person.Name) log.Println(person.Address) log.Println(person.Birthday) } c.String(200, "Success") }
8.數據驗證
Gin提供了數據檢驗的方法,Gin的數據驗證是和數據綁定結合在一塊兒的,只須要在數據綁定的結構體成員變量的標籤添加bingding規則便可。
// 省略的代碼 ... // 定義的 Login 結構體 // 該 struct 能夠綁定在 Form 和 JSON 中 // binding:"required" 意思是必要參數。若是未提供,Bind 會返回 error type Login struct { User string `form:"user" json:"user" binding:"required"` Password string `form:"password" json:"password" binding:"required"` } func main() { router := gin.Default() // POST 到這個路由一段 JSON, 如 ({"user": "manu", "password": "123"}) router.POST("/loginJSON", func(c *gin.Context) { var json Login // 驗證數據並綁定 if err := c.ShouldBindJSON(&json); err == nil { if json.User == "manu" && json.Password == "123" { c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) } else { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) } } else { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } }) // POST 到這個路由一個 Form 表單 (user=manu&password=123) router.POST("/loginForm", func(c *gin.Context) { var form Login // 驗證數據並綁定 if err := c.ShouldBind(&form); err == nil { if form.User == "manu" && form.Password == "123" { c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) } else { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) } } else { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } }) router.Run(":8080") }
9.輸出響應
Gin提供了多種常見格式的輸出,包括HTML, String, JSON, XML, YAML
1)String
// 省略的代碼 ... func Handler(c *gin.Context) { // 使用 String 方法便可 c.String(200, "Success") } // 省略的代碼 ...
2)JSON, XML, YAML
gin.H表示實例化一個json對象
// 省略的代碼 ... func main() { r := gin.Default() // gin.H 本質是 map[string]interface{} r.GET("/someJSON", func(c *gin.Context) { // 會輸出頭格式爲 application/json; charset=UTF-8 的 json 字符串 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 // 會輸出 {"user": "Lena", "Message": "hey", "Number": 123} c.JSON(http.StatusOK, msg) }) r.GET("/someXML", func(c *gin.Context) { // 會輸出頭格式爲 text/xml; charset=UTF-8 的 xml 字符串 c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/someYAML", func(c *gin.Context) { // 會輸出頭格式爲 text/yaml; charset=UTF-8 的 yaml 字符串 c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.Run(":8080") } // 省略的代碼 ...
3)HTML
待實現
10.其餘 Gin沒有提供ORM,CONFIG組件,能夠由開發者本身選擇。