beego/validation

2020-03-09  本文已影响0人  GGBond_8488

相信接触过后端开发的都使用过表单设计工具,这里就分析一下beego表单验证工具validation是如何工作的

    import (
        "github.com/astaxie/beego/validation"
        "log"
    )

    type User struct {
        Name string
        Age int
    }

    func main() {
        u := User{"man", 40}
        valid := validation.Validation{}
        valid.Required(u.Name, "name")
        valid.MaxSize(u.Name, 15, "nameMax")
        valid.Range(u.Age, 0, 140, "age")
        if valid.HasErrors() {
            // validation does not pass
            // print invalid message
            for _, err := range valid.Errors {
                log.Println(err.Key, err.Message)
            }
        }
        // or use like this
        if v := valid.Max(u.Age, 140, "ageMax"); !v.Ok {
            log.Println(v.Error.Key, v.Error.Message)
        }
    }

more info: http://beego.me/docs/mvc/controller/validation.md

这是官方给的一段示例代码
可以看到 首先这里初始化了一个valid结构体
并调用了其下的相应的方法,这里就以最简单的Required为例讲一讲valid是如何验证数据的

// Required Test that the argument is non-nil and non-empty (if string or list)
func (v *Validation) Required(obj interface{}, key string) *Result {
    return v.apply(Required{key}, obj)
}

这是源码里的valid方法,可以看到它属于Validation对象,并且调用了validation的apply方法.

type Validation struct {
    // if this field set true, in struct tag valid
    // if the struct field vale is empty
    // it will skip those valid functions, see CanSkipFuncs
    RequiredFirst bool

    Errors    []*Error
    ErrorsMap map[string][]*Error
}
//接口
// Validator interface
type Validator interface {
    IsSatisfied(interface{}) bool
    DefaultMessage() string
    GetKey() string
    GetLimitValue() interface{}
}
//结构体对象
// Required struct
type Required struct {
    Key string
}
//这里传入了一个 Validator的对象,但上文调用的时传入的时Required对象,
//说明有一个一定是接口,并且另一个实现了这个接口,我把他们放在上面
func (v *Validation) apply(chk Validator, obj interface{}) *Result {
    if nil == obj {
        if chk.IsSatisfied(obj) {
            return &Result{Ok: true}
        }
    } else if reflect.TypeOf(obj).Kind() == reflect.Ptr {
        if reflect.ValueOf(obj).IsNil() {
            if chk.IsSatisfied(nil) {
                return &Result{Ok: true}
            }
        } else {
            if chk.IsSatisfied(reflect.ValueOf(obj).Elem().Interface()) {
                return &Result{Ok: true}
            }
        }
    } else if chk.IsSatisfied(obj) {
        return &Result{Ok: true}
    }
//下面是返回错误信息的了
//可以看到主要的工作方法是Validator下的IsSatisfied方法
--------------------------------------------------------------------------------------
/*
·········
*/
    // Also return it in the result.
    return &Result{
        Ok:    false,
        Error: err,
    }
}
func (r Required) IsSatisfied(obj interface{}) bool {
    if obj == nil {
        return false
    }

    if str, ok := obj.(string); ok {
        return len(strings.TrimSpace(str)) > 0
    }
    if _, ok := obj.(bool); ok {
        return true
    }
    if i, ok := obj.(int); ok {
        return i != 0
    }
    if i, ok := obj.(uint); ok {
        return i != 0
    }
    if i, ok := obj.(int8); ok {
        return i != 0
    }
    if i, ok := obj.(uint8); ok {
        return i != 0
        /*
         ······省略
        */
    v := reflect.ValueOf(obj)
    if v.Kind() == reflect.Slice {
        return v.Len() > 0
    }
    return true
}

可以看到这里先使用类型断言判断传入的空接口类型,再判断其值是否设置了。
其他诸如

// Min Test that the obj is greater than min if obj's type is int
func (v *Validation) Min(obj interface{}, min int, key string) *Result {
    return v.apply(Min{min, key}, obj)
}

// Max Test that the obj is less than max if obj's type is int
func (v *Validation) Max(obj interface{}, max int, key string) *Result {
    return v.apply(Max{max, key}, obj)
}

// Range Test that the obj is between mni and max if obj's type is int
func (v *Validation) Range(obj interface{}, min, max int, key string) *Result {
    return v.apply(Range{Min{Min: min}, Max{Max: max}, key}, obj)
}

Min,Max,Rang等也是如此
而类似IP,Email,Phone则是使用相应的正则匹配但是执行流程也是这样。

func (m Min) IsSatisfied(obj interface{}) bool {
    var v int
    switch obj.(type) {
    case int64:
        if wordsize == 32 {
            return false
        }
        v = int(obj.(int64))
    case int:
        v = obj.(int)
    case int32:
        v = int(obj.(int32))
    case int16:
        v = int(obj.(int16))
    case int8:
        v = int(obj.(int8))
    default:
        return false
    }

    return v >= m.Min
}

但是结构体比较特殊,是单独写的验证函数,有兴趣可以自己去看看

上一篇下一篇

猜你喜欢

热点阅读