Golang验证器多字段依赖 [英] Golang validator multifield dependency

查看:151
本文介绍了Golang验证器多字段依赖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想验证以下结构:


  type CarModel struct {
gorm.Model
OwnerID int`json:owneridvalidate:nonzero`
类型字符串`json:typevalidate:regexp =(?)(A | B)
字符串`json:url验证:isurl`
B字符串`json:ip验证:isip`
}


我想根据类型验证A和B,
如果type = A,则A必须存在并且必须是URL但B必须不存在
如果type = B那么A不能存在并且B必须是IP

这是可能的验证器?



我尝试了自定义验证,但找不到类型值的方法:

  func checkB(v interface {},param string)error {
theB:= reflect.ValueOf(v)
如果B.Kind()!= reflect.String {
return validator.ErrUnsupported
}
//检查B是否为IP
ipcool:= net.ParseIP(theB.String())
if ipcool == nil {
return errors.New(B:ip incorrecte+ theB.String())
}
return nil
}






在Alex Nichol的回答中,我想首先感谢您的帮助。



如果我理解正确,我必须遍历所有的验证字段,以保持类型,A和B的值的跟踪,然后检查它们取决于类型...

我做到了这一点:
$ b

  func checkMonitor(v interface {})错误{
var mytype字符串
var myA字符串
var myB string

val:= reflect.ValueOf(v)
//遍历字段
for i:= 0;我< val.NumField(); i ++ {
//查找validate标签
field:= val.Type()。Field(i)
tags:= field.Tag
_,ok:= tags。查找(验证)
if!ok {
//无验证标记。
continue
}

//获取字段的值。
fieldValue:= val.Field(i)

switch field.Name {$ b $ caseType:
mytype = fieldValue.Interface()
A:
myA = fieldValue.Interface()
caseB:
myB = fieldValue.Interface()
}
//验证逻辑在这里。
//fmt.Println(\"field,field.Name,has validate tag,validate,value,fieldValue.Interface())
}
if mytype == A{
if myA =={
return errors.New(A et et type A)
}
ipcool:= net.ParseIP(myA)
if ipcool == nil {
return errors.New(A incorrecte+ myA)
}
} else if mytype ==HTML{
if myB =={
return errors.New(B vide et type B)
}
_,urlpascool:= url.ParseRequestURI(myB)
if urlpascool! = nil {
return errors.New(B incorrecte+ myB)
}
}
return nil
}

但是在mytype,myA和myB上出现错误:

无法使用fieldValue.Interface()(type interface {})作为类型字符串赋值:需要类型断言



编辑:
只需要使用我的大脑:

  switch field.Name {
caseType:
mytype = fieldValue .String()
caseA:
myA = fieldValue.String()
caseB:
myB = fieldValue.Interface()
}


解决方案

您可能希望使用反射遍历该结构,为每个字段获取 validate 标记,并检查该字段。这意味着您必须在结构级别进行验证。否则,如果您将 myInstance.OwnerID 等内容传递给函数,您将失去与之关联的标记。



这段代码循环遍历一个结构体的字段,并为每个标签获取 validate 标记:

  func checkStruct(v interface {})错误{
val:= reflect.ValueOf(v)

//遍历字段
for i:= 0;我< val.NumField(); i ++ {
//查找validate标签
field:= val.Type()。Field(i)
tags:= field.Tag
validate,ok:= tags。查找(验证)
if!ok {
//无验证标记。
continue
}

//获取字段的值。
fieldValue:= val.Field(i)

//验证逻辑在这里。
fmt.Println(field,field.Name,has validate tag,validate,value,
fieldValue.Interface())
}
return nil

$ / code>

例如,我们可以将它传递给下面的 CarModel

  checkStruct(CarModel {
OwnerID:2,
类型: B,
A:http://google.com,
B:192.168.1.1,
})

,它会打印出下列内容:

 字段OwnerID验证标记非零且值为2 
字段类型具有验证标记regexp =(?)(A | B)和值B
字段A具有验证标记isurl并且值http://google.com
字段B具有验证标签isip并且值为192.168.1.1


I'd like to validate the following structure :

type CarModel struct {
  gorm.Model
  OwnerID    int    `json:"ownerid" validate:"nonzero"`
  Type       string `json:"type" validate:"regexp=(?)(A|B)"`
  A        string `json:"url" validate:"isurl"`
  B         string `json:"ip" validate:"isip"`
}

I would like to validate A and B depending on Type, if type = A then A must exist and must be a URL BUT B must not exist if type = B then A must not exist and B must be an IP

is this possible with validator ?

I did try custom validation but I cannot find a way to see type value :

func checkB(v interface{}, param string) error {
    theB := reflect.ValueOf(v)
    if theB.Kind() != reflect.String {
        return validator.ErrUnsupported
    }
    //check if B is an IP
    ipcool := net.ParseIP(theB.String())
    if ipcool == nil {
        return errors.New("B : ip incorrecte " + theB.String())
    }
    return nil
}


Upon the answer of Alex Nichol, I would like first to thank you for your help.

If I understood correctly, I would have to iterate through all the "validate" fields, to keep a trace of the value of TYPE, A and B and then to check them depending on TYPE ...

I did this :

func checkMonitor(v interface{}) error {
    var mytype string
    var myA string
    var myB string

    val := reflect.ValueOf(v)
    // Iterate through fields
    for i := 0; i < val.NumField(); i++ {
        // Lookup the validate tag
        field := val.Type().Field(i)
        tags := field.Tag
        _, ok := tags.Lookup("validate")
        if !ok {
            // No validate tag.
            continue
        }

        // Get the value of the field.
        fieldValue := val.Field(i)

        switch field.Name {
        case "Type":
            mytype = fieldValue.Interface()
        case "A":
            myA = fieldValue.Interface()
        case "B":
            myB = fieldValue.Interface()
        }
        // Validation logic here.
        //fmt.Println("field", field.Name, "has validate tag", validate, "and value", fieldValue.Interface())
    }
    if mytype == "A" {
        if myA == "" {
            return errors.New("A vide et type A")
        }
        ipcool := net.ParseIP(myA)
        if ipcool == nil {
            return errors.New("A incorrecte " + myA)
        }
    } else if mytype == "HTML" {
        if myB == "" {
            return errors.New("B vide et type B")
        }
        _, urlpascool := url.ParseRequestURI(myB)
        if urlpascool != nil {
            return errors.New("B incorrecte " + myB)
        }
    }
    return nil
}

but got an error on the mytype, myA and myB in the switch case :

cannot use fieldValue.Interface() (type interface {}) as type string in assignment: need type assertion

EDIT : just needed to use my brain :

switch field.Name {
case "Type":
   mytype = fieldValue.String()
case "A":
   myA = fieldValue.String()
case "B":
   myB = fieldValue.Interface()
}

解决方案

You probably want to use reflection to iterate over the fields of the struct, get the validate tag for each field, and check the field. This means you'll have to do validation on a struct level. Otherwise, if you pass something like myInstance.OwnerID to a function, you'll lose the tag associated with it.

This code loops through the fields of a struct and gets the validate tag for each:

func checkStruct(v interface{}) error {
    val := reflect.ValueOf(v)

    // Iterate through fields
    for i := 0; i < val.NumField(); i++ {
        // Lookup the validate tag
        field := val.Type().Field(i)
        tags := field.Tag
        validate, ok := tags.Lookup("validate")
        if !ok {
            // No validate tag.
            continue
        }

        // Get the value of the field.
        fieldValue := val.Field(i)

        // Validation logic here.
        fmt.Println("field", field.Name, "has validate tag", validate, "and value",
            fieldValue.Interface())
    }
    return nil
}

For example, we could pass it the following CarModel:

checkStruct(CarModel{
    OwnerID: 2,
    Type:    "B",
    A:       "http://google.com",
    B:       "192.168.1.1",
})

and it would print out the following:

field OwnerID has validate tag nonzero and value 2
field Type has validate tag regexp=(?)(A|B) and value B
field A has validate tag isurl and value http://google.com
field B has validate tag isip and value 192.168.1.1

这篇关于Golang验证器多字段依赖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆