package rule import ( "git.sxidc.com/go-framework/baize/framework/core/infrastructure/logger" "git.sxidc.com/go-tools/utils/reflectutils" "git.sxidc.com/go-tools/utils/strutils" "git.sxidc.com/go-tools/utils/template" "github.com/iancoleman/strcase" "github.com/pkg/errors" "reflect" "strings" ) const ( TypeString = "string" TypeTime = "time" TypeNumber = "number" TypeBool = "bool" ) func IsSupportedType(typeStr string) bool { return typeStr == TypeString || typeStr == TypeTime || typeStr == TypeNumber || typeStr == TypeBool } const ( tagPartSeparator = ";" tagPartKeyValueSeparator = ":" ) const ( tagKey = "rule" tagPartColumn = "column" tagPartType = "type" ) type Tag struct { ColumnName string Type string } func parseTag(entityElemValue reflect.Value, onParsedFieldTagFunc OnParsedFieldTagFunc) error { for i := 0; i < entityElemValue.NumField(); i++ { entityField := entityElemValue.Type().Field(i) entityFieldValue := entityElemValue.Field(i) // 无效值,不进行映射 if !entityFieldValue.IsValid() { continue } entityFieldElemValue := reflectutils.PointerValueElem(entityFieldValue) tagStr, ok := entityField.Tag.Lookup(tagKey) if !ok { continue } tag, err := parseFieldTag(entityField, tagStr) if err != nil { return err } if tag == nil { continue } // 结构类型的字段,解析结构内部 if entityFieldElemValue.Kind() == reflect.Struct && !reflectutils.IsValueTime(entityFieldElemValue) { err := parseTag(entityFieldElemValue, onParsedFieldTagFunc) if err != nil { return err } continue } err = onParsedFieldTagFunc(entityField.Name, entityFieldElemValue, tag) if err != nil { return err } } return nil } func parseFieldTag(field reflect.StructField, tagStr string) (*Tag, error) { fieldType := reflectutils.PointerTypeElem(field.Type) fieldKind := reflectutils.GroupTypeKind(fieldType) var fieldTypeStr string if fieldKind == reflect.Int64 || fieldKind == reflect.Uint64 || fieldKind == reflect.Float64 { fieldTypeStr = TypeNumber } else if fieldKind == reflect.String { fieldTypeStr = TypeString } else if fieldKind == reflect.Struct && fieldType.String() == "time.Time" { fieldTypeStr = TypeTime } else if fieldKind == reflect.Bool { fieldTypeStr = TypeBool } else { return nil, errors.New("type支持的类型包括: string, number, time") } tag := &Tag{ ColumnName: strcase.ToSnake(template.Id(field.Name)), Type: fieldTypeStr, } if strutils.IsStringEmpty(tagStr) { return tag, nil } tagParts := strings.Split(tagStr, tagPartSeparator) if tagParts != nil || len(tagParts) != 0 { for _, tagPart := range tagParts { tagPartKeyValue := strings.SplitN(strings.TrimSpace(tagPart), tagPartKeyValueSeparator, 2) if tagPartKeyValue != nil && len(tagPartKeyValue) == 2 && strutils.IsStringNotEmpty(tagPartKeyValue[1]) { tagPartKeyValue[1] = strings.Trim(tagPartKeyValue[1], "'") } if strutils.IsStringEmpty(tagPartKeyValue[0]) { continue } switch tagPartKeyValue[0] { case tagPartColumn: if strutils.IsStringEmpty(tagPartKeyValue[1]) { return nil, errors.New("column没有赋值列名") } tag.ColumnName = tagPartKeyValue[1] case tagPartType: if strutils.IsStringEmpty(tagPartKeyValue[1]) { return nil, errors.New("type没有赋值字段类型") } if !IsSupportedType(tagPartKeyValue[1]) { return nil, errors.Errorf("类型为%v, type支持的类型包括: string, number, time", tagPartKeyValue[1]) } tag.Type = tagPartKeyValue[1] default: err := errors.New(tagKey + "不支持的tag: " + tagPartKeyValue[0]) logger.GetInstance().Error(err) continue } } } return tag, nil }