package tag import ( "git.sxidc.com/go-framework/baize/infrastructure/logger" "git.sxidc.com/go-tools/utils/strutils" "git.sxidc.com/service-supports/fserr" "reflect" "strings" "time" ) func AssignTo[F any, T any](from F) T { var zero T assign, err := ParseAssignTag(from) if err != nil { logger.GetInstance().Error(err) return zero } retType := reflect.TypeOf(zero) retValue := reflect.New(retType).Elem() return retValue.Interface() } const ( assignDefaultStringSliceSeparator = "::" assignTagPartSeparator = ";" assignTagPartKeyValueSeparator = ":" ) const ( assignTagKey = "assign" assignIgnore = "-" assignToField = "toField" assignParseTime = "parseTime" assignFormatTime = "formatTime" assignJoinWith = "joinWith" assignSplitWith = "splitWith" assignTrim = "trim" assignTrimLeft = "trimLeft" assignTrimRight = "trimRight" ) type Assign struct { AssignElement map[string]any } type AssignElement struct { ToField string ParseTime string FormatTime string JoinWith string SplitWith string Trim string TrimLeft string TrimRight string // 原字段的反射结构 OriginFieldType reflect.Type OriginFieldValue reflect.Value // 值类型的反射结构 FieldTypeElem reflect.Type FieldValueElem reflect.Value } func ParseAssignTag(from any) (*Assign, error) { if from == nil { return nil, fserr.New("没有传递结构或结构指针") } fromType := reflect.TypeOf(from) if fromType.Kind() != reflect.Ptr && fromType.Kind() != reflect.Struct { return nil, fserr.New("参数不是结构或结构指针") } if fromType.Kind() == reflect.Ptr && fromType.Elem().Kind() != reflect.Struct { return nil, fserr.New("参数不是结构或结构指针") } fromValue := reflect.ValueOf(from) fromElemValue := fromValue if fromType.Kind() == reflect.Ptr { fromElemValue = fromValue.Elem() } assign := new(Assign) assign.AssignElement = make(map[string]any) for i := 0; i < fromElemValue.NumField(); i++ { field := fromType.Field(i) fieldValue := fromElemValue.Field(i) // 零值,不用赋值 if !fieldValue.IsValid() { continue } element, err := parseSqlMappingElement(field, fieldValue) if err != nil { return nil, err } if element == nil { continue } assign.AssignElement[field.Name] = element } return assign, nil } func parseSqlMappingElement(field reflect.StructField, fieldValue reflect.Value) (any, error) { assignTag := field.Tag.Get(assignTagKey) if assignTag == assignIgnore { return nil, nil } fieldValueElemType := field.Type if field.Type.Kind() == reflect.Ptr { fieldValueElemType = field.Type.Elem() } fieldValueElem := fieldValue if fieldValue.Kind() == reflect.Ptr { fieldValueElem = fieldValue.Elem() } if fieldValueElemType.Kind() == reflect.Struct && fieldValueElemType != reflect.TypeOf(time.Time{}) { return ParseAssignTag(fieldValueElem.Interface()) } element := &AssignElement{ ToField: field.Name, ParseTime: time.DateTime, FormatTime: time.DateTime, JoinWith: assignDefaultStringSliceSeparator, SplitWith: assignDefaultStringSliceSeparator, Trim: "", TrimLeft: "", TrimRight: "", OriginFieldType: field.Type, OriginFieldValue: fieldValue, FieldTypeElem: fieldValueElemType, FieldValueElem: fieldValueElem, } if strutils.IsStringEmpty(assignTag) { return element, nil } assignParts := strings.Split(assignTag, 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.TrimSpace(strings.Trim(assignPartKeyValue[1], "'")) } switch assignPartKeyValue[0] { case assignToField: element.ToField = assignPartKeyValue[1] case assignParseTime: if fieldValueElemType.Elem().Kind() != reflect.String { return nil, fserr.New(assignParseTime + "应该添加在string字段上") } element.ParseTime = assignPartKeyValue[1] case assignFormatTime: if fieldValueElemType.Elem().Kind() != reflect.Struct && fieldValueElemType != reflect.TypeOf(time.Time{}) { return nil, fserr.New(assignFormatTime + "应该添加在time.Time字段上") } element.FormatTime = assignPartKeyValue[1] case assignJoinWith: if strutils.IsStringEmpty(assignPartKeyValue[1]) { return nil, fserr.New(assignJoinWith + "没有赋值分隔符") } if fieldValueElemType.Kind() != reflect.Slice || fieldValueElemType.Elem().Kind() != reflect.String { return nil, fserr.New(assignJoinWith + "应该添加在[]string字段上") } element.JoinWith = assignPartKeyValue[1] case assignSplitWith: if strutils.IsStringEmpty(assignPartKeyValue[1]) { return nil, fserr.New(assignSplitWith + "没有赋值分隔符") } if fieldValueElemType.Elem().Kind() != reflect.String { return nil, fserr.New(assignSplitWith + "应该添加在string字段上") } element.SplitWith = assignPartKeyValue[1] case assignTrim: if fieldValueElemType.Elem().Kind() != reflect.String { return nil, fserr.New(assignTrim + "应该添加在string字段上") } element.Trim = assignPartKeyValue[1] case assignTrimLeft: if fieldValueElemType.Elem().Kind() != reflect.String { return nil, fserr.New(assignTrimLeft + "应该添加在string字段上") } element.TrimLeft = assignPartKeyValue[1] case assignTrimRight: if fieldValueElemType.Elem().Kind() != reflect.String { return nil, fserr.New(assignTrimRight + "应该添加在string字段上") } element.TrimRight = assignPartKeyValue[1] default: continue } } } return element, nil }