优化对decimal.Decimal的支持
This commit is contained in:
+204
-19
@@ -67,7 +67,7 @@ func AttactToStruct(structxx interface{}, updateMap map[string]string) (map[stri
|
|||||||
// 获取结构体类型信息
|
// 获取结构体类型信息
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
fieldMap := buildFieldMap(t)
|
fieldMap := buildFieldMap(t)
|
||||||
fmt.Printf("字段映射2: %+v %+v\n", fieldMap,fieldMap["data"])
|
fmt.Printf("字段映射2: %+v %+v\n", fieldMap, fieldMap["data"])
|
||||||
|
|
||||||
for mapKey, mapValue := range updateMap {
|
for mapKey, mapValue := range updateMap {
|
||||||
fieldInfo, exists := fieldMap[mapKey]
|
fieldInfo, exists := fieldMap[mapKey]
|
||||||
@@ -197,6 +197,11 @@ func setSliceElementValue(elemValue reflect.Value, item interface{}, elemType re
|
|||||||
return setSliceElementValue(elemValue.Elem(), item, elemType.Elem())
|
return setSliceElementValue(elemValue.Elem(), item, elemType.Elem())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查是否实现了 UnmarshalJSON 方法
|
||||||
|
if hasUnmarshalJSON(elemType) {
|
||||||
|
return setUnmarshalJSONValue(elemValue, item)
|
||||||
|
}
|
||||||
|
|
||||||
// 根据元素类型进行转换
|
// 根据元素类型进行转换
|
||||||
switch elemType.Kind() {
|
switch elemType.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
@@ -384,6 +389,11 @@ func isBasicStructType(t reflect.Type) bool {
|
|||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查是否为 decimal.Decimal
|
||||||
|
if isDecimalType(t) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// 这里可以添加更多需要排除的基本结构体类型
|
// 这里可以添加更多需要排除的基本结构体类型
|
||||||
if t.PkgPath() == "time" && t.Name() == "Time" {
|
if t.PkgPath() == "time" && t.Name() == "Time" {
|
||||||
return true
|
return true
|
||||||
@@ -398,6 +408,85 @@ func isBasicStructType(t reflect.Type) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断是否为 decimal.Decimal 类型
|
||||||
|
func isDecimalType(t reflect.Type) bool {
|
||||||
|
return t.PkgPath() == "github.com/shopspring/decimal" && t.Name() == "Decimal"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查类型是否实现了 UnmarshalJSON 方法
|
||||||
|
func hasUnmarshalJSON(t reflect.Type) bool {
|
||||||
|
// 处理指针类型
|
||||||
|
if t.Kind() == reflect.Ptr {
|
||||||
|
t = t.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否实现了 json.Unmarshaler 接口
|
||||||
|
unmarshalerType := reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
|
||||||
|
return t.Implements(unmarshalerType) || reflect.PtrTo(t).Implements(unmarshalerType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查类型是否实现了 UnmarshalText 方法
|
||||||
|
func hasUnmarshalText(t reflect.Type) bool {
|
||||||
|
// 处理指针类型
|
||||||
|
if t.Kind() == reflect.Ptr {
|
||||||
|
t = t.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否实现了 encoding.TextUnmarshaler 接口
|
||||||
|
textUnmarshalerType := reflect.TypeOf((*interface {
|
||||||
|
UnmarshalText([]byte) error
|
||||||
|
})(nil)).Elem()
|
||||||
|
return t.Implements(textUnmarshalerType) || reflect.PtrTo(t).Implements(textUnmarshalerType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 UnmarshalJSON 方法设置值
|
||||||
|
func setUnmarshalJSONValue(field reflect.Value, value interface{}) error {
|
||||||
|
jsonBytes, err := json.Marshal(value)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("序列化值失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取字段的地址(确保我们可以调用指针方法)
|
||||||
|
var fieldAddr reflect.Value
|
||||||
|
if field.CanAddr() {
|
||||||
|
fieldAddr = field.Addr()
|
||||||
|
} else {
|
||||||
|
// 对于不可寻址的字段,创建一个临时变量
|
||||||
|
temp := reflect.New(field.Type())
|
||||||
|
temp.Elem().Set(field)
|
||||||
|
fieldAddr = temp
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用 UnmarshalJSON 方法
|
||||||
|
if unmarshaler, ok := fieldAddr.Interface().(json.Unmarshaler); ok {
|
||||||
|
return unmarshaler.UnmarshalJSON(jsonBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("类型 %s 未实现 json.Unmarshaler", field.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 UnmarshalText 方法设置值
|
||||||
|
func setUnmarshalTextValue(field reflect.Value, value string) error {
|
||||||
|
// 获取字段的地址
|
||||||
|
var fieldAddr reflect.Value
|
||||||
|
if field.CanAddr() {
|
||||||
|
fieldAddr = field.Addr()
|
||||||
|
} else {
|
||||||
|
temp := reflect.New(field.Type())
|
||||||
|
temp.Elem().Set(field)
|
||||||
|
fieldAddr = temp
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用 UnmarshalText 方法
|
||||||
|
if unmarshaler, ok := fieldAddr.Interface().(interface {
|
||||||
|
UnmarshalText([]byte) error
|
||||||
|
}); ok {
|
||||||
|
return unmarshaler.UnmarshalText([]byte(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("类型 %s 未实现 UnmarshalText", field.Type())
|
||||||
|
}
|
||||||
|
|
||||||
// 处理嵌套结构体(支持JSON解析)
|
// 处理嵌套结构体(支持JSON解析)
|
||||||
// processNestedStruct 处理嵌套结构体
|
// processNestedStruct 处理嵌套结构体
|
||||||
func processNestedStruct(field reflect.Value, value string, parentKey string) (map[string]ChangeInfo, error) {
|
func processNestedStruct(field reflect.Value, value string, parentKey string) (map[string]ChangeInfo, error) {
|
||||||
@@ -420,25 +509,106 @@ func processNestedStruct(field reflect.Value, value string, parentKey string) (m
|
|||||||
return nil, fmt.Errorf("无效的结构体字段")
|
return nil, fmt.Errorf("无效的结构体字段")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 尝试解析JSON字符串到map
|
// 首先尝试解析为JSON对象(用于真正的嵌套结构体)
|
||||||
var nestedMap map[string]string
|
var nestedMap map[string]interface{}
|
||||||
if err := json.Unmarshal([]byte(value), &nestedMap); err != nil {
|
if err := json.Unmarshal([]byte(value), &nestedMap); err == nil {
|
||||||
return nil, fmt.Errorf("嵌套结构体值必须是JSON格式: %w", err)
|
// 成功解析为JSON对象,说明是真正的嵌套结构体
|
||||||
|
stringMap := make(map[string]string, len(nestedMap))
|
||||||
|
for k, v := range nestedMap {
|
||||||
|
str, err := cast.ToStringE(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("转换嵌套字段 %s 的值失败: %w", k, err)
|
||||||
|
}
|
||||||
|
stringMap[k] = str
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归处理嵌套结构体
|
||||||
|
nestedChanges, err := AttactToStruct(structValue.Addr().Interface(), stringMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为嵌套字段的变更记录添加前缀
|
||||||
|
for key, change := range nestedChanges {
|
||||||
|
fullKey := parentKey + "." + key
|
||||||
|
changeMap[fullKey] = change
|
||||||
|
}
|
||||||
|
return changeMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 递归处理嵌套结构体
|
// 如果解析JSON对象失败,尝试直接设置整个结构体的值
|
||||||
nestedChanges, err := AttactToStruct(structValue.Addr().Interface(), nestedMap)
|
// 这可能是一个基本结构体类型(如decimal.Decimal)或者实现了Unmarshaler接口的类型
|
||||||
if err != nil {
|
if hasUnmarshalJSON(structValue.Type()) {
|
||||||
return nil, err
|
// 对于实现了UnmarshalJSON的类型,直接使用JSON解析
|
||||||
|
err := json.Unmarshal([]byte(value), structValue.Addr().Interface())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("解析嵌套结构体值失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录变更
|
||||||
|
oldValueStr, _ := cast.ToStringE(field.Interface())
|
||||||
|
newValueStr := value
|
||||||
|
changeMap[parentKey] = ChangeInfo{
|
||||||
|
Old: oldValueStr,
|
||||||
|
New: newValueStr,
|
||||||
|
Val: structValue.Interface(),
|
||||||
|
}
|
||||||
|
return changeMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 为嵌套字段的变更记录添加前缀
|
// 对于其他基本结构体类型,尝试直接设置
|
||||||
for key, change := range nestedChanges {
|
if isBasicStructType(structValue.Type()) {
|
||||||
fullKey := parentKey + "." + key
|
// 保存旧值
|
||||||
changeMap[fullKey] = change
|
oldValueStr, _ := cast.ToStringE(field.Interface())
|
||||||
|
|
||||||
|
// 尝试设置新值
|
||||||
|
err := setBasicStructValue(structValue, value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("设置基本结构体值失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录变更
|
||||||
|
newValueStr, _ := cast.ToStringE(field.Interface())
|
||||||
|
changeMap[parentKey] = ChangeInfo{
|
||||||
|
Old: oldValueStr,
|
||||||
|
New: newValueStr,
|
||||||
|
Val: structValue.Interface(),
|
||||||
|
}
|
||||||
|
return changeMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return changeMap, nil
|
return nil, fmt.Errorf("嵌套结构体值必须是有效的JSON格式或基本结构体类型")
|
||||||
|
|
||||||
|
// // 尝试解析JSON字符串到map
|
||||||
|
// var nestedMap map[string]string
|
||||||
|
// if err := json.Unmarshal([]byte(value), &nestedMap); err != nil {
|
||||||
|
// return nil, fmt.Errorf("嵌套结构体值必须是JSON格式: %w", err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 递归处理嵌套结构体
|
||||||
|
// nestedChanges, err := AttactToStruct(structValue.Addr().Interface(), nestedMap)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 为嵌套字段的变更记录添加前缀
|
||||||
|
// for key, change := range nestedChanges {
|
||||||
|
// fullKey := parentKey + "." + key
|
||||||
|
// changeMap[fullKey] = change
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return changeMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置基本结构体的值
|
||||||
|
func setBasicStructValue(field reflect.Value, value string) error {
|
||||||
|
// 检查是否实现了UnmarshalText
|
||||||
|
if hasUnmarshalText(field.Type()) {
|
||||||
|
return setUnmarshalTextValue(field, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于其他基本结构体类型,尝试JSON解析
|
||||||
|
return json.Unmarshal([]byte(value), field.Addr().Interface())
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测是否为自定义类型
|
// 检测是否为自定义类型
|
||||||
@@ -466,6 +636,24 @@ func isCustomType(t reflect.Type) bool {
|
|||||||
func setFieldValue(field reflect.Value, value string) (interface{}, error) {
|
func setFieldValue(field reflect.Value, value string) (interface{}, error) {
|
||||||
kind := field.Kind()
|
kind := field.Kind()
|
||||||
|
|
||||||
|
// 优先检查是否实现了 UnmarshalJSON 方法
|
||||||
|
if hasUnmarshalJSON(field.Type()) {
|
||||||
|
err := setUnmarshalJSONValue(field, value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("UnmarshalJSON 失败: %w", err)
|
||||||
|
}
|
||||||
|
return field.Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其次检查是否实现了 UnmarshalText 方法
|
||||||
|
if hasUnmarshalText(field.Type()) {
|
||||||
|
err := setUnmarshalTextValue(field, value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("UnmarshalText 失败: %w", err)
|
||||||
|
}
|
||||||
|
return field.Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// 检测是否为自定义类型(有包路径的类型)
|
// 检测是否为自定义类型(有包路径的类型)
|
||||||
if isCustomType(field.Type()) {
|
if isCustomType(field.Type()) {
|
||||||
return setCustomTypeValue(field, value)
|
return setCustomTypeValue(field, value)
|
||||||
@@ -566,16 +754,13 @@ func convertMap(field reflect.Value, value string) (interface{}, error) {
|
|||||||
// 处理自定义类型
|
// 处理自定义类型
|
||||||
func setCustomTypeValue(field reflect.Value, value string) (interface{}, error) {
|
func setCustomTypeValue(field reflect.Value, value string) (interface{}, error) {
|
||||||
// 检查是否实现了TextUnmarshaler接口
|
// 检查是否实现了TextUnmarshaler接口
|
||||||
if unmarshaler, ok := field.Addr().Interface().(interface {
|
if hasUnmarshalText(field.Type()) {
|
||||||
UnmarshalText([]byte) error
|
err := setUnmarshalTextValue(field, value)
|
||||||
}); ok {
|
|
||||||
err := unmarshaler.UnmarshalText([]byte(value))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return field.Interface(), nil
|
return field.Interface(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 对于其他自定义类型,我们需要获取其基础类型并进行转换
|
// 对于其他自定义类型,我们需要获取其基础类型并进行转换
|
||||||
baseType := getBaseType(field.Type())
|
baseType := getBaseType(field.Type())
|
||||||
if baseType == nil {
|
if baseType == nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user