【问题标题】:How can I validate a struct datatype with a custom validator?如何使用自定义验证器验证结构数据类型?
【发布时间】:2021-07-20 06:09:29
【问题描述】:

我正在使用go-playground/validator/v10 来验证一些输入,并且在使用自定义验证标签和函数时遇到了一些问题。问题是当结构字段之一是不同的结构时,不会调用该函数。这是一个例子:

type ChildStruct struct {
    Value int
}

type ParentStruct struct {
    Child ChildStruct `validate:"myValidate"`
}

func myValidate(fl validator.FieldLevel) bool {
    fmt.Println("INSIDE MY VALIDATOR") // <- This is never printed
    return false
}

func main() {
    validator := validator.New()
    validator.RegisterValidation("myValidate", myValidate)
    data := &ParentStruct{
        Child: ChildStruct{
            Value: 10,
        },
    }
    validateErr := validator.Struct(data)
    if validateErr != nil { // <- This is always nil since MyValidate is never called
        fmt.Println("GOT ERROR")
        fmt.Println(validateErr)
    }
    fmt.Println("DONE")
}

如果我将 parentStruct 更改为:

type ParentStruct struct {
    Child int `validate:"myValidate"`
}

一切正常。 如果我将validate:"myValidate" 部分添加到 ChildStruct 它也可以工作,但是,返回的错误是说 ChildStruct.Value 是错误的,而它应该说 ParentStruct.Child 是错误的。

有人知道我做错了什么吗?

【问题讨论】:

    标签: go go-playground


    【解决方案1】:

    搜索了一段时间后,我终于找到了一个名为RegisterCustomTypeFunc 的函数,它注册了一个自定义类型,这使得go-playground/validator/v10 可以对其进行验证。所以解决方法是在问题中的示例中添加以下内容:

    func childStructCustomTypeFunc(field reflect.Value) interface{} {   
        if value, ok := field.Interface().(ChildStruct); ok {
            return value.Value
        }
        return nil
    }
    

    与:

    validator.RegisterCustomTypeFunc(childStructCustomTypeFunc, ChildStruct{})
    

    现在验证器将进入myValidate 函数,返回消息将是ParentStruct.Child 字段的错误

    【讨论】:

      【解决方案2】:

      函数validator.RegisterValidation(...) 正在注册一个字段 级别的自定义验证器,正如注册函数的类型所暗示的func(fl validator.FieldLevel) bool

      结构字段本身不会以这种方式验证,并且您的自定义验证器会被忽略。

      要验证结构字段,您应该使用validate.RegisterStructValidation(myValidate, ChildStruct{}),其中函数myValidate 的类型为validator.StructLevelFunc

      在此函数中,您可以对结构体进行验证,可以是字段本身和/或其嵌套字段:

      func myValidate(sl validator.StructLevel) {
          fmt.Println("INSIDE MY VALIDATOR") // now called
          if sl.Current().Interface().(ChildStruct).Value != 20 {
              sl.ReportError(sl.Current().Interface(), "ChildStruct", "", "", "")
          }
      }
      
      func main() {
          vald := validator.New()
          vald.RegisterStructValidation(myValidate, ChildStruct{})
          data := &ParentStruct{
              Child: ChildStruct{
                  Value: 10,
              },
          }
          validateErr := vald.Struct(data)
          if validateErr != nil {         
              fmt.Println("GOT ERROR")
              fmt.Println(validateErr)
          }
          fmt.Println("DONE")
      }
      

      操场上的例子:https://play.golang.org/p/f0f2YE_e1VL

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-08
        • 2016-05-07
        • 2011-12-19
        相关资源
        最近更新 更多