数据校验-递归校验

校验组件支持强大的递归校验(嵌套校验)特性。如果给定的校验数据中的属性或者键值为struct/map/slice类型时,将会被自动执行递归校验。我们来看几个示例:

示例1,递归校验:struct

package main

import (
    "fmt"

    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/os/gctx"
)

type SearchReq struct {
    Key    string `v:"required"`
    Option SearchOption
}

type SearchOption struct {
    Page int `v:"min:1"`
    Size int `v:"max:100"`
}

func main() {
    var (
        ctx = gctx.New()
        req = SearchReq{
            Key: "GoFrame",
            Option: SearchOption{
                Page: 1,
                Size: 10000,
            },
        }
    )
    err := g.Validator().Data(req).Run(ctx)
    fmt.Println(err)
}

执行后,终端输出:

The Size value `10000` must be equal or lesser than 100

示例2,递归校验:slice

package main

import (
    "fmt"

    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/os/gctx"
)

func main() {
    type Student struct {
        Name string `v:"required#Student Name is required"`
        Age  int
    }
    type Teacher struct {
        Name     string
        Students []Student
    }
    var (
        ctx     = gctx.New()
        teacher = Teacher{}
        data    = g.Map{
            "name":     "john",
            "students": `[{"age":2},{"name":"jack", "age":4}]`,
        }
    )
    err := g.Validator().Assoc(data).Data(teacher).Run(ctx)
    fmt.Println(err)
}

执行后,终端输出:

Student Name is required

示例3,递归校验:map

package main

import (
    "fmt"

    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/os/gctx"
)

func main() {
    type Student struct {
        Name string `v:"required#Student Name is required"`
        Age  int
    }
    type Teacher struct {
        Name     string
        Students map[string]Student
    }
    var (
        ctx     = gctx.New()
        teacher = Teacher{
            Name: "Smith",
            Students: map[string]Student{
                "john": {Name: "", Age: 18},
            },
        }
    )
    err := g.Validator().Data(teacher).Run(ctx)
    fmt.Println(err)
}

执行后,终端输出:

Student Name is required

注意事项:空对象对递归校验的影响

package main

import (
    "fmt"

    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/os/gctx"
)

func main() {
    type Student struct {
        Name string `v:"required"`
    }
    type Teacher struct {
        Students Student
    }
    var (
        ctx     = gctx.New()
        teacher = Teacher{}
        data    = g.Map{
            "students": nil,
        }
    )
    err := g.Validator().Assoc(data).Data(teacher).Run(ctx)
    fmt.Println(err)
}

执行后,终端输出:

Student Name is required

有同学可能会觉得奇怪,明明我都没有传递Student字段值,为什么还会递归校验Student结构体里面的Name字段?这是因为这里的 Student 属性是个空结构体,是带有默认值的(Name默认值为空字符串)。递归校验里面,虽然 Student 不是必须参数,这个意思是你可以不传递,但是只要传递了就会按照里面属性的校验规则执行校验(带有默认值的空对象也算是有值)。可以对比和以下代码的差别:

package main

import (
    "fmt"

    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/os/gctx"
)

func main() {
    type Student struct {
        Name string `v:"required"`
    }
    type Teacher struct {
        Students *Student
    }
    var (
        ctx     = gctx.New()
        teacher = Teacher{}
        data    = g.Map{
            "students": nil,
        }
    )
    err := g.Validator().Assoc(data).Data(teacher).Run(ctx)
    fmt.Println(err)
}

和前一示例的唯一差异在于Student属性从结构体改为了结构体指针*Student,这样该属性不是空对象便没有默认值了。执行后,终端输出位空,表示校验通过。