diff --git a/TODO b/TODO index 740646c93..ae76a2dcc 100644 --- a/TODO +++ b/TODO @@ -43,7 +43,6 @@ ghttp hook回调使用方式在注册路由比较多的时候,优先级可能 gform参考 https://gohouse.github.io/gorose/dist/index.html 进行改进 完善配置管理章节,说明默认的配置文件更改方式; 完善gform配置管理说明,g.DB/Database和gdb.New的区别; -改进gconv.Struct方法,支持不区分大小写的属性-键名匹配,便于开发者执行对象转换; diff --git a/g/util/gconv/gconv_struct.go b/g/util/gconv/gconv_struct.go index 2ed0e0819..24ad7c9c6 100644 --- a/g/util/gconv/gconv_struct.go +++ b/g/util/gconv/gconv_struct.go @@ -7,6 +7,7 @@ package gconv import ( + "gitee.com/johng/gf/g/container/gset" "gitee.com/johng/gf/g/util/gstr" "reflect" "gitee.com/johng/gf/third/github.com/fatih/structs" @@ -83,16 +84,38 @@ func Struct(params interface{}, objPointer interface{}, attrMapping...map[string } } // 最后按照默认规则进行匹配 + attrset := gset.NewStringSet(false) + elemtype := elem.Type() + for i := 0; i < elem.NumField(); i++ { + attrset.Add(elemtype.Field(i).Name) + } for mapk, mapv := range paramsMap { - name := gstr.UcFirst(mapk) - if _, ok := dmap[name]; ok { + name := "" + for _, v := range []string{gstr.UcFirst(mapk), gstr.ToLower(mapk), gstr.ToUpper(mapk)} { + if _, ok := dmap[v]; ok { + continue + } + if _, ok := tagmap[v]; ok { + continue + } + // 循环查找属性名称进行匹配 + attrset.Iterator(func(value string) bool { + if strings.EqualFold(value, v) { + name = value + return false + } + return true + }) + if name != "" { + break + } + } + // 如果没有匹配到属性名称,放弃 + if name == "" { continue } - // 后续tag逻辑中会处理的key(重复的键名)这里便不处理 - if _, ok := tagmap[mapk]; !ok { - if err := bindVarToStruct(elem, name, mapv); err != nil { - return err - } + if err := bindVarToStruct(elem, name, mapv); err != nil { + return err } } return nil @@ -120,7 +143,7 @@ func getTagMapOfStruct(objPointer interface{}) map[string]string { } // 将参数值绑定到对象指定名称的属性上 -func bindVarToStruct(elem reflect.Value, name string, value interface{}) error { +func bindVarToStruct(elem reflect.Value, name string, value interface{}) (err error) { structFieldValue := elem.FieldByName(name) // 键名与对象属性匹配检测,map中如果有struct不存在的属性,那么不做处理,直接return if !structFieldValue.IsValid() { @@ -136,7 +159,7 @@ func bindVarToStruct(elem reflect.Value, name string, value interface{}) error { defer func() { // 如果转换失败,那么可能是类型不匹配造成(例如属性包含自定义类型),那么执行递归转换 if recover() != nil { - bindVarToStructIfDefaultConvertionFailed(structFieldValue, value) + err = bindVarToStructIfDefaultConvertionFailed(structFieldValue, value) } }() structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String()))) @@ -144,7 +167,7 @@ func bindVarToStruct(elem reflect.Value, name string, value interface{}) error { } // 将参数值绑定到对象指定索引位置的属性上 -func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) error { +func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) (err error) { structFieldValue := elem.FieldByIndex([]int{index}) // 键名与对象属性匹配检测 if !structFieldValue.IsValid() { @@ -160,7 +183,7 @@ func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) er defer func() { // 如果转换失败,那么可能是类型不匹配造成(例如属性包含自定义类型),那么执行递归转换 if recover() != nil { - bindVarToStructIfDefaultConvertionFailed(structFieldValue, value) + err = bindVarToStructIfDefaultConvertionFailed(structFieldValue, value) } }() structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String()))) @@ -168,7 +191,7 @@ func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) er } // 当默认的基本类型转换失败时,通过recover判断后执行反射类型转换 -func bindVarToStructIfDefaultConvertionFailed(structFieldValue reflect.Value, value interface{}) { +func bindVarToStructIfDefaultConvertionFailed(structFieldValue reflect.Value, value interface{}) error { switch structFieldValue.Kind() { case reflect.Struct: Struct(value, structFieldValue) @@ -190,7 +213,8 @@ func bindVarToStructIfDefaultConvertionFailed(structFieldValue reflect.Value, va } structFieldValue.Set(a) default: - panic(errors.New(fmt.Sprintf(`cannot convert to type "%s"`, structFieldValue.Type().String()))) + return errors.New(fmt.Sprintf(`cannot convert to type "%s"`, structFieldValue.Type().String())) } + return nil } diff --git a/g/util/gstr/gstr.go b/g/util/gstr/gstr.go index eeb46a7da..dd788afe1 100644 --- a/g/util/gstr/gstr.go +++ b/g/util/gstr/gstr.go @@ -23,6 +23,16 @@ func ReplaceByMap(origin string, replaces map[string]string) string { return result } +// 字符串转换为小写 +func ToLower(s string) string { + return strings.ToLower(s) +} + +// 字符串转换为大写 +func ToUpper(s string) string { + return strings.ToUpper(s) +} + // 字符串首字母转换为大写 func UcFirst(s string) string { if len(s) == 0 { diff --git a/geg/util/gconv/gconv_struct1.go b/geg/util/gconv/gconv_struct1.go index 2e6a971e7..1b2906560 100644 --- a/geg/util/gconv/gconv_struct1.go +++ b/geg/util/gconv/gconv_struct1.go @@ -16,13 +16,13 @@ type User struct { func main() { user := (*User)(nil) - // 使用map直接映射绑定属性值到对象 + // 使用默认映射规则绑定属性值到对象 user = new(User) params1 := g.Map{ "uid" : 1, - "name" : "john", - "pass1" : "123", - "pass2" : "123", + "Name" : "john", + "PASS1" : "123", + "PASS2" : "456", } if err := gconv.Struct(params1, user); err == nil { fmt.Println(user) @@ -33,8 +33,8 @@ func main() { params2 := g.Map { "uid" : 2, "name" : "smith", - "password1" : "456", - "password2" : "456", + "password1" : "111", + "password2" : "222", } if err := gconv.Struct(params2, user); err == nil { fmt.Println(user) diff --git a/geg/util/gconv/gconv_struct2.go b/geg/util/gconv/gconv_struct2.go index 0b3bf6132..c9ad3a369 100644 --- a/geg/util/gconv/gconv_struct2.go +++ b/geg/util/gconv/gconv_struct2.go @@ -1,31 +1,28 @@ package main import ( - "gitee.com/johng/gf/g/util/gconv" - "gitee.com/johng/gf/g" "fmt" + "gitee.com/johng/gf/g" + "gitee.com/johng/gf/g/util/gconv" ) -// 演示slice类型属性的赋值 + +// 使用默认映射规则绑定属性值到对象 func main() { type User struct { - Scores []int + Uid int + Name string + Pass1 string + Pass2 string } - - user := new(User) - scores := []interface{}{99, 100, 60, 140} - - // 通过map映射转换 - if err := gconv.Struct(g.Map{"Scores" : scores}, user); err != nil { - fmt.Println(err) - } else { - g.Dump(user) + user := new(User) + params := g.Map { + "uid" : 1, + "Name" : "john", + "PASS1" : "123", + "PASS2" : "456", } - - // 通过变量映射转换,直接slice赋值 - if err := gconv.Struct(scores, user); err != nil { - fmt.Println(err) - } else { - g.Dump(user) + if err := gconv.Struct(params, user); err == nil { + fmt.Println(user) } } \ No newline at end of file diff --git a/geg/util/gconv/gconv_struct3.go b/geg/util/gconv/gconv_struct3.go index 797ce13db..0b3bf6132 100644 --- a/geg/util/gconv/gconv_struct3.go +++ b/geg/util/gconv/gconv_struct3.go @@ -6,24 +6,23 @@ import ( "fmt" ) +// 演示slice类型属性的赋值 func main() { - type Score struct { - Name string - Result int - } type User struct { - Scores Score + Scores []int } user := new(User) - scores := map[string]interface{}{ - "Scores" : map[string]interface{}{ - "Name" : "john", - "Result" : 100, - }, + scores := []interface{}{99, 100, 60, 140} + + // 通过map映射转换 + if err := gconv.Struct(g.Map{"Scores" : scores}, user); err != nil { + fmt.Println(err) + } else { + g.Dump(user) } - // 嵌套struct转换 + // 通过变量映射转换,直接slice赋值 if err := gconv.Struct(scores, user); err != nil { fmt.Println(err) } else { diff --git a/geg/util/gconv/gconv_struct4.go b/geg/util/gconv/gconv_struct4.go index 99dcb221b..797ce13db 100644 --- a/geg/util/gconv/gconv_struct4.go +++ b/geg/util/gconv/gconv_struct4.go @@ -12,7 +12,7 @@ func main() { Result int } type User struct { - Scores []Score + Scores Score } user := new(User) @@ -23,7 +23,7 @@ func main() { }, } - // 嵌套struct转换,属性为slice类型,数值为map类型 + // 嵌套struct转换 if err := gconv.Struct(scores, user); err != nil { fmt.Println(err) } else { diff --git a/geg/util/gconv/gconv_struct5.go b/geg/util/gconv/gconv_struct5.go index 5e31d47e7..99dcb221b 100644 --- a/geg/util/gconv/gconv_struct5.go +++ b/geg/util/gconv/gconv_struct5.go @@ -17,19 +17,13 @@ func main() { user := new(User) scores := map[string]interface{}{ - "Scores" : []interface{}{ - map[string]interface{}{ - "Name" : "john", - "Result" : 100, - }, - map[string]interface{}{ - "Name" : "smith", - "Result" : 60, - }, + "Scores" : map[string]interface{}{ + "Name" : "john", + "Result" : 100, }, } - // 嵌套struct转换,属性为slice类型,数值为slice map类型 + // 嵌套struct转换,属性为slice类型,数值为map类型 if err := gconv.Struct(scores, user); err != nil { fmt.Println(err) } else { diff --git a/geg/util/gconv/gconv_struct6.go b/geg/util/gconv/gconv_struct6.go new file mode 100644 index 000000000..5e31d47e7 --- /dev/null +++ b/geg/util/gconv/gconv_struct6.go @@ -0,0 +1,38 @@ +package main + +import ( + "gitee.com/johng/gf/g/util/gconv" + "gitee.com/johng/gf/g" + "fmt" +) + +func main() { + type Score struct { + Name string + Result int + } + type User struct { + Scores []Score + } + + user := new(User) + scores := map[string]interface{}{ + "Scores" : []interface{}{ + map[string]interface{}{ + "Name" : "john", + "Result" : 100, + }, + map[string]interface{}{ + "Name" : "smith", + "Result" : 60, + }, + }, + } + + // 嵌套struct转换,属性为slice类型,数值为slice map类型 + if err := gconv.Struct(scores, user); err != nil { + fmt.Println(err) + } else { + g.Dump(user) + } +} \ No newline at end of file