在第一篇中看到了Gin提供了不少的獲取和解析參數的方法:json
// **** 輸入數據 //從URL中拿值,好比 /user/:id => /user/john Param(key string) string //從GET參數中拿值,好比 /path?id=john GetQueryArray(key string) ([]string, bool) GetQuery(key string)(string, bool) Query(key string) string DefaultQuery(key, defaultValue string) string GetQueryArray(key string) ([]string, bool) QueryArray(key string) []string //從POST中拿數據 GetPostFormArray(key string) ([]string, bool) PostFormArray(key string) []string GetPostForm(key string) (string, bool) PostForm(key string) string DefaultPostForm(key, defaultValue string) string // 文件 FormFile(name string) (*multipart.FileHeader, error) MultipartForm() (*multipart.Form, error) SaveUploadedFile(file *multipart.FileHeader, dst string) error // 數據綁定 Bind(obj interface{}) error //根據Content-Type綁定數據 BindJSON(obj interface{}) error BindQuery(obj interface{}) error //--- Should ok, else return error ShouldBindJSON(obj interface{}) error ShouldBind(obj interface{}) error ShouldBindJSON(obj interface{}) error ShouldBindQuery(obj interface{}) error
其中從url中獲取 從get參數中獲取 從post拿數據相信咱們均可以想象的到,基本就是從request中的url或者body中獲取數據而後返回
可是其中的數據綁定我本身開始是很疑惑的,究竟是怎麼實現的。疑惑的是若是object中我客戶端少輸入了參數 或者多輸入的參數會是怎麼樣。舉個例子:函數
type Login struct { User string `json:"user"` Password string `json:"password"` Age int } //僞代碼 l := Login{} context.Bind(&l)
若是客戶端輸入的是{"user":"TAO","age":10} 沒有輸入password 獲得的對象是什麼會不會報錯
若是客戶端輸入的是{"user":"TAO","age":10,"class":"class"}多輸入了一個class的參數 結果是什麼
若是客戶端輸入的是{} 這邊會不會報錯,會獲得什麼結果
這些都是須要看源碼
先看gin/binding/binding.gopost
//Binding 接口 定義了一個返回名字的函數 //還有一個Bind 函數接口 這個是關鍵函數 //從request中獲取數據解析 //全部類型的處理對象都繼承這個接口來實現多態 type Binding interface { Name() string Bind(*http.Request, interface{}) error } type BindingBody interface { Binding BindBody([]byte, interface{}) error } //在包中定義了8個對象 能夠供給context直接使用 var ( JSON = jsonBinding{} XML = xmlBinding{} Form = formBinding{} Query = queryBinding{} FormPost = formPostBinding{} FormMultipart = formMultipartBinding{} ProtoBuf = protobufBinding{} MsgPack = msgpackBinding{} )
接下來是繼承Binding接口的對象,這樣的對象有不少咱們就舉一個例子JSON,JSON是咱們使用的最多的一個方式。
gin/binding/json.go學習
//type 是Gin處理json對象使用的類 繼承Binding type jsonBinding struct{} func (jsonBinding) Name() string { return "json" } //調用decodeJSON方法處理 func (jsonBinding) Bind(req *http.Request, obj interface{}) error { return decodeJSON(req.Body, obj) } func (jsonBinding) BindBody(body []byte, obj interface{}) error { return decodeJSON(bytes.NewReader(body), obj) } // 能夠看到,這個方法就是從request中獲取body而後使用json包的decoder來轉換成對象 func decodeJSON(r io.Reader, obj interface{}) error { decoder := json.NewDecoder(r) if EnableDecoderUseNumber { decoder.UseNumber() } if err := decoder.Decode(obj); err != nil { return err } return validate(obj) }
最後再看一下context是如何調用的url
//這個binding.JSON 就是上面binding中定義的那8個類其中的一個 這裏能夠直接的使用 func (c *Context) BindJSON(obj interface{}) error { return c.MustBindWith(obj, binding.JSON) } //這個方法能夠接收Binding接口,在Gin中有7 8 個類都是繼承了這個接口 均可以調用這個方法來執行解析 func (c *Context) MustBindWith(obj interface{}, b binding.Binding) (err error) { if err = c.ShouldBindWith(obj, b); err != nil { c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) } return } //這個方法就是調用上面一段代碼定義的json的bind方法 func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error { return b.Bind(c.Request, obj) }
看了上面的代碼,其實整個binding已經很清晰了。
最終,Gin就是調用了json包中的解析。那麼咱們上面的一系列問題就很輕鬆的解決了code
這些行爲跟json的處理行爲是徹底一致的。orm
老規矩,在瞭解了binding的主體流程以後,咱們能夠本身簡單的實現其中幾個功能 好比json和xml的解析。咱們能夠看到如下代碼,能夠很清晰的看到Gin的實現方式。xml
package mygin import ( "encoding/json" "encoding/xml" "net/http" ) var ( JSON = JsonBinding{} XML = XmlBinding{} ) //bind接口 方便多態 type Binding interface { //返回name Name() string //具體執行 Bind(*http.Request, interface{}) error } type XmlBinding struct { } func (XmlBinding) Name() string { return "XmlBinding" } func (XmlBinding) Bind(r *http.Request, obj interface{}) error { //使用json包中的方法 把string轉成對象 decoder := xml.NewDecoder(r.Body) if err := decoder.Decode(obj); err != nil { return err } return nil } type JsonBinding struct { } func (JsonBinding) Name() string { return "jsonBinding" } func (JsonBinding) Bind(r *http.Request, obj interface{}) error { //使用json包中的方法 把string轉成對象 decoder := json.NewDecoder(r.Body) if err := decoder.Decode(obj); err != nil { return err } return nil } // context調用 func (c *Context) BindWith(obj interface{}, b Binding) error { //調用binding 的Bind方法 if err := b.Bind(c.Request, obj); err != nil { return err } return nil } func (c *Context) BindJson(obj interface{}) error { return c.BindWith(obj, JSON) }
代碼比較簡單,幾乎不須要加註釋就能很清楚的看懂。 配合上一篇文章的Gin主流程能夠徹底的跑起來。結果這裏就不寫了,上面都描述過了。對象