github.com/zhongdalu/gf@v1.0.0/g/util/gvalid/gvalid_check_struct.go (about) 1 // Copyright 2017-2018 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 7 package gvalid 8 9 import ( 10 "strings" 11 12 "github.com/zhongdalu/gf/g/internal/structs" 13 "github.com/zhongdalu/gf/g/util/gconv" 14 ) 15 16 var ( 17 // 同时支持gvalid、valid和v标签,优先使用gvalid 18 structTagPriority = []string{"gvalid", "valid", "v"} 19 ) 20 21 // 校验struct对象属性,object参数也可以是一个指向对象的指针,返回值同CheckMap方法。 22 // struct的数据校验结果信息是顺序的。 23 func CheckStruct(object interface{}, rules interface{}, msgs ...CustomMsg) *Error { 24 // 字段别名记录,用于msgs覆盖struct tag的 25 fieldAliases := make(map[string]string) 26 params := make(map[string]interface{}) 27 checkRules := make(map[string]string) 28 customMsgs := make(CustomMsg) 29 // 返回的顺序规则 30 errorRules := make([]string, 0) 31 // 返回的校验错误 32 errorMaps := make(ErrorMap) 33 // 解析rules参数 34 switch v := rules.(type) { 35 // 支持校验错误顺序: []sequence tag 36 case []string: 37 for _, tag := range v { 38 name, rule, msg := parseSequenceTag(tag) 39 if len(name) == 0 { 40 continue 41 } 42 // 错误提示 43 if len(msg) > 0 { 44 ruleArray := strings.Split(rule, "|") 45 msgArray := strings.Split(msg, "|") 46 for k, v := range ruleArray { 47 // 如果msg条数比rule少,那么多余的rule使用默认的错误信息 48 if len(msgArray) <= k { 49 continue 50 } 51 if len(msgArray[k]) == 0 { 52 continue 53 } 54 array := strings.Split(v, ":") 55 if _, ok := customMsgs[name]; !ok { 56 customMsgs[name] = make(map[string]string) 57 } 58 customMsgs[name].(map[string]string)[strings.TrimSpace(array[0])] = strings.TrimSpace(msgArray[k]) 59 } 60 } 61 checkRules[name] = rule 62 errorRules = append(errorRules, name+"@"+rule) 63 } 64 65 // 不支持校验错误顺序: map[键名]校验规则 66 case map[string]string: 67 checkRules = v 68 } 69 // 首先, 按照属性循环一遍将struct的属性、数值、tag解析 70 for nameOrTag, field := range structs.MapField(object, structTagPriority, true) { 71 fieldName := field.Name() 72 params[fieldName] = field.Value() 73 // MapField返回map[name/tag]*Field,当nameOrTag != fieldName时,nameOrTag为tag 74 if nameOrTag != fieldName { 75 // sequence tag == struct tag, 这里的name为别名 76 name, rule, msg := parseSequenceTag(nameOrTag) 77 if len(name) == 0 { 78 name = fieldName 79 } else { 80 fieldAliases[fieldName] = name 81 } 82 // params参数使用别名**扩容**(而不仅仅使用别名),仅用于验证使用 83 if _, ok := params[name]; !ok { 84 params[name] = field.Value() 85 } 86 // 校验规则 87 if _, ok := checkRules[name]; !ok { 88 if _, ok := checkRules[fieldName]; ok { 89 // tag中存在别名,且rules传入的参数中使用了属性命名时,进行规则替换,并删除该属性的规则 90 checkRules[name] = checkRules[fieldName] 91 delete(checkRules, fieldName) 92 } else { 93 checkRules[name] = rule 94 } 95 errorRules = append(errorRules, name+"@"+rule) 96 } else { 97 // 传递的rules规则会覆盖struct tag的规则 98 continue 99 } 100 // 错误提示 101 if len(msg) > 0 { 102 ruleArray := strings.Split(rule, "|") 103 msgArray := strings.Split(msg, "|") 104 for k, v := range ruleArray { 105 // 如果msg条数比rule少,那么多余的rule使用默认的错误信息 106 if len(msgArray) <= k { 107 continue 108 } 109 if len(msgArray[k]) == 0 { 110 continue 111 } 112 array := strings.Split(v, ":") 113 if _, ok := customMsgs[name]; !ok { 114 customMsgs[name] = make(map[string]string) 115 } 116 customMsgs[name].(map[string]string)[strings.TrimSpace(array[0])] = strings.TrimSpace(msgArray[k]) 117 } 118 } 119 } 120 } 121 122 // 自定义错误消息,非必须参数,优先级比rules参数中以及struct tag中定义的错误消息更高 123 if len(msgs) > 0 && len(msgs[0]) > 0 { 124 for k, v := range msgs[0] { 125 if a, ok := fieldAliases[k]; ok { 126 // 属性的别名存在时,覆盖别名的错误信息 127 customMsgs[a] = v 128 } else { 129 customMsgs[k] = v 130 } 131 } 132 } 133 134 /* 以下逻辑和CheckMap相同 */ 135 136 // 开始执行校验: 以校验规则作为基础进行遍历校验 137 var value interface{} 138 // 这里的rule变量为多条校验规则,不包含名字或者错误信息定义 139 for key, rule := range checkRules { 140 value = nil 141 if v, ok := params[key]; ok { 142 value = v 143 } 144 if e := Check(value, rule, customMsgs[key], params); e != nil { 145 _, item := e.FirstItem() 146 // 如果值为nil|"",并且不需要require*验证时,其他验证失效 147 if value == nil || gconv.String(value) == "" { 148 required := false 149 // rule => error 150 for k := range item { 151 if _, ok := mustCheckRulesEvenValueEmpty[k]; ok { 152 required = true 153 break 154 } 155 } 156 if !required { 157 continue 158 } 159 } 160 if _, ok := errorMaps[key]; !ok { 161 errorMaps[key] = make(map[string]string) 162 } 163 for k, v := range item { 164 errorMaps[key][k] = v 165 } 166 } 167 } 168 if len(errorMaps) > 0 { 169 return newError(errorRules, errorMaps) 170 } 171 return nil 172 }