Struct校验常使用以下链式操作方式:

g.Validator().Data(object).Run(ctx)

校验tag规则介绍

在开始介绍Struct参数类型校验之前,我们来介绍一下常用的校验tag规则。规则如下:

[属性别名@]校验规则[#错误提示]

其中:

  • 属性别名错误提示非必需字段校验规则必需字段。
  • 属性别名 非必需字段,指定在校验中使用的对应struct属性的别名,同时校验后返回的error对象中的也将使用该别名返回。例如在处理请求表单时比较有用,因为表单的字段名称往往和struct的属性名称不一致。大部分场景下不需要设置属性别名,默认直接使用属性名称即可。
  • 校验规则则为当前属性的校验规则,多个校验规则请使用|符号组合,例如:required|between:1,100
  • 错误提示 非必需字段,表示自定义的错误提示信息,当规则校验时对默认的错误提示信息进行覆盖。

校验tag使用示例

package main

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

type User struct {
	Uid   int    `v:"uid      @integer|min:1#|请输入用户ID"`
	Name  string `v:"name     @required|length:6,30#请输入用户名称|用户名称长度非法"`
	Pass1 string `v:"password1@required|password3"`
	Pass2 string `v:"password2@required|password3|same:Pass1#|密码格式不合法|两次密码不一致,请重新输入"`
}

func main() {
	var (
		ctx  = gctx.New()
		user = &User{
			Name:  "john",
			Pass1: "Abc123!@#",
			Pass2: "123",
		}
	)  

	err := g.Validator().Data(user).Run(ctx)  
	if err != nil {
		g.Dump(err.Items())
	}
}

可以看到,我们可以对在struct定义时使用了gvalidgvalid tag来绑定校验的规则及错误提示信息。在此示例代码中,same:password1规则同使用same:Pass1规则是一样的效果。也就是说,在数据校验中,可以同时使用原有的struct属性名称,也可以使用别名。但是,返回的结果中只会使用别名返回,这也是别名最大的用途。此外,在对struct对象进行校验时,也可以传递校验或者和错误提示参数,这个时候会覆盖struct在定义时绑定的对应参数。

以上示例执行后,输出结果为:

[
    {
        "uid": {
            "min": "请输入用户ID",
        },
    },
    {
        "name": {
            "length": "用户名称长度非法",
        },
    },
    {
        "password2": {
            "password3": "密码格式不合法",
        },
    },
]

使用map指定校验规则

package main

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

func main() {
	type User struct {
		Age  int
		Name string
	}
	var (
		ctx   = gctx.New()
		user  = User{Name: "john"}
		rules = map[string]string{
			"Name": "required|length:6,16",
			"Age":  "between:18,30",
		}
		messages = map[string]interface{}{
			"Name": map[string]string{
				"required": "名称不能为空",
				"length":   "名称长度为{min}到{max}个字符",
			},
			"Age": "年龄为18到30周岁",
		}
	)  

	err := g.Validator().Rules(rules).Messages(messages).Data(user).Run(ctx)
	if err != nil {
		g.Dump(err.Maps())
	}
}

在以上示例中,Age属性由于默认值0的存在,因此会引起required规则的失效,因此这里没有使用required规则而是使用between规则来进行校验。示例代码执行后,终端输出:

{
	"Age": {
		"between": "年龄为18到30周岁"
	},
	"Name": {
		"length": "名称长度为6到16个字符"
	}
}

结构体递归校验(嵌套校验)

支持递归的结构体校验(嵌套校验),即如果属性也是结构体(也支持嵌套结构体(embedded)),那么将会自动将该属性执行递归校验。使用示例:

package main

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

func main() {
	type Pass struct {
		Pass1 string `v:"password1@required|same:password2#请输入您的密码|您两次输入的密码不一致"`
		Pass2 string `v:"password2@required|same:password1#请再次输入您的密码|您两次输入的密码不一致"`
	}
	type User struct {
		Pass
		Id   int
		Name string `valid:"name@required#请输入您的姓名"`
	}
	var (
		ctx  = gctx.New()
		user = &User{
			Name: "john",
			Pass: Pass{
				Pass1: "1",
				Pass2: "2",
			},
		}
	)
	err := g.Validator().Data(user).Run(ctx)  
	g.Dump(err.Maps())
}

或者属性为嵌套结构体(embedded)的场景:

package main

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

func main() {
	type Pass struct {
		Pass1 string `v:"password1@required|same:password2#请输入您的密码|您两次输入的密码不一致"`
		Pass2 string `v:"password2@required|same:password1#请再次输入您的密码|您两次输入的密码不一致"`
	}
	type User struct {
		Id   int
		Name string `valid:"name@required#请输入您的姓名"`
		Pass Pass
	}
	var (
		ctx  = gctx.New()
		user = &User{
			Name: "john",
			Pass: Pass{
				Pass1: "1",
				Pass2: "2",
			},
		}
	)
	err := g.Validator().Data(user).Run(ctx)
	g.Dump(err.Maps())
}

执行后,终端输出:

{
    "password1": {
        "same": "您两次输入的密码不一致",
    },
    "password2": {
        "same": "您两次输入的密码不一致",
    },
}

更多递归校验的介绍,请参考章节:数据校验-递归校验

Content Menu

  • No labels

7 Comments

  1. 多个验证规则,如何只定义一个错误提示?让定义的规则都提示这一个错误信息,不需要每个规则都定义错误提示信息。

    1. 写个后置中间判断error是否是validate的 然后改写返回的message

  2. 结构体校验为什么返回的是title字段不能为空,而不是标题不能为空

    type MenuMeta struct {
    Title string `json:"title" v:"required" dc:"标题"`
    FrameSrc string `json:"frameSrc" dc:"内嵌地址"`
    Icon int `json:"icon" v:"required" dc:"图标"`
    Hidden bool `json:"showLink" dc:"是否隐藏"`
    ShowParent bool `json:"showParent" dc:"是否显示父级菜单"`
    KeepAlive bool `json:"keepAlive" dc:"路由组件缓存"`
    FrameLoading bool `json:"frameLoading" dc:"内嵌加载动画"`
    }

    1. 写上对应规则的失败消息

      1. 不能设置一个字段的label,后续验证是label+错误提示吗? 如果每个添加中文注释,这不是显得tag的内容很长了吗

        1. 你可以查看下源码找下有没有对应的set方法

          1. 没有找到类似的,但还是谢谢你的回答吧