多数据校验 - CheckStruct

CheckStruct的使用方式同CheckMap,除了第一个参数为struct类型的结构体对象(也可以是对象指针)。

注意哟,大家常问的问题。struct的属性会有默认值,在某些情况下会引起required规则的失效,因此根据实际情况配合多种规则(例如min规则)一起校验会是一个比较严谨的做法。此外,也可以将属性改为指针类型,例如*int*float64等。

接口文档: https://godoc.org/github.com/gogf/gf/util/gvalid

  1. func CheckStruct(object interface{}, rules interface{}, msgs ...CustomMsg) *Error

示例1,使用map指定规则及提示信息

  1. package main
  2. import (
  3. "github.com/gogf/gf/frame/g"
  4. "github.com/gogf/gf/util/gvalid"
  5. )
  6. func main() {
  7. type Object struct {
  8. Name string
  9. Age int
  10. }
  11. rules := map[string]string {
  12. "Name" : "required|length:6,16",
  13. "Age" : "between:18,30",
  14. }
  15. msgs := map[string]interface{} {
  16. "Name" : map[string]string {
  17. "required" : "名称不能为空",
  18. "length" : "名称长度为:min到:max个字符",
  19. },
  20. "Age" : "年龄为18到30周岁",
  21. }
  22. obj := Object{Name : "john"}
  23. // 也可以是指针
  24. // obj := &Object{Name : "john"}
  25. if e := gvalid.CheckStruct(obj, rules,msgs); e != nil {
  26. g.Dump(e.Maps())
  27. }
  28. }
  29. /*
  30. 输出:
  31. {
  32. "Age": {
  33. "between": "年龄为18到30周岁"
  34. },
  35. "Name": {
  36. "length": "名称长度为6到16个字符"
  37. }
  38. }
  39. */

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

示例2,使用gvalid tag绑定规则及错误信息

使用gvalid tag设置的规则,其校验结果是顺序性的。

  1. package main
  2. import (
  3. "github.com/gogf/gf/frame/g"
  4. "github.com/gogf/gf/util/gvalid"
  5. )
  6. type User struct {
  7. Uid int `v:"uid @integer|min:1"`
  8. Name string `v:"name @required|length:6,30#请输入用户名称|用户名称长度非法"`
  9. Pass1 string `v:"password1@required|password3"`
  10. Pass2 string `v:"password2@required|password3|same:password1#||两次密码不一致,请重新输入"`
  11. }
  12. func main() {
  13. user := &User{
  14. Name : "john",
  15. Pass1: "Abc123!@#",
  16. Pass2: "123",
  17. }
  18. // 使用结构体定义的校验规则和错误提示进行校验
  19. if e := gvalid.CheckStruct(user, nil); e != nil {
  20. g.Dump(e.Maps())
  21. }
  22. // 自定义校验规则和错误提示,对定义的特定校验规则和错误提示进行覆盖
  23. rules := map[string]string {
  24. "uid" : "min:6",
  25. }
  26. msgs := map[string]interface{} {
  27. "password2" : map[string]string {
  28. "password3" : "名称不能为空",
  29. },
  30. }
  31. if e := gvalid.CheckStruct(user, rules, msgs); e != nil {
  32. g.Dump(e.Maps())
  33. }
  34. }

可以看到,我们可以对在struct定义时使用了gvalid的标签属性(gvalid tag)来绑定校验的规则及错误提示信息,规则如下:

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

可以看到,CheckStructCheckMapgvalid tag规则是一样的,不过在字段的含义上有一点点小区别:

  • 属性别名错误提示非必需字段校验规则必需字段
  • 属性别名 非必需字段,指定在校验中使用的对应struct属性的别名,同时校验成功后的map中的也将使用该别名返回,例如在处理请求表单时比较有用,因为表单的字段名称往往和struct的属性名称不一致;
  • 错误提示 非必需字段,表示自定义的错误提示信息,当规则校验时对默认的错误提示信息进行覆盖;

在此示例代码中,same:password1规则同使用same:Pass2规则是一样的效果。也就是说,在数据校验中,可以同时使用原有的struct属性名称,也可以使用别名。但是,返回的结果中只会使用别名返回,这也是别名最大的用途。

此外,在使用CheckStruct方法对struct对象进行校验时,也可以传递校验或者和错误提示参数,这个时候会覆盖struct在定义时绑定的对应参数。

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

  1. {
  2. "name": {
  3. "length": "用户名称长度非法"
  4. },
  5. "password2": {
  6. "password3": "密码格式不合法,密码格式为任意6-18位的可见字符,必须包含大小写字母、数字和特殊字符",
  7. "same": "两次密码不一致,请重新输入"
  8. },
  9. "uid": {
  10. "min": "字段最小值为1"
  11. }
  12. }
  13. {
  14. "name": {
  15. "length": "用户名称长度非法"
  16. },
  17. "password2": {
  18. "password3": "名称不能为空",
  19. "same": "字段值不合法"
  20. },
  21. "uid": {
  22. "min": "字段最小值为6"
  23. }
  24. }

示例3,属性递归校验

gvalid.CheckStruct支持递归校验,即如果属性也是结构体,并且结构体的属性带有gvalid标签,无论多深的递归层级,这些属性都将被根据设定的规则进行校验。

使用示例:

  1. package main
  2. import (
  3. "github.com/gogf/gf/frame/g"
  4. "github.com/gogf/gf/util/gvalid"
  5. )
  6. func main() {
  7. type Pass struct {
  8. Pass1 string `valid:"password1@required|same:password2#请输入您的密码|您两次输入的密码不一致"`
  9. Pass2 string `valid:"password2@required|same:password1#请再次输入您的密码|您两次输入的密码不一致"`
  10. }
  11. type User struct {
  12. Id int
  13. Name string `valid:"name@required#请输入您的姓名"`
  14. Pass Pass
  15. }
  16. user := &User{
  17. Name: "john",
  18. Pass: Pass{
  19. Pass1: "1",
  20. Pass2: "2",
  21. },
  22. }
  23. err := gvalid.CheckStruct(user, nil)
  24. g.Dump(err.Maps())
  25. }

执行后,终端输出:

  1. {
  2. "password1": {
  3. "same": "您两次输入的密码不一致"
  4. },
  5. "password2": {
  6. "same": "您两次输入的密码不一致"
  7. }
  8. }

可选校验规则

当给定的数据校验规则中不包含required*规则时,表示该规则不是一个必须规则,当属性值为nil或者空字符串时,将会忽略其校验。

示例1,空字符串

  1. type Params struct {
  2. Page int `v:"required|min:1 # page is required"`
  3. Size int `v:"required|between:1,100 # size is required"`
  4. ProjectId string `v:"between:1,10000 # project id must between :min, :max"`
  5. }
  6. obj := &Params{
  7. Page: 1,
  8. Size: 10,
  9. }
  10. err := gvalid.CheckStruct(obj, nil)
  11. fmt.Println(err)
  12. // Output:
  13. // <nil>

示例2,空指针属性

  1. type Params struct {
  2. Page int `v:"required|min:1 # page is required"`
  3. Size int `v:"required|between:1,100 # size is required"`
  4. ProjectId *gvar.Var `v:"between:1,10000 # project id must between :min, :max"`
  5. }
  6. obj := &Params{
  7. Page: 1,
  8. Size: 10,
  9. }
  10. err := gvalid.CheckStruct(obj, nil)
  11. fmt.Println(err)
  12. // Output:
  13. // <nil>

示例3,空整型属性

需要注意的是,如果键值为0或者false,将仍然会被校验。

  1. type Params struct {
  2. Page int `v:"required|min:1 # page is required"`
  3. Size int `v:"required|between:1,100 # size is required"`
  4. ProjectId int `v:"between:1,10000 # project id must between :min, :max"`
  5. }
  6. obj := &Params{
  7. Page: 1,
  8. Size: 10,
  9. }
  10. err := gvalid.CheckStruct(obj, nil)
  11. fmt.Println(err)
  12. // Output:
  13. // project id must between 1, 10000