package tag import ( "git.sxidc.com/go-framework/baize/infrastructure/logger" "git.sxidc.com/go-tools/utils/reflectutils" "git.sxidc.com/go-tools/utils/strutils" "git.sxidc.com/service-supports/fserr" "reflect" "strings" "time" ) type OnAssignParsedFieldTagFunc func(fromFieldName string, fromFieldElemValue reflect.Value, toFieldElementValue reflect.Value, assignTag *AssignTag) error func UseAssignTag(from any, to any, onParsedFieldTagFunc OnAssignParsedFieldTagFunc) error { if from == nil || to == nil { return nil } fromValue := reflect.ValueOf(from) toValue := reflect.ValueOf(to) // 类型校验 if !reflectutils.IsValueStructOrStructPointer(fromValue) { return fserr.New("参数不是结构或结构指针") } if !reflectutils.IsValueStructPointer(toValue) { return fserr.New("返回类型不是结构指针") } fromElemValue := reflectutils.PointerValueElem(fromValue) toElemValue := reflectutils.PointerValueElem(toValue) for i := 0; i < toElemValue.NumField(); i++ { toField := toElemValue.Field(i) if !toField.IsValid() { return fserr.New("被赋值的结构存在无效字段") } // 初始化空值指针 if toField.Kind() == reflect.Ptr && toField.IsNil() { toField.Set(reflect.New(toField.Type().Elem())) } } err := parseStructAssignTag(fromElemValue, &toElemValue, onParsedFieldTagFunc) if err != nil { return err } return nil } func DefaultOnAssignParsedFieldTagFunc(fromFieldElemValue reflect.Value, toFieldElemValue reflect.Value, assignTag *AssignTag) error { fromKind := reflectutils.GroupValueKind(fromFieldElemValue) toKind := reflectutils.GroupValueKind(toFieldElemValue) var fromAny any switch fromKind { case reflect.Struct: // time.Time类型的结构,接收字段是string类型,使用FormatTime的格式转换 if reflectutils.IsValueTime(fromFieldElemValue) && toKind == reflect.String { fromString := fromFieldElemValue.Interface().(time.Time).Format(assignTag.FormatTime) fromAny = assignTrimFromString(fromString, assignTag) break } // 不是time.Time类型的结构,接收字段是结构,执行结构到结构字段的赋值 if !reflectutils.IsValueTime(fromFieldElemValue) && toKind == reflect.Struct { return parseStructAssignTag(fromFieldElemValue, &toFieldElemValue, func(fromFieldName string, fromFieldElemValue reflect.Value, toFieldElementValue reflect.Value, tag *AssignTag) error { return DefaultOnAssignParsedFieldTagFunc(fromFieldElemValue, toFieldElementValue, assignTag) }) } // 直接将整个结构进行字段赋值 fromAny = fromFieldElemValue.Interface() case reflect.Slice: if reflectutils.IsSliceValueOf(fromFieldElemValue, reflect.String) && toKind == reflect.String { fromString := strings.Join(fromFieldElemValue.Interface().([]string), assignTag.JoinWith) fromAny = assignTrimFromString(fromString, assignTag) break } fromAny = fromFieldElemValue.Interface() case reflect.String: fromString := fromFieldElemValue.String() if reflectutils.IsValueTime(toFieldElemValue) { toTimeField, err := time.ParseInLocation(assignTag.ParseTime, fromString, time.Local) if err != nil { return err } fromAny = toTimeField break } if reflectutils.IsSliceValueOf(toFieldElemValue, reflect.String) { fromAny = strings.Split(fromString, assignTag.SplitWith) break } fromAny = assignTrimFromString(fromString, assignTag) default: fromAny = fromFieldElemValue.Interface() } switch toKind { case reflect.Int64: return reflectutils.AssignInt64Value(fromAny, toFieldElemValue) case reflect.Uint64: return reflectutils.AssignUint64Value(fromAny, toFieldElemValue) case reflect.Float64: return reflectutils.AssignFloat64Value(fromAny, toFieldElemValue) case reflect.Bool: return reflectutils.AssignBoolValue(fromAny, toFieldElemValue) case reflect.String: return reflectutils.AssignStringValue(fromAny, toFieldElemValue) default: toFieldElemValue.Set(reflect.ValueOf(fromAny)) return nil } } func assignTrimFromString(fromString string, assignTag *AssignTag) string { if strutils.IsStringNotEmpty(assignTag.Trim) { return strings.Trim(fromString, assignTag.Trim) } else { if strutils.IsStringNotEmpty(assignTag.TrimPrefix) { return strings.TrimPrefix(fromString, assignTag.TrimPrefix) } if strutils.IsStringNotEmpty(assignTag.TrimSuffix) { return strings.TrimSuffix(fromString, assignTag.TrimSuffix) } } return fromString } func parseStructAssignTag(fromElemValue reflect.Value, toElemValue *reflect.Value, onParsedFieldTagFunc OnAssignParsedFieldTagFunc) error { for i := 0; i < fromElemValue.NumField(); i++ { fromField := fromElemValue.Type().Field(i) fromFieldValue := fromElemValue.Field(i) // 无效值 if !fromFieldValue.IsValid() { continue } if fromFieldValue.Kind() == reflect.Pointer && fromFieldValue.IsNil() { fromFieldValue.Set(reflect.New(fromField.Type.Elem())) } fromFieldElemValue := reflectutils.PointerValueElem(fromFieldValue) tagStr := fromField.Tag.Get(assignTagKey) // 结构类型的字段上没有添加Tag, 先尝试直接按照字段赋值 if strutils.IsStringEmpty(tagStr) && fromFieldElemValue.Kind() == reflect.Struct && !reflectutils.IsValueTime(fromFieldElemValue) { err := parseStructAssignTag(fromFieldElemValue, toElemValue, onParsedFieldTagFunc) if err != nil { return err } continue } assignTag, err := parseAssignTag(fromField, tagStr) if err != nil { return err } if assignTag == nil { continue } toFieldValue := toElemValue.FieldByName(assignTag.ToField) // 不存在对应的字段 if !toFieldValue.IsValid() { continue } toFieldElemValue := toFieldValue if toFieldValue.Kind() == reflect.Pointer { if !toFieldValue.IsValid() { continue } if !toFieldValue.CanSet() { continue } // 空值针,初始化 if toFieldValue.IsNil() { toFieldValue.Set(reflect.New(toFieldValue.Type().Elem())) } toFieldElemValue = toFieldValue.Elem() } err = onParsedFieldTagFunc(fromField.Name, fromFieldElemValue, toFieldElemValue, assignTag) if err != nil { return err } } return nil } const ( assignDefaultStringSliceSeparator = "::" assignTagPartSeparator = ";" assignTagPartKeyValueSeparator = ":" ) const ( assignTagKey = "assign" assignIgnore = "-" assignToField = "toField" assignParseTime = "parseTime" assignFormatTime = "formatTime" assignJoinWith = "joinWith" assignSplitWith = "splitWith" assignTrim = "trim" assignTrimPrefix = "trimPrefix" assignTrimSuffix = "trimSuffix" ) type AssignTag struct { ToField string ParseTime string FormatTime string JoinWith string SplitWith string Trim string TrimPrefix string TrimSuffix string } func parseAssignTag(field reflect.StructField, tagStr string) (*AssignTag, error) { if tagStr == assignIgnore { return nil, nil } assignTag := &AssignTag{ ToField: field.Name, ParseTime: time.DateTime, FormatTime: time.DateTime, JoinWith: assignDefaultStringSliceSeparator, SplitWith: assignDefaultStringSliceSeparator, Trim: "", TrimPrefix: "", TrimSuffix: "", } if strutils.IsStringEmpty(tagStr) { return assignTag, nil } assignParts := strings.Split(tagStr, assignTagPartSeparator) if assignParts != nil || len(assignParts) != 0 { for _, assignPart := range assignParts { assignPartKeyValue := strings.SplitN(strings.TrimSpace(assignPart), assignTagPartKeyValueSeparator, 2) if assignPartKeyValue != nil && len(assignPartKeyValue) == 2 && strutils.IsStringNotEmpty(assignPartKeyValue[1]) { assignPartKeyValue[1] = strings.Trim(assignPartKeyValue[1], "'") } switch assignPartKeyValue[0] { case assignToField: assignTag.ToField = assignPartKeyValue[1] case assignParseTime: assignTag.ParseTime = assignPartKeyValue[1] case assignFormatTime: assignTag.FormatTime = assignPartKeyValue[1] case assignJoinWith: if strutils.IsStringEmpty(assignPartKeyValue[1]) { return nil, fserr.New(assignJoinWith + "没有赋值分隔符") } assignTag.JoinWith = assignPartKeyValue[1] case assignSplitWith: if strutils.IsStringEmpty(assignPartKeyValue[1]) { return nil, fserr.New(assignSplitWith + "没有赋值分隔符") } assignTag.SplitWith = assignPartKeyValue[1] case assignTrim: assignTag.Trim = assignPartKeyValue[1] case assignTrimPrefix: assignTag.TrimPrefix = assignPartKeyValue[1] case assignTrimSuffix: assignTag.TrimSuffix = assignPartKeyValue[1] default: err := fserr.New(assignTagKey + "不支持的tag: " + assignPartKeyValue[0]) logger.GetInstance().Error(err) continue } } } return assignTag, nil }