Gin框架使用詳解


1.什么是Gin
Gin是go編寫的一個web應用框架。

2.Gin安裝

go get github.com/gin-gonic/gin

3.Gin使用示例

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")
}

運行結果:

4.路由(Router)
1)restful api
注冊路由方法有GET,POST,PUT,PATCH,DELETE,OPTIONS

// 省略的代碼 ...

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/:id

// 省略的代碼 ...

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統一前綴

// 省略的代碼 ...

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()控制調用邏輯

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組件,可以由開發者自己選擇。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM