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  }