参数绑定

1991/6/26 Gin框架

# 1.介绍

Gin框架中参数不但能通过指定key接收,也可以直接绑定到结构体中,本篇主要讲解怎么直接绑定到结构体中,若要查看通过指定key接收,可查看历史文章Gin框架(五):参数接收 (opens new window)

# 1.1 绑定方法

Gin提供了Must bind 和 Should bind两种类型的绑定方法,这两种类型对应的方法如下:

功能 Must bind方法 Should bind方法
Bind ShouldBind
绑定JSON BindJSON ShouldBindJSON
绑定XML BindXML ShouldBindXML
绑定GET BindQuery ShouldBindQuery
绑定YAML BindYAML ShouldBindYAML

a.MustBindWith和ShouldBindWith

Bind*类型的方法是对MustBindWith封装;Should*类型的方法是对ShouldBindWith的封装;

# 1.2 绑定语法

定义被绑定的结构体

type StructName struct {
  Xxx  type  `form:"paramName" binding:"required"`
}
1
2
3

标签说明:

  • form:"paramName": paramName为参数的名称;
  • binding:"required": 代表字段必须绑定;

# 2.绑定uri参数

通过使用函数BindQueryShouldBindQuery,用来只绑定GET请求中的uri参数,如:/funcName?a=x&b=x中的a和b

# 2.1 代码

//-------- main.go ---------------
package main
import (
 "github.com/gin-gonic/gin" // 引入Gin框架
 "go-use/practise" // 代码示例包
)
func main() {
 engine := gin.Default()
 practise.TestBindQuery(engine)
 _ = engine.Run()
}
//------ go-use/practise/param_bind.go -------
// 定义结构体
type UriParam struct {
 Name  string   `form:"name" binding:"required"`
 Age   int      `form:"age"`
  Home  string   `form:"home"`
}
// 绑定GET(BindQuery和ShouldBindQuery)
func TestBindQuery(engine *gin.Engine) {
 engine.GET("/bindQuery", func(context *gin.Context) {
  bindType := context.Query("type")
  var uriParam UriParam
  var err error
  if bindType == "1" {
   fmt.Println("BindQuery")
   err = context.BindQuery(&uriParam)
  } else {
   fmt.Println("ShouldBindQuery")
   err = context.ShouldBindQuery(&uriParam)
  }
  if err != nil {
   context.JSON(500, gin.H{"error": err.Error()})
   return
  }
  fmt.Printf("uriParam:%+v\n", uriParam)
  context.JSON(200, gin.H{"result": uriParam})
 })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 2.2 请求

# 参数都传
➜ curl -X GET http://127.0.0.1:8080/bindQuery?age=24&name=张三&home=北京&type=1
{"result":{"Name":"张三","Age":24,"Home":"北京"}}
➜ curl -X GET http://127.0.0.1:8080/bindQuery?age=24&name=张三&home=北京&type=2
{"result":{"Name":"张三","Age":24,"Home":"北京"}}
# 必填参数name不填时,都会报错
➜ curl -X GET http://127.0.0.1:8080/bindQuery?age=24&home=北京&type=2
{"error":"Key: 'UriParam.Name' Error:Field validation for 'Name' failed on the 'required' tag"}
1
2
3
4
5
6
7
8

# 3.绑定JSON

使用函数BindJSON 和 ShouldBindJSON来绑定提交的JSON参数信息。

# 3.1 代码

//-------- main.go ---------------
package main
import (
 "github.com/gin-gonic/gin" // 引入Gin框架
 "go-use/practise" // 代码示例包
)
func main() {
 engine := gin.Default()
 practise.TestBindJson(engine)
 _ = engine.Run()
}
//------ go-use/practise/param_bind.go -------
// 定义待绑定的JSON结构体
type Param struct {
 Name  string   `json:"name"`
 Age   int      `json:"age"`
 Likes []string `json:"likes"`
}
// 绑定提交的Json数据
func TestBindJson(engine *gin.Engine) {
 engine.POST("/bindJson", func(context *gin.Context) {
  var jsonParam Param
  var err error
  bindType := context.Query("type")
  fmt.Println(bindType)
  if bindType == "1" {
   err = context.BindJSON(&jsonParam)
  } else {
   err = context.ShouldBindJSON(&jsonParam)
  }
  if err != nil {
   context.JSON(500, gin.H{"error": err})
   return
  }
  context.JSON(200, gin.H{"result": jsonParam})
 })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 3.2 请求

# 4.绑定XML

使用函数BindXML 和 ShouldBindXML来绑定提交的XML参数信息。

# 4.1 代码

//-------- main.go ---------------
package main
import (
 "github.com/gin-gonic/gin" // 引入Gin框架
 "go-use/practise" // 代码示例包
)
func main() {
 engine := gin.Default()
 practise.TestBindXml(engine)
 _ = engine.Run()
}
//------ go-use/practise/param_bind.go -------
// 修改待绑定的JSON结构体,添加XML标签
type Param struct {
 Name  string   `json:"name" xml:"name"`
 Age   int      `json:"age" xml:"age"`
 Likes []string `json:"likes" xml:"likes"`
}
// 绑定Xml信息
func TestBindXml(engine *gin.Engine) {
 engine.POST("/bindXml", func(context *gin.Context) {
  var param Param
  var err error
  bindType := context.Query("type")
  if bindType == "1" {
   err = context.BindXML(&param)
  } else {
   err = context.ShouldBindXML(&param)
  }
  if err != nil {
   context.JSON(500, gin.H{"error": err})
   return
  }
  context.JSON(200, gin.H{"result": param})
 })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 4.2 请求

# 5.绑定request.Body

c.Request.Body` 不能多次被调用,第一次绑定之后 `c.Request.Body会设置成EOF
1

# 5.1 错误示例

  • a.代码

    //-------- main.go ---------------
    package main
    import (
     "github.com/gin-gonic/gin" // 引入Gin框架
     "go-use/practise" // 代码示例包
    )
    func main() {
     engine := gin.Default()
     practise.TestBindXml(engine)
     _ = engine.Run()
    }
    //------ go-use/practise/param_bind.go -------
    type BodyAParam struct {
     Name string `json:"name"`
    }
    type BodyBParam struct {
     Home string `json:"home"`
    }
    // 重复绑定request.Body(错误示例)
    func TestBindBody(engine *gin.Engine) {
     engine.POST("/body", func(context *gin.Context) {
      paramA := BodyAParam{}
      paramB := BodyBParam{}
      // c.ShouldBind 使用了 c.Request.Body,不可重用。
      _ = context.ShouldBindJSON(&paramA)
      // 因为现在 c.Request.Body 是 EOF,所以这里会报错。
      _ = context.ShouldBindJSON(&paramB)
      context.JSON(200,gin.H{"paramA":paramA,"paramB":paramB})
     })
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
  • b.请求返回

    # 发现只有paramA绑定成功
    ➜ curl -X POST http://127.0.0.1:8080/body -d '{"name":"李四","home":"上海"}'
    {"paramA":{"name":"李四"},"paramB":{"home":""}}
    
    1
    2
    3

# 5.2 正确示例

  • a.代码

    //-------- main.go ---------------
    package main
    import (
     "github.com/gin-gonic/gin" // 引入Gin框架
     "go-use/practise" // 代码示例包
    )
    func main() {
     engine := gin.Default()
     practise.TestBindXml(engine)
     _ = engine.Run()
    }
    //------ go-use/practise/param_bind.go -------
    type BodyAParam struct {
     Name string `json:"name"`
    }
    type BodyBParam struct {
     Home string `json:"home"`
    }
    // 重复绑定request.Body(正确示例)
    func TestBindBody2(engine *gin.Engine) {
     engine.POST("/body2", func(context *gin.Context) {
      paramA := BodyAParam{}
      paramB := BodyBParam{}
      // 读取 c.Request.Body 并将结果存入上下文。
      _ = context.ShouldBindBodyWith(&paramA,binding.JSON)
      // 这时, 复用存储在上下文中的 body。
      _ = context.ShouldBindBodyWith(&paramB,binding.JSON)
      context.JSON(200,gin.H{"paramA":paramA,"paramB":paramB})
     })
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
  • b.请求返回

    # paramA和paramB都绑定成功
    ➜ curl -X POST http://127.0.0.1:8080/body2 -d '{"name":"李四","home":"上海"}'
    {"paramA":{"name":"李四"},"paramB":{"home":"上海"}}
    
    1
    2
    3