参数绑定
import (
"fmt"
"github.com/gin-gonic/gin"
)
// json是json的绑定方式
// form是url绑定方式,自动绑定也是这个字段。例;127.0.0.1:9090/query?name=张三&age=12&sex=男
// uri是另一种url的绑定方式。例;127.0.0.1:9090/uri/张三/12/男
type UserInfo struct {
Name string `json:"name" form:"name" uri:"name"`
Age int `json:"age" form:"age" uri:"age"`
Sex string `json:"sex" form:"sex" uri:"sex"`
}
// 可以将前端传递来的数据与结构体进行参数绑定和校验
func main() {
r := gin.Default()
//绑定json参数
r.POST("/", func(c *gin.Context) {
var userInfo UserInfo
//将传过来的json内容绑定到userInfo,如果校验不通过返回err
err := c.ShouldBindJSON(&userInfo)
if err != nil {
c.JSON(200, gin.H{"msg": "你错了"})
return
}
c.JSON(200, userInfo)
})
r.POST("/query", func(c *gin.Context) {
var userInfo UserInfo
//ShouldBindQuery。根据url或者form表单绑定动态参数,不一定非要query,对应form字段。
//例:127.0.0.1:9090/query?name=张三&age=12&sex=男
err := c.ShouldBindQuery(&userInfo)
if err != nil {
c.JSON(200, gin.H{"msg": "你错了"})
return
}
c.JSON(200, userInfo)
})
///uri/:name/:age/:sex要和参数一一对应,不一定非要uri。例;127.0.0.1:9090/uri/张三/12/男
r.POST("/uri/:name/:age/:sex", func(c *gin.Context) {
var userInfo UserInfo
//ShouldBindUri。根据url和绑定动态参数,对应uri字段。
//例;127.0.0.1:9090/uri/张三/12/男
err := c.ShouldBindUri(&userInfo)
if err != nil {
c.JSON(200, gin.H{"msg": "你错了"})
return
}
c.JSON(200, userInfo)
})
r.POST("/form", func(c *gin.Context) {
fmt.Println(c.MultipartForm())
var userInfo UserInfo
//ShouldBind。自动绑定动态参数,根据form字段来判断
err := c.ShouldBind(&userInfo)
if err != nil {
c.JSON(200, gin.H{"msg": "你错了"})
return
}
c.JSON(200, userInfo)
})
r.Run(":9090")
}
参数验证
import (
"fmt"
"github.com/gin-gonic/gin"
)
type SignUserInfo struct {
Name string `json:"name" binding:"required"` //用户名,如果加了binding则必须填写而且不能为空,不填会报错
Age int `json:"age" binding:"lt=30,gt=18"` //年龄,小于30大于18
Password string `json:"password" binding:"min=4,max=6"` //密码,字符串最小是4位,最大是6位
RePassword string `json:"re_password" binding:"eqfield=Password"` //密码确认,必须和Passord一致,不然会异常
Sex string `json:"sex" binding:"oneof=man woman"` //只能是man或者woman
Fyes string `json:"fyes" binding:"contains=f"` //字符串必须包含f
Fno string `json:"fno" binding:"excludes=f"` //字符串必须不包含f
Likelist []string `json:"likelist" binding:"required,dive,min=1,startswith=like"` //数组前缀必须是like才能通过校验
IP string `json:"ip" binding:"ip"` //必须是IP地址
URL string `json:"url" binding:"url"` //必须是url地址
URI string `json:"uri" binding:"uri"` //必须是uri地址,uri是url的子集,相当于/12/31/1,也可以是url,uri的范围比url要广
Date string `json:"date" binding:"datetime=2006-01-02 15:04:06"` //传时间内容,datetime=2006-01-02 15:04:06相当于格式,必须按照这个格式来传输
}
func main() {
r := gin.Default()
r.POST("/", func(c *gin.Context) {
var user SignUserInfo
//将前端传来的数据放入结构体,如果类型错误则报错
err := c.ShouldBindJSON(&user)
fmt.Println(user.Name)
if err != nil {
c.JSON(200, gin.H{"msg": err.Error()})
return
}
c.JSON(200, user)
})
r.Run(":9090")
}
// {
// "name":"\"西游记\"",
// "age":3,
// "password":"122332",
// "re_password":"122332",
// "sex":"man",
// "fyes":"manf",
// "fno":"aaa",
// "likelist":["likego"],
// "ip":"255.255.255.255",
// "url":"http://www.baidu.com/123",
// "uri":"/12/31/1",
// "date":"2022-12-07 01:10:11"
// }
自定义错误信息
import (
"fmt"
"reflect"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
)
type User struct {
Name string `json:"name" binding:"required" msg:"用户名校验失败"`
Age int `json:"age" binding:"required" msg:"请输入年龄"`
}
// 获取结构体中的msg参数
func GetValidMsg(err error, obj any) string {
//映射类型
getObj := reflect.TypeOf(obj).Elem()
//err其实是一个接口
//将err接口断言为具体类型validator.ValidationErrors是固定格式,如果是这个格式就走下面
if errs, ok := err.(validator.ValidationErrors); ok {
//断言成功
//errs其实是一个切片,报错会存在多个地方报错,所以肯定是一个数组或者切片
msg := ""
for _, e := range errs {
fmt.Println(e)
//循环每个错误信息
//根据报错字段获取结构体的具体字段,比如name字段错误,就返回请输入年龄,e是结构体里的值,e.Field()是报错的字段
if f, ok2 := getObj.FieldByName(e.Field()); ok2 {
//获取字段对应的json值
msg += f.Tag.Get("msg") + " "
}
}
return msg
}
return err.Error()
}
func main() {
r := gin.Default()
r.POST("/", func(c *gin.Context) {
var user User
//进行校验
err := c.ShouldBindJSON(&user)
//如果校验未通过
if err != nil {
c.JSON(200, gin.H{"msg": GetValidMsg(err, &user)})
return
}
c.JSON(200, gin.H{"data": user})
})
r.Run(":9090")
}
自定义验证信息
import (
"fmt"
"reflect"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)
type User struct {
Name string `json:"name" binding:"required,sign" msg:"用户名校验失败"`
Age int `json:"age" binding:"required" msg:"请输入年龄"`
}
// 获取结构体中的msg参数
func GetValidMsg(err error, obj interface{}) string {
//映射类型
getObj := reflect.TypeOf(obj).Elem()
//err其实是一个接口
//将err接口断言为具体类型validator.ValidationErrors是固定格式,如果是这个格式就走下面
if errs, ok := err.(validator.ValidationErrors); ok {
//断言成功
//errs其实是一个切片,报错会存在多个地方报错,所以肯定是一个数组或者切片
msg := ""
for _, e := range errs {
fmt.Println(e)
//循环每个错误信息
//根据报错字段获取结构体的具体字段,比如name字段错误,就返回请输入年龄,e是结构体里的值,e.Field()是报错的字段
if f, ok2 := getObj.FieldByName(e.Field()); ok2 {
//获取字段对应的json值
msg += f.Tag.Get("msg") + " "
}
}
return msg
}
return err.Error()
}
func signValid(fl validator.FieldLevel) bool {
//如果name字段包含以下内容则报错
for _, nameStr := range []string{"张三", "李四", "王五"} {
name := fl.Field().Interface().(string)
if name == nameStr {
return false
}
}
return true
}
func main() {
r := gin.Default()
//注册器
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("sign", signValid)
}
r.POST("/", func(c *gin.Context) {
var user User
//进行校验
err := c.ShouldBindJSON(&user)
//如果校验未通过
if err != nil {
c.JSON(200, gin.H{"msg": GetValidMsg(err, &user)})
return
}
c.JSON(200, gin.H{"data": user})
})
r.Run(":9090")
}