gin bind(重要)


 

一、數據綁定:

1. 數據綁定介紹:

Gin提供了兩類綁定方法:

  • Must bind:
    • Methods:
      • Bind, BindJSON, BindXML, BindQuery, BindYAML
    • Behavior:
      • 這些方法屬於MustBindWith的具體調用. 如果發生綁定錯誤, 則請求終止, 並觸發 c.AbortWithError(400, err).SetType(ErrorTypeBind)響應狀態碼被設置為 400 並且Content-Type被設置為text/plain; charset=utf-8. 如果您在此之后嘗試設置響應狀態碼, Gin會輸出日志[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422. 如果您希望更好地控制綁定, 考慮使用ShouldBind等效方法.
  • Should bind:
    • Methods:
      • ShouldBind, ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML
    • Behavior:
      • 這些方法屬於ShouldBindWith的具體調用. 如果發生綁定錯誤, Gin 會返回錯誤並由開發者處理錯誤和請求.

2. 數據綁定–Should bind:

2.1 ShouldBind:

.
├── chapter05
│   └── bind_form.go
├── main.go
├── static
├── template
│   ├── chapter05
│   │   └── user_add.html
  • ./main.go
package main import ( "gin_project/chapter05" "github.com/gin-gonic/gin" ) func main() { engine := gin.Default() // 注冊模板 engine.LoadHTMLGlob("template/**/*") // 注冊靜態文件 engine.Static("./static", "static") // 注冊路由 engine.GET("/to_bindform", chapter05.ToBindform) engine.POST("/push_bindform", chapter05.DoBindform) engine.GET("/push_bindquery", chapter05.DoBindquery) // http://localhost:9000/push_bindquery?name=zhangsan&age=110&addr=%E5%8C%97%E4%BA%AC engine.POST("/push_bindajax", chapter05.DoBindajax) engine.Run(":9000") } 

 

  • ./chapter05/bind_form.go
package chapter05 import ( "fmt" "net/http" "github.com/gin-gonic/gin" ) type User struct { Name string `form:"name" json:"name"` Age int `form:"age" json:"age"` Addr string `form:"addr" json:"addr"` } func ToBindform(ctx *gin.Context) { ctx.HTML(http.StatusOK, "chapter05/user_add.html", nil) } // bind form data func DoBindform(ctx *gin.Context) { var user User err := ctx.ShouldBind(&user) fmt.Println(user) if err != nil { ctx.String(http.StatusNotFound, "綁定form失敗") } else { ctx.String(http.StatusOK, "綁定form成功") } } // bind Query data func DoBindquery(ctx *gin.Context) { var user User err := ctx.ShouldBind(&user) fmt.Println(user) if err != nil { ctx.String(http.StatusNotFound, "綁定query失敗") } else { ctx.String(http.StatusOK, "綁定query成功") } } // bind Ajax data func DoBindajax(ctx *gin.Context) { var user User err := ctx.ShouldBind(&user) fmt.Println(user) if err != nil { ctx.String(http.StatusNotFound, "綁定ajax失敗") } else { ctx.String(http.StatusOK, "綁定ajax成功") } } 

 

  • ./template/chapter05/user_add.html
{{ define "chapter05/user_add.html" }}
<!DOCTYPE html> <html lang="zh"> <head> <title>post請求練習</title> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> <style> .userForm { width: 480px; height: 360px; margin: 20px 200px; } input { margin: 5px 0; } </style> </head> <body> <div class="userForm"> <h2>bind form data</h2> <form action="/push_bindform" method="post"> <p>姓名:<input type="text" name="name" id="name"></p> <p>年齡:<input type="text" name="age" id="age"></p> <p>地址:<input type="text" name="addr" id="addr"></p> <p><input type="submit" value="提交form"></p> <p><input type="button" value="提交ajax" id="sub-btn"></p> </form> </div> <script> // 使用ajax提交json var btn = document.querySelector("#sub-btn") btn.onclick = function(ev) { var name = document.getElementById("name").value; var age = document.getElementById("age").value; var addr = document.getElementById("addr").value; console.log(name, age, addr); $.ajax({ url:"/push_bindajax", type:"POST", data: JSON.stringify({ "name":name, "age":Number(age), "addr":addr }), contentType: "application/json", dataType: "json", success:function (data) { alert(data["code"]); alert(data["msg"]); }, fail:function (data) { console.log(data); } }) } </script> </body> </html> {{ end }} 

 

2.2 ShouldBindWith

可以使用顯式綁定聲明綁定 multipart form:

ctx.ShouldBindWith(&form, binding.Form)

或者簡單地使用 ShouldBind 方法自動綁定

2.3 ShouldBindQuery等

ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML等函數只綁定對應格式的參數

2.4 ShouldBindUri:綁定 Uri:

package main import ( "gin_project/chapter05" "github.com/gin-gonic/gin" ) func main() { engine := gin.Default() // 注冊模板 engine.LoadHTMLGlob("template/**/*") // 注冊靜態文件 engine.Static("./static", "static") // 注冊路由 engine.GET("/push_bindURI/:name/:age/:addr", chapter05.DoBindURI) // http://localhost:9000/push_bindURI/zhangsan/19/%E5%8C%97%E4%BA%AC engine.Run(":9000") } 

 

package chapter05 import ( "fmt" "net/http" "github.com/gin-gonic/gin" ) type User struct { Name string `form:"name" json:"name" uri:"name"` Age int `form:"age" json:"age" uri:"age"` Addr string `form:"addr" json:"addr" uri:"addr"` } ... // bind URI data func DoBindURI(ctx *gin.Context) { var user User err := ctx.ShouldBindUri(&user) fmt.Println(user) if err != nil { ctx.String(http.StatusNotFound, "綁定uri失敗") } else { ctx.String(http.StatusOK, "綁定uri成功") } }

 

3. 數據綁定–Must bind

3.1 Bind

可以綁定Form、QueryString、Json等

和ShouldBind的區別在於,ShouldBind沒有綁定成功不報錯,就是空值,Bind會報錯

3.2 BindQuery等

BindJSON, BindXML, BindQuery, BindYAML等函數只綁定對應格式的參數

二、數據驗證:

1. 使用:

go-playground/validator.v8進行驗證
使用structTagbinding,如:binding:"required"
如果沒有空值或者類型不匹配就會報錯,重定向到400 (Bad Request)
錯誤信息:Key: 'Article.Title' Error:Field validation for 'Title' failed on the 'required' tag

./
├── chapter05
│   └── valid_data.go
├── main.go
├── static
├── template
│   ├── chapter05
│   │   └── valid_data.html

 

  • ./main.go
package main import ( "gin_project/chapter05" "github.com/gin-gonic/gin" ) func main() { engine := gin.Default() // 注冊模板 engine.LoadHTMLGlob("template/**/*") // 注冊靜態文件 engine.Static("./static", "static") // 注冊路由 engine.GET("/to_valid", chapter05.ToValidData) engine.POST("/do_valid", chapter05.DoValidData) engine.Run(":9000") } 

 

  • ./chapter05/valid_data.go
package chapter05 import ( "fmt" "net/http" "github.com/gin-gonic/gin" ) type Article struct { Id int `form:"-"` Title string `form:"title" binding:"required"` Content string `form:"content"` Desc string `form:"desc"` } func ToValidData(ctx *gin.Context) { ctx.HTML(http.StatusOK, "chapter05/valid_data.html", nil) } func DoValidData(ctx *gin.Context) { var article Article err := ctx.ShouldBind(&article) if err != nil { fmt.Println(err) ctx.JSON(http.StatusBadRequest, gin.H{ "msg": "參數錯誤", }) } fmt.Println(article) ctx.String(http.StatusOK, "成功") } 

 

  • ./template/chapter05/valid_data.html
{{ define "chapter05/valid_data.html" }}
<!DOCTYPE html> <html lang="cn"> <head> <title>數據驗證</title> <style> .form { width: 300px; height: 300px; margin: 100px auto; } </style> </head> <body> <div class="form"> <form action="/do_valid" method="post"> <p>title: <input type="text" name="title"></p> <p>content: <input type="text" name="content"></p> <p>desc: <input type="text" name="desc"></p> <p><input type="submit" name="btn" value="提交"></p> </form> </div> </body> </html> {{ end }} 

 

2. 其他驗證器:

官方文檔:https://godoc.org/gopkg.in/go-playground/validator.v8#hdr-Baked_In_Validators_and_Tags

注意:
多個驗證器之間用英文輸入法下的逗號(,)隔開, 並且是按照驗證器的順序執行的
如果希望在參數中包含逗號(即excludesall =,), 則需要使用UTF-8十六進制表示形式0x2C例如: validate:"excludesall=0x2C"

驗證器 說明 示例
- 忽略字段 binding:"-"
required 必填字段 binding:“required”
min 最小長度 binding:“min=10”
max 最大長度 binding:“max=10”
| binding:"rgb
structonly 如果有嵌套,可以決定只驗證結構體上的 binding:“structonly”
omitempty 省略空,如果為空,則不會繼續驗證該字段上其他的規則,只有不為空才會繼續驗證其他的  
len 長度 binding:“len=10”
eq 等於 binding:“eq=10”
ne 不等於 binding:“ne=10”
gt 大於 binding:“gt=10”
gte 大於等於 binding:“gte=10”
lt 小於 binding:“lt=10”
lte 小於等於 binding:“lte=10”
eqfield 等於其他字段的值 Password string binding:"eqfield=ConfirmPassword"
nefield 不等於其他字段的值  
eqcsfield 類似eqfield,它會驗證相對於頂層結構提供的字段 binding:"eqcsfield = InnerStructField.Field
necsfield    
gtfield 大於其他字段的值  
gtefield    
gtcsfield    
gtecsfield    
ltfield 小於其他字段的值  
ltefield    
ltcsfield    
ltecsfield    
alpha 字符串值僅包含字母字符  
alphanum 字符串值僅包含字母數字字符  
numeric 字符串值包含基本數字值。基本不包括指數等…  
hexadecimal 字符串值包含有效的十六進制  
hexcolor 驗證字符串值包含有效的十六進制顏色, 包括井號(#)  
rgb 字符串值包含有效的rgb顏色  
rgba 字符串值包含有效的rgba顏色  
HSL 字符串值包含有效的hsl顏色  
hsla 字符串值包含有效的hsla顏色  
email 字符串值包含有效的電子郵件  
url 字符串值包含有效的網址,必須包含http://等  
uri 字符串值包含有效的uri. 它將接受golang請求uri接受的任何uri  
base64 字符串值包含有效的base64值  
contains 字符串值包含子字符串值, contains=@  
containsany 包含所有,containsany =!@#?  
containsrune 字符串值包含提供的符號 containsrune = @  
excludes 字符串值不包含子字符串值,excludes = @  
excludeall 排除所有  
excluderune 字符串值不包含提供的符號,excluderune = @  
isbn 國際標准書號,驗證字符串值包含有效的isbn10或isbn13值  
isbn10 國際標准書號10, 驗證字符串值包含有效的isbn10值  
isbn13 國際標准書號13, 字符串值包含有效的isbn13值  
uuid 字符串值包含有效的UUID  
uuid3 字符串值包含有效的版本3 UUID  
uuid4 字符串值包含有效的版本5 UUID  
uuid5 字符串值包含有效的版本5 UUID  
ascii 字符串值僅包含ASCII字符. 注意:如果字符串為空, 則驗證為true  
asciiprint 字符串值僅包含可打印的ASCII字符. 注意: 如果字符串為空,則驗證為true  
multibyte 字符串值包含一個或多個多字節字符。注意:如果字符串為空,則驗證為true  
datauri 字符串值包含有效的DataURI。注意:這還將驗證數據部分是有效的base64  
latitude 緯度,字符串值包含有效的緯度  
longitude 經度,字符串值包含有效的經度  
ssn 字符串值包含有效的美國社會安全號碼  
ip 字符串值包含有效的IP地址  
ipv4 字符串值包含有效的v4 IP地址  
ipv6 字符串值包含有效的v6 IP地址  
cidr 字符串值包含有效的CIDR地址  
cidrv4 字符串值包含有效的CIDR地址  
cidrv6 字符串值包含有效的v6 CIDR地址  
tcp_addr 字符串值包含有效的可解析TCP地址  
dive 嵌套驗證  
name [][]string `binding:"gt=0,dive,len=1,dive,required"` // gt = 0將應用於[] // len = 1將應用於[] string //必填項將應用於字符串 name [][]string `binding:"gt=0,dive,dive,required"` // gt = 0 將應用於[] // []string 將保留驗證 //必填項將應用於字符串 

 

注意:gt、gte、lt、lte等都可以用於時間的比較,后面不需要跟值,直接binding:“gt”,表示大於當前utc時間

3. 自定義驗證器:

自定義驗證器

3.1 安裝:

go get github.com/go-playground/validator

3.2 定義驗證器:

注意:必須為validator.Func類型

var Len6Valid validator.Func = func(fl validator.FieldLevel) bool { data := fl.Field().Interface().(string) if len(data) > 6 { fmt.Println("false") return false }else { fmt.Println("true") return true } } 

 

3.3 注冊驗證器:

在路由匹配前,main中即可

if v, ok := binding.Validator.Engine().(*validator.Validate); ok { v.RegisterValidation("len_valid", valid.Len6Valid) } 

 

3.4 結構體中使用:

這里必須binding中,而且名稱為前面注冊的字符串名稱

type Article struct { Id int `form:"id"` Title string `form:"title" binding:"required,len_valid"` Desc string `form:"desc" binding:"required,len_valid"` }

 

4. beego中的驗證器:

4.1 安裝

go get github.com/astaxie/beego/validation

4.2 驗證方法:

方法 說明
Required 不為空,即各個類型要求不為其零值
Min(min int) 最小值,有效類型:int,其他類型都將不能通過驗證
Max(max int) 最大值,有效類型:int,其他類型都將不能通過驗證
Range(min, max int) 數值的范圍,有效類型:int,他類型都將不能通過驗證
MinSize(min int) 最小長度,有效類型:string slice,其他類型都將不能通過驗證
MaxSize(max int) 最大長度,有效類型:string slice,其他類型都將不能通過驗證
Length(length int) 指定長度,有效類型:string slice,其他類型都將不能通過驗證
Alpha alpha字符,有效類型:string,其他類型都將不能通過驗證
Numeric 數字,有效類型:string,其他類型都將不能通過驗證
AlphaNumeric alpha 字符或數字,有效類型:string,其他類型都將不能通過驗證
Match(pattern string) 正則匹配,有效類型:string,其他類型都將被轉成字符串再匹配(fmt.Sprintf(“%v”, obj).Match)
AlphaDash alpha 字符或數字或橫杠 -_,有效類型:string,其他類型都將不能通過驗證
Email 郵箱格式,有效類型:string,其他類型都將不能通過驗證
IP IP 格式,目前只支持 IPv4 格式驗證,有效類型:string,其他類型都將不能通過驗證
Base64 base64 編碼,有效類型:string,其他類型都將不能通過驗證
Mobile 手機號,有效類型:string,其他類型都將不能通過驗證
Tel 固定電話號,有效類型:string,其他類型都將不能通過驗證
Phone 手機號或固定電話號,有效類型:string,其他類型都將不能通過驗證
ZipCode 郵政編碼,有效類型:string,其他類型都將不能通過驗證

4.3 通過 StructTag校驗數據:

  • 驗證函數寫在 “valid” tag 的標簽里
  • 各個驗證規則之間用分號 “;” 分隔,分號后面可以有空格
  • 參數用括號 “()” 括起來,多個參數之間用逗號 “,” 分開,逗號后面可以有空格
  • 正則函數(Match)的匹配模式用兩斜杠 “/” 括起來
  • 各個函數的結果的 key 值為字段名.驗證函數名
type LoginParams struct { Name string valid:"Required" Age int valid:"Required;MinSize(2)" Addr string valid:"Required" } func (l *LoginController) Post() { valid := validation.Validation{} // 解析到結構體 params := LoginParams{} if err := l.ParseForm(&params); err != nil { //handle error return } //重寫錯誤信息:validation.SetDefaultMessage(map) var messages = map[string]string{ "Required": "不能為空", "MinSize": "最短長度為 %d", "Length": "長度必須為 %d", "Numeric": "必須是有效的數字", "Email": "必須是有效的電子郵件地址", "Mobile": "必須是有效的手機號碼", } validation.SetDefaultMessage(messages) // 校驗 b, err := valid.Valid(&params) // 驗證StructTag 是否正確 if err != nil { fmt.Println(err) } if !b { // 驗證沒通過,則b為false for _, err := range valid.Errors { fmt.Println(err.Key, err.Message) message := err.Key + err.Message l.Ctx.WriteString(message) } } }


免責聲明!

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



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