github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/validate/validate.go (about) 1 package validate 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "reflect" 7 "sort" 8 "strings" 9 "sync" 10 11 "github.com/antonmedv/expr" 12 "github.com/isyscore/isc-gobase/constants" 13 "github.com/isyscore/isc-gobase/goid" 14 "github.com/isyscore/isc-gobase/isc" 15 "github.com/isyscore/isc-gobase/logger" 16 "github.com/isyscore/isc-gobase/validate/matcher" 17 ) 18 19 var lock sync.Mutex 20 21 type MatchCollector func(objectTypeFullName string, fieldKind reflect.Kind, objectFieldName string, tagName string, subCondition string, errMsg string) 22 23 type CollectorEntity struct { 24 name string 25 infCollector MatchCollector 26 } 27 28 type CheckResult struct { 29 Result bool 30 ErrMsg string 31 } 32 33 var checkerEntities []CollectorEntity 34 35 /* 核查的标签 */ 36 var matchTagArray = []string{constants.Value, constants.IsBlank, constants.Range, constants.Model, constants.Condition, constants.Regex, constants.Customize} 37 38 func Check(object any, fieldNames ...string) (bool, string) { 39 return CheckWithParameter(map[string]interface{}{}, object, fieldNames...) 40 } 41 42 // CheckWithParameter 添加额外参数的传递 43 func CheckWithParameter(parameterMap map[string]interface{}, object interface{}, fieldNames ...string) (bool, string) { 44 if object == nil { 45 return true, "" 46 } 47 objType := reflect.TypeOf(object) 48 objValue := reflect.ValueOf(object) 49 50 // 指针类型按照指针类型 51 if objType.Kind() == reflect.Ptr { 52 objValue = objValue.Elem() 53 return Check(objValue.Interface(), fieldNames...) 54 } 55 56 if objType.Kind() != reflect.Struct { 57 return true, "" 58 } 59 60 // 搜集核查器 61 collectCollector(objType) 62 63 ch := make(chan *CheckResult) 64 for index, num := 0, objType.NumField(); index < num; index++ { 65 field := objType.Field(index) 66 fieldValue := objValue.Field(index) 67 68 // 私有字段不处理 69 if !isc.IsPublic(field.Name) { 70 continue 71 } 72 73 // 过滤选择的列 74 if !isSelectField(field.Name, fieldNames...) { 75 continue 76 } 77 78 // 基本类型 79 if matcher.IsCheckedKing(fieldValue.Type()) || (fieldValue.Kind() == reflect.Ptr && !fieldValue.Elem().IsValid()) || (fieldValue.Kind() == reflect.Ptr && matcher.IsCheckedKing(fieldValue.Elem().Type())) { 80 tagJudge := field.Tag.Get(constants.MATCH) 81 if len(tagJudge) == 0 { 82 continue 83 } 84 85 // 核查结果:任何一个属性失败,则返回失败 86 goid.Go(func() { 87 check(parameterMap, object, field, fieldValue.Interface(), ch) 88 }) 89 checkResult := <-ch 90 if !checkResult.Result { 91 close(ch) 92 return false, checkResult.ErrMsg 93 } 94 } else if fieldValue.Kind() == reflect.Struct || (fieldValue.Kind() == reflect.Ptr && fieldValue.Elem().Kind() == reflect.Struct) { 95 // struct 结构类型 96 tagMatch := field.Tag.Get(constants.MATCH) 97 if len(tagMatch) == 0 || (len(tagMatch) == 1 && tagMatch != constants.CHECK) { 98 continue 99 } 100 result, err := Check(fieldValue.Interface()) 101 if !result { 102 return false, err 103 } 104 } else if fieldValue.Kind() == reflect.Map || (fieldValue.Kind() == reflect.Ptr && fieldValue.Elem().Kind() == reflect.Map) { 105 // map结构 106 if fieldValue.Len() == 0 { 107 continue 108 } 109 110 for mapR := fieldValue.MapRange(); mapR.Next(); { 111 mapKey := mapR.Key() 112 mapValue := mapR.Value() 113 114 result, err := Check(mapKey.Interface()) 115 if !result { 116 return false, err 117 } 118 result, err = Check(mapValue.Interface()) 119 if !result { 120 return false, err 121 } 122 } 123 } else if fieldValue.Kind() == reflect.Array || (fieldValue.Kind() == reflect.Ptr && fieldValue.Elem().Kind() == reflect.Array) { 124 // Array 结构 125 arrayLen := fieldValue.Len() 126 for arrayIndex := 0; arrayIndex < arrayLen; arrayIndex++ { 127 fieldValueItem := fieldValue.Index(arrayIndex) 128 result, err := Check(fieldValueItem.Interface()) 129 if !result { 130 return false, err 131 } 132 } 133 } else if fieldValue.Kind() == reflect.Slice || (fieldValue.Kind() == reflect.Ptr && fieldValue.Elem().Kind() == reflect.Slice) { 134 // Slice 结构 135 tagJudge := field.Tag.Get(constants.MATCH) 136 if len(tagJudge) == 0 { 137 continue 138 } 139 140 // 核查结果:任何一个属性失败,则返回失败 141 goid.Go(func() { 142 check(parameterMap, object, field, fieldValue.Interface(), ch) 143 }) 144 checkResult := <-ch 145 if !checkResult.Result { 146 close(ch) 147 return false, checkResult.ErrMsg 148 } 149 150 arrayLen := fieldValue.Len() 151 for arrayIndex := 0; arrayIndex < arrayLen; arrayIndex++ { 152 fieldValueItem := fieldValue.Index(arrayIndex) 153 result, err := Check(fieldValueItem.Interface()) 154 if !result { 155 return false, err 156 } 157 } 158 } 159 } 160 close(ch) 161 return true, "" 162 } 163 164 // 搜集核查器 165 func collectCollector(objType reflect.Type) { 166 objectFullName := objType.String() 167 168 /* 搜集过则不再搜集 */ 169 if _, contain := matcher.MatchMap[objectFullName]; contain { 170 return 171 } 172 173 lock.Lock() 174 /* 搜集过则不再搜集 */ 175 if _, contain := matcher.MatchMap[objectFullName]; contain { 176 return 177 } 178 179 doCollectCollector(objType) 180 lock.Unlock() 181 } 182 183 func doCollectCollector(objType reflect.Type) { 184 // 基本类型不需要搜集 185 if matcher.IsCheckedKing(objType) { 186 return 187 } 188 189 // 指针类型按照指针类型 190 if objType.Kind() == reflect.Ptr { 191 doCollectCollector(objType.Elem()) 192 return 193 } 194 195 if objType.Kind() != reflect.Struct { 196 return 197 } 198 199 objectFullName := objType.String() 200 for fieldIndex, num := 0, objType.NumField(); fieldIndex < num; fieldIndex++ { 201 field := objType.Field(fieldIndex) 202 fieldKind := field.Type.Kind() 203 204 // 不可访问字段不处理 205 if !isc.IsPublic(field.Name) { 206 continue 207 } 208 209 if fieldKind == reflect.Ptr { 210 fieldKind = field.Type.Elem().Kind() 211 } 212 213 // 禁用 214 tagMatch := field.Tag.Get(constants.Disable) 215 if len(tagMatch) != 0 && tagMatch == "true" { 216 continue 217 } 218 219 // 基本类型 220 if matcher.IsCheckedKing(field.Type) { 221 // 错误码信息 222 errMsg := field.Tag.Get(constants.ErrMsg) 223 224 // match 225 tagMatch := field.Tag.Get(constants.MATCH) 226 if len(tagMatch) == 0 { 227 continue 228 } 229 230 if _, contain := matcher.MatchMap[objectFullName][field.Name]; !contain { 231 addMatcher(objectFullName, fieldKind, field.Name, tagMatch, errMsg) 232 } 233 234 // accept 235 tagAccept := field.Tag.Get(constants.Accept) 236 if len(tagMatch) == 0 { 237 continue 238 } 239 240 if _, contain := matcher.MatchMap[objectFullName][field.Name]; contain { 241 addCollector(objectFullName, fieldKind, field.Name, constants.Accept, tagAccept, errMsg) 242 } 243 } else if fieldKind == reflect.Struct { 244 // struct 结构类型 245 tagMatch := field.Tag.Get(constants.MATCH) 246 if len(tagMatch) == 0 || (len(tagMatch) == 1 && tagMatch != constants.CHECK) { 247 continue 248 } 249 250 doCollectCollector(field.Type) 251 } else if fieldKind == reflect.Map { 252 // Map 结构 253 doCollectCollector(field.Type.Key()) 254 doCollectCollector(field.Type.Elem()) 255 } else if fieldKind == reflect.Array { 256 // Array 结构 257 doCollectCollector(field.Type.Elem()) 258 } else if fieldKind == reflect.Slice { 259 // Slice 结构 260 261 // 错误码信息 262 errMsg := field.Tag.Get(constants.ErrMsg) 263 264 // match 265 tagMatch := field.Tag.Get(constants.MATCH) 266 if len(tagMatch) == 0 { 267 continue 268 } 269 270 if _, contain := matcher.MatchMap[objectFullName][field.Name]; !contain { 271 addMatcher(objectFullName, fieldKind, field.Name, tagMatch, errMsg) 272 } 273 274 // accept 275 tagAccept := field.Tag.Get(constants.Accept) 276 if len(tagMatch) == 0 { 277 continue 278 } 279 280 if _, contain := matcher.MatchMap[objectFullName][field.Name]; !contain { 281 addCollector(objectFullName, fieldKind, field.Name, constants.Accept, tagAccept, errMsg) 282 } 283 284 doCollectCollector(field.Type.Elem()) 285 } else { 286 // Uintptr 类型不处理 287 } 288 } 289 } 290 291 // 是否是选择的列,没有选择也认为是选择的 292 func isSelectField(fieldName string, fieldNames ...string) bool { 293 if len(fieldNames) == 0 { 294 return true 295 } 296 for _, name := range fieldNames { 297 // 不区分大小写 298 if strings.EqualFold(name, fieldName) { 299 return true 300 } 301 } 302 return false 303 } 304 305 // 搜集处理器,对于有一些空格的也进行单独处理 306 func addMatcher(objectFullName string, fieldKind reflect.Kind, fieldName string, matchJudge string, errMsg string) { 307 var subStrIndexes []int 308 for _, tag := range matchTagArray { 309 index := strings.Index(matchJudge, tag) 310 if index != -1 { 311 subStrIndexes = append(subStrIndexes, index) 312 } 313 } 314 sort.Ints(subStrIndexes) 315 316 lastIndex := 0 317 for _, subIndex := range subStrIndexes { 318 if lastIndex == subIndex { 319 continue 320 } 321 subJudgeStr := matchJudge[lastIndex:subIndex] 322 buildChecker(objectFullName, fieldKind, fieldName, constants.MATCH, subJudgeStr, errMsg) 323 lastIndex = subIndex 324 } 325 326 subJudgeStr := matchJudge[lastIndex:] 327 buildChecker(objectFullName, fieldKind, fieldName, constants.MATCH, subJudgeStr, errMsg) 328 } 329 330 // 添加搜集器 331 func addCollector(objectFullName string, fieldKind reflect.Kind, fieldName string, tagName string, matchJudge string, errMsg string) { 332 buildChecker(objectFullName, fieldKind, fieldName, tagName, matchJudge, errMsg) 333 } 334 335 func buildChecker(objectFullName string, fieldKind reflect.Kind, fieldName string, tagName string, subStr string, errMsg string) { 336 for _, entity := range checkerEntities { 337 entity.infCollector(objectFullName, fieldKind, fieldName, tagName, subStr, errMsg) 338 } 339 } 340 341 func check(parameterMap map[string]interface{}, object any, field reflect.StructField, fieldRelValue any, ch chan *CheckResult) { 342 objectType := reflect.TypeOf(object) 343 344 if fieldMatcher, contain := matcher.MatchMap[objectType.String()][field.Name]; contain { 345 accept := fieldMatcher.Accept 346 errMsgProgram := fieldMatcher.ErrMsgProgram 347 matchers := fieldMatcher.Matchers 348 349 // 黑名单,而且匹配到,则核查失败 350 if !accept { 351 if matchResult, errMsg := judgeMatch(matchers, parameterMap, object, field, fieldRelValue, accept); matchResult { 352 if errMsgProgram != nil { 353 env := map[string]any{ 354 "sprintf": fmt.Sprintf, 355 "root": object, 356 "current": fieldRelValue, 357 } 358 359 output, err := expr.Run(errMsgProgram, env) 360 if err != nil { 361 logger.Error(err.Error()) 362 ch <- &CheckResult{Result: false, ErrMsg: err.Error()} 363 return 364 } 365 366 result := fmt.Sprintf("%v", output) 367 368 ch <- &CheckResult{Result: false, ErrMsg: result} 369 } else { 370 ch <- &CheckResult{Result: false, ErrMsg: errMsg} 371 } 372 return 373 } 374 } 375 376 // 白名单,没有匹配到,则核查失败 377 if accept { 378 if matchResult, errMsg := judgeMatch(matchers, parameterMap, object, field, fieldRelValue, accept); !matchResult { 379 if errMsgProgram != nil { 380 env := map[string]any{ 381 "sprintf": fmt.Sprintf, 382 "root": object, 383 "current": fieldRelValue, 384 } 385 386 output, err := expr.Run(errMsgProgram, env) 387 if err != nil { 388 logger.Error(err.Error()) 389 ch <- &CheckResult{Result: false, ErrMsg: err.Error()} 390 return 391 } 392 393 result := fmt.Sprintf("%v", output) 394 ch <- &CheckResult{Result: false, ErrMsg: result} 395 } else { 396 ch <- &CheckResult{Result: false, ErrMsg: errMsg} 397 } 398 return 399 } 400 } 401 } 402 ch <- &CheckResult{Result: true} 403 return 404 } 405 406 // 任何一个匹配上,则返回true,都没有匹配上则返回false 407 func judgeMatch(matchers []*matcher.Matcher, parameterMap map[string]interface{}, object any, field reflect.StructField, fieldValue any, accept bool) (bool, string) { 408 var errMsgArray []string 409 for _, match := range matchers { 410 if (*match).IsEmpty() { 411 continue 412 } 413 414 matchResult := (*match).Match(parameterMap, object, field, fieldValue) 415 if matchResult { 416 if !accept { 417 errMsgArray = append(errMsgArray, (*match).GetBlackMsg()) 418 } else { 419 errMsgArray = []string{} 420 } 421 return true, arraysToString(errMsgArray) 422 } else { 423 if accept { 424 errMsgArray = append(errMsgArray, (*match).GetWhitMsg()) 425 } 426 } 427 } 428 return false, arraysToString(errMsgArray) 429 } 430 431 func RegisterCustomize(funName string, fun any) { 432 matcher.RegisterCustomize(funName, fun) 433 } 434 435 // 包的初始回调 436 func init() { 437 /* 匹配后是否接受 */ 438 checkerEntities = append(checkerEntities, CollectorEntity{constants.Accept, matcher.CollectAccept}) 439 440 /* 搜集匹配器 */ 441 checkerEntities = append(checkerEntities, CollectorEntity{constants.Value, matcher.BuildValuesMatcher}) 442 checkerEntities = append(checkerEntities, CollectorEntity{constants.IsBlank, matcher.BuildIsBlankMatcher}) 443 checkerEntities = append(checkerEntities, CollectorEntity{constants.IsUnBlank, matcher.BuildIsUnBlankMatcher}) 444 checkerEntities = append(checkerEntities, CollectorEntity{constants.Range, matcher.BuildRangeMatcher}) 445 checkerEntities = append(checkerEntities, CollectorEntity{constants.Model, matcher.BuildModelMatcher}) 446 checkerEntities = append(checkerEntities, CollectorEntity{constants.Condition, matcher.BuildConditionMatcher}) 447 checkerEntities = append(checkerEntities, CollectorEntity{constants.Customize, matcher.BuildCustomizeMatcher}) 448 checkerEntities = append(checkerEntities, CollectorEntity{constants.Regex, matcher.BuildRegexMatcher}) 449 } 450 451 func arraysToString(dataArray []string) string { 452 if len(dataArray) == 1 { 453 return dataArray[0] 454 } 455 myValue, _ := json.Marshal(dataArray) 456 return string(myValue) 457 }