mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
改进gconv.Struct转换默认规则,支持不区分大小写的键名与属性名称匹配
This commit is contained in:
1
TODO
1
TODO
@ -43,7 +43,6 @@ ghttp hook回调使用方式在注册路由比较多的时候,优先级可能
|
||||
gform参考 https://gohouse.github.io/gorose/dist/index.html 进行改进
|
||||
完善配置管理章节,说明默认的配置文件更改方式;
|
||||
完善gform配置管理说明,g.DB/Database和gdb.New的区别;
|
||||
改进gconv.Struct方法,支持不区分大小写的属性-键名匹配,便于开发者执行对象转换;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
38
geg/util/gconv/gconv_struct6.go
Normal file
38
geg/util/gconv/gconv_struct6.go
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user