diff --git a/ch6-web/ch6-04-validator.md b/ch6-web/ch6-04-validator.md index 8734934..ec6f24d 100644 --- a/ch6-web/ch6-04-validator.md +++ b/ch6-web/ch6-04-validator.md @@ -122,3 +122,86 @@ fmt.Println(err) // Key: 'RegisterReq.PasswordRepeat' Error:Field validation for 如果觉得这个 validator 提供的错误信息不够人性化,例如要把错误信息返回给用户,那就不应该直接显示英文了。可以针对每种 tag 进行错误信息订制,读者可以自行探索。 ## 原理 + +从结构上来看,每一个 struct 都可以看成是一棵树。从字段校验这个角度来讲,无论我们采用深度优先搜索还是广度优先搜索来对这棵 struct 树来进行遍历,都是可以的。 + +我们来写一个递归的深度优先搜索方式的遍历 demo: + +```go +package main + +import ( + "fmt" + "reflect" + "regexp" + "strconv" + "strings" +) + +type Nested struct { + Email string `validate:"email"` +} +type T struct { + Age int `validate:"eq=10"` + Nested Nested +} + +func validateEmail(input string) bool { + if pass, _ := regexp.MatchString(`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`, input); pass { + return true + } + return false +} + +func validate(v interface{}) (bool, string) { + validateResult := true + errmsg := "success" + vt := reflect.TypeOf(v) + vv := reflect.ValueOf(v) + for i := 0; i < vv.NumField(); i++ { + fieldVal := vv.Field(i) + tagContent := vt.Field(i).Tag.Get("validate") + k := fieldVal.Kind() + + switch k { + case reflect.Int: + val := fieldVal.Int() + tagValStr := strings.Split(tagContent, "=") + tagVal, _ := strconv.ParseInt(tagValStr[1], 10, 64) + if val != tagVal { + errmsg = "validate int failed, tag is: "+ tagVal) + return false + } + case reflect.String: + val := fieldVal.String() + tagValStr := tagContent + switch tagValStr { + case "email": + nestedResult := validateEmail(val) + if nestedResult == false { + errmsg = "validate mail failed, field val is: "+ val + validateResult = false + } + } + case reflect.Struct: + valInter := fieldVal.Interface() + nestedResult := validate(valInter) + if nestedResult == false { + validateResult = false + } + } + } + return validateResult +} + +func main() { + var a = T{Age: 10, Nested: Nested{Email: "abc@abc.com"}} + + validateResult := validate(a) + fmt.Println(validateResult) +} + +``` + +这里我们简单地对 eq=x 和 email 这两个 tag 进行了支持,读者可以对这个程序进行简单的修改以查看具体的 validate 效果。 +