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
}
但是结构体比较特殊,是单独写的验证函数,有兴趣可以自己去看看