技術概述
本博客介紹使用gin框架完成基礎的數據解析與綁定功能,以及列舉出一些比較容易踩的坑。主要內容包括:json數據解析與綁定,表單數據解析與綁定,url數據解析與綁定
技術詳述
1. json數據解析與綁定
先看官方文檔中的源代碼:
// 定義接收數據的結構體
type Login struct {
User string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
Pssword string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
}
func main() {
r := gin.Default()
// JSON綁定
r.POST("loginJSON", func(c *gin.Context) {
var json Login
// 將request的body中的數據,自動按照json格式解析到結構體
if err := c.ShouldBindJSON(&json); err != nil {
// 返回錯誤信息
// gin.H封裝了生成json數據的工具
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 判斷用戶名密碼是否正確
if json.User != "root" || json.Pssword != "admin" {
c.JSON(http.StatusBadRequest, gin.H{"status": "304"})
return
}
c.JSON(http.StatusOK, gin.H{"status": "200"})
})
r.Run(":8000")
}
這是一個簡單的獲取json中的賬號密碼,並進行驗證的例子。從該例子中可以看出:
- 獲取json數據時不必通過輸入json中每個key值來獲得對應的數據
- 結構體需要與獲取json的格式相對應
- 返回結果可以使用gin框架中封裝的方法
- post方法中需要一個與上下文(context)有關的參數,用於接收前端發來的json數據
於是,我們可以:
- 將service服務的結構體中的數據與需要從前端獲取的參數一一對應,而刪除掉多余的數據
- 聲明一個函數用於json數據獲取,解析與綁定,並調用相應的服務,將
c *gin.Context
作為方程的參數 - 將service服務的結構體與接收的json進行綁定
- 調用service服務處理數據
- 返回結果
下面用一個比較完整的程序片段來闡述具體用法:
-
service結構體中的數據
type CreateTeamService struct { model.TeamRepositoryInterface // 聲明了具體操作數據庫創建團隊的接口 Name string `form:"name" json:"name" binding:"required"` GroupLeaderID int `form:"group_leader_id" json:"group_leader_id" binding:"required"` ClassID int `form:"class_id" json:"class_id" binding:"required"` }
-
post方法響應請求
// 創建團隊 v1.POST("team/create", api.CreateTeam)
-
json數據解析與綁定具體函數
func CreateTeam(c *gin.Context) { // 該函數與CreateTeamService服務在不同的文件中 var service service.CreateTeamService if err := c.ShouldBind(&service); err == nil { // 實例化接口 service.TeamRepositoryInterface = &model.Repo res := service.CreateTeam() c.JSON(http.StatusOK, res) } else { c.JSON(http.StatusOK, ErrorResponse(err)) } }
可以看出,大致過程與上述官方文檔中的用例一致。
2. 表單數據解析和綁定
具體代碼與json數據解析與綁定幾乎完全一致,不同處僅僅在於將ShouldBindJSON()
方法換成了Bind()
方法。
這也是gin框架的強大之處,即面對不同的前端數據有統一的代碼處理方法。其本質上,還是將表單數據中每個數據的key值與結構中的數據一一對應。
-
表單結構示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <form action="http://localhost:8000/loginForm" method="post" enctype="application/x-www-form-urlencoded"> 用戶名<input type="text" name="username"><br> 密碼<input type="password" name="password"> <input type="submit" value="提交"> </form> </body> </html>
-
結構體示例
type Login struct { // binding:"required"修飾的字段,若接收為空值,則報錯,是必須字段 User string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"` Pssword string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"` }
3. URI數據解析和綁定
具體代碼與上述兩種方式大致相同,同樣地,需要將ShouldBindJSON()
方法換成ShouldBindUri
方法。
除此之外,需要注意獲取api參數的方法,在此僅介紹最簡單的一種方法:
-
獲取api參數代碼
(測試url:
localhost:8080/user/烏雞/805376577.com
)r.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") //截取/ action = strings.Trim(action, "/") c.String(http.StatusOK, name+" is "+action) })
輸出結果:烏雞 is 805376577.com
注意事項&最佳實踐
- 一定要在使用service服務的函數中實例化結構體中的接口,不然會報空指針的錯誤
- 注意結構體中的數據類型,嚴格按照接口文檔中的數據類型設計,同時,在“json”或“form“屬性中填入相應的”key“值,做到一一對應
- 一定要在接收數據時加入判錯處理
- 最好不要在一個函數中調用兩個service服務(實際上也很難做到)
- 返回給前端的結果可以考慮用
http.StatusOK
替代200
總結
gin框架給代碼的編寫帶來了諸多方便,不僅代碼簡單友好,並且在程序出錯的情況下也可以通過報錯快速找到解決措施,因為gin的報錯都很詳細,我推薦使用go語言可以多多使用gin框架。
雖然網上gin的官方文檔都介紹的比較詳細,但是關於gin的個人教程以及問答帖子在國內的數量比較少,所以有時候出了問題比較難在網上直接找到解決方法。好在gin語法簡單,只要有一定編程基礎,應該都能夠獨立解決大部分問題。