美文网首页
beego/validation

beego/validation

作者: GGBond_8488 | 来源:发表于2020-03-09 20:17 被阅读0次

    相信接触过后端开发的都使用过表单设计工具,这里就分析一下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
    }
    

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

    相关文章

      网友评论

          本文标题:beego/validation

          本文链接:https://www.haomeiwen.com/subject/vxdmdhtx.html