From 1e1f994869c8989ce4ef66347897dd13f7aa9132 Mon Sep 17 00:00:00 2001 From: john Date: Fri, 28 Sep 2018 09:58:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9Bgconv=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E6=96=B9=E6=B3=95=EF=BC=8C=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E4=BF=AE=E6=94=B9gconv.MapToStruct=20->=20gconv.Struct?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- g/container/gvar/gvar.go | 73 +++++++++++++++++++--------- g/database/gdb/gdb_type_record.go | 2 +- g/encoding/gjson/gjson.go | 2 +- g/net/ghttp/ghttp_request_post.go | 2 +- g/net/ghttp/ghttp_request_query.go | 2 +- g/net/ghttp/ghttp_request_request.go | 2 +- g/util/gconv/gconv_struct.go | 58 ++++++++++++++++++---- geg/database/redis/config.tomll | 4 ++ geg/database/redis/config.yml | 4 -- geg/util/gconv/gconv_struct1.go | 4 +- geg/util/gconv/gconv_struct2.go | 13 +++-- geg/util/gconv/gconv_struct3.go | 26 ++++++++++ 12 files changed, 145 insertions(+), 47 deletions(-) create mode 100644 geg/database/redis/config.tomll delete mode 100644 geg/database/redis/config.yml create mode 100644 geg/util/gconv/gconv_struct3.go diff --git a/g/container/gvar/gvar.go b/g/container/gvar/gvar.go index a375e1b1b..c90879840 100644 --- a/g/container/gvar/gvar.go +++ b/g/container/gvar/gvar.go @@ -10,41 +10,68 @@ package gvar import ( "time" "gitee.com/johng/gf/g/util/gconv" + "gitee.com/johng/gf/g/container/gtype" ) type Var struct { - value interface{} + value interface{} // 变量值 + safe bool // 当为true时,value为 *gtype.Interface 类型 } -func New(value...interface{}) *Var { +// 创建一个动态变量,value参数可以为nil +func New(value interface{}, safe...bool) *Var { v := &Var{} - if len(value) > 0 { - v.value = value[0] + if len(safe) > 0 && safe[0] { + v.safe = safe[0] + v.value = gtype.NewInterface(value) + } else { + v.value = value } return v } -func (v *Var) IsNil() bool { return v.value == nil } -func (v *Var) Bytes() []byte { return gconv.Bytes(v.value) } -func (v *Var) String() string { return gconv.String(v.value) } -func (v *Var) Bool() bool { return gconv.Bool(v.value) } +func (v *Var) Set(value interface{}) { + if v.safe { + v.value.(*gtype.Interface).Set(value) + } else { + v.value = value + } +} -func (v *Var) Int() int { return gconv.Int(v.value) } -func (v *Var) Int8() int8 { return gconv.Int8(v.value) } -func (v *Var) Int16() int16 { return gconv.Int16(v.value) } -func (v *Var) Int32() int32 { return gconv.Int32(v.value) } -func (v *Var) Int64() int64 { return gconv.Int64(v.value) } +func (v *Var) Val() interface{} { + if v.safe { + return v.value.(*gtype.Interface).Val() + } else { + return v.value + } +} -func (v *Var) Uint() uint { return gconv.Uint(v.value) } -func (v *Var) Uint8() uint8 { return gconv.Uint8(v.value) } -func (v *Var) Uint16() uint16 { return gconv.Uint16(v.value) } -func (v *Var) Uint32() uint32 { return gconv.Uint32(v.value) } -func (v *Var) Uint64() uint64 { return gconv.Uint64(v.value) } +func (v *Var) IsNil() bool { return v.Val() == nil } +func (v *Var) Bytes() []byte { return gconv.Bytes(v.Val()) } +func (v *Var) String() string { return gconv.String(v.Val()) } +func (v *Var) Bool() bool { return gconv.Bool(v.Val()) } -func (v *Var) Float32() float32 { return gconv.Float32(v.value) } -func (v *Var) Float64() float64 { return gconv.Float64(v.value) } +func (v *Var) Int() int { return gconv.Int(v.Val()) } +func (v *Var) Int8() int8 { return gconv.Int8(v.Val()) } +func (v *Var) Int16() int16 { return gconv.Int16(v.Val()) } +func (v *Var) Int32() int32 { return gconv.Int32(v.Val()) } +func (v *Var) Int64() int64 { return gconv.Int64(v.Val()) } -func (v *Var) Strings() []string { return gconv.Strings(v.value) } +func (v *Var) Uint() uint { return gconv.Uint(v.Val()) } +func (v *Var) Uint8() uint8 { return gconv.Uint8(v.Val()) } +func (v *Var) Uint16() uint16 { return gconv.Uint16(v.Val()) } +func (v *Var) Uint32() uint32 { return gconv.Uint32(v.Val()) } +func (v *Var) Uint64() uint64 { return gconv.Uint64(v.Val()) } -func (v *Var) Time(format...string) time.Time { return gconv.Time(v.value, format...) } -func (v *Var) TimeDuration() time.Duration { return gconv.TimeDuration(v.value) } \ No newline at end of file +func (v *Var) Float32() float32 { return gconv.Float32(v.Val()) } +func (v *Var) Float64() float64 { return gconv.Float64(v.Val()) } + +func (v *Var) Strings() []string { return gconv.Strings(v.Val()) } + +func (v *Var) Time(format...string) time.Time { return gconv.Time(v.Val(), format...) } +func (v *Var) TimeDuration() time.Duration { return gconv.TimeDuration(v.Val()) } + +// 将变量转换为对象,注意 objPointer 参数必须为struct指针 +func (v *Var) Struct(objPointer interface{}, attrMapping...map[string]string) error { + return gconv.Struct(v.Val(), objPointer, attrMapping...) +} \ No newline at end of file diff --git a/g/database/gdb/gdb_type_record.go b/g/database/gdb/gdb_type_record.go index 813c218a7..04e1162b0 100644 --- a/g/database/gdb/gdb_type_record.go +++ b/g/database/gdb/gdb_type_record.go @@ -38,5 +38,5 @@ func (r Record) ToStruct(obj interface{}) error { for k, v := range r { m[k] = v.String() } - return gconv.MapToStruct(m, obj) + return gconv.Struct(m, obj) } diff --git a/g/encoding/gjson/gjson.go b/g/encoding/gjson/gjson.go index 539040d23..cf20e7707 100644 --- a/g/encoding/gjson/gjson.go +++ b/g/encoding/gjson/gjson.go @@ -685,7 +685,7 @@ func (j *Json) ToToml() ([]byte, error) { func (j *Json) ToStruct(o interface{}) error { j.mu.RLock() defer j.mu.RUnlock() - return gconv.MapToStruct(j.ToMap(), o) + return gconv.Struct(j.ToMap(), o) } // 打印Json对象 diff --git a/g/net/ghttp/ghttp_request_post.go b/g/net/ghttp/ghttp_request_post.go index 00c47ef59..f5186112c 100644 --- a/g/net/ghttp/ghttp_request_post.go +++ b/g/net/ghttp/ghttp_request_post.go @@ -146,5 +146,5 @@ func (r *Request) GetPostToStruct(object interface{}, mapping...map[string]strin for k, v := range r.GetPostMap() { params[k] = v } - gconv.MapToStruct(params, object, tagmap) + gconv.Struct(params, object, tagmap) } \ No newline at end of file diff --git a/g/net/ghttp/ghttp_request_query.go b/g/net/ghttp/ghttp_request_query.go index 45826f5aa..3d04ecbfe 100644 --- a/g/net/ghttp/ghttp_request_query.go +++ b/g/net/ghttp/ghttp_request_query.go @@ -145,5 +145,5 @@ func (r *Request) GetQueryToStruct(object interface{}, mapping...map[string]stri for k, v := range r.GetQueryMap() { params[k] = v } - gconv.MapToStruct(params, object, tagmap) + gconv.Struct(params, object, tagmap) } \ No newline at end of file diff --git a/g/net/ghttp/ghttp_request_request.go b/g/net/ghttp/ghttp_request_request.go index 2cc525262..45a0184ab 100644 --- a/g/net/ghttp/ghttp_request_request.go +++ b/g/net/ghttp/ghttp_request_request.go @@ -130,6 +130,6 @@ func (r *Request) GetRequestToStruct(object interface{}, mapping...map[string]st for k, v := range r.GetRequestMap() { params[k] = v } - gconv.MapToStruct(params, object, tagmap) + gconv.Struct(params, object, tagmap) } diff --git a/g/util/gconv/gconv_struct.go b/g/util/gconv/gconv_struct.go index f7a556b6b..f587dd3e9 100644 --- a/g/util/gconv/gconv_struct.go +++ b/g/util/gconv/gconv_struct.go @@ -15,12 +15,37 @@ import ( // 将params键值对参数映射到对应的struct对象属性上,第三个参数mapping为非必需,表示自定义名称与属性名称的映射关系。 // 需要注意: -// 1、第二个参数为struct对象指针; +// 1、第二个参数应当为struct对象指针; // 2、struct对象的**公开属性(首字母大写)**才能被映射赋值; // 3、map中的键名可以为小写,映射转换时会自动将键名首字母转为大写做匹配映射,如果无法匹配则忽略; -func MapToStruct(params map[string]interface{}, object interface{}, mapping...map[string]string) error { +func Struct(params interface{}, objPointer interface{}, attrMapping...map[string]string) error { + isParamMap := true + paramsMap := (map[string]interface{})(nil) + // 先将参数转为 map[string]interface{} 类型 + if m, ok := params.(map[string]interface{}); ok { + paramsMap = m + } else { + paramsMap = make(map[string]interface{}) + if reflect.ValueOf(params).Kind() == reflect.Map { + ks := reflect.ValueOf(params).MapKeys() + vs := reflect.ValueOf(params) + for _, k := range ks { + paramsMap[String(k.Interface())] = vs.MapIndex(k).Interface() + } + } else { + isParamMap = false + } + } + // struct的反射对象 + elem := reflect.ValueOf(objPointer).Elem() + // 如果给定的参数不是map类型,那么直接将参数值映射到第一个属性上 + if !isParamMap { + bindVarToStructByIndex(elem, 0, params) + return nil + } + // 标签映射关系map,如果有的话 tagmap := make(map[string]string) - fields := structs.Fields(object) + fields := structs.Fields(objPointer) // 将struct中定义的属性转换名称构建称tagmap for _, field := range fields { if tag := field.Tag("gconv"); tag != "" { @@ -29,12 +54,11 @@ func MapToStruct(params map[string]interface{}, object interface{}, mapping...ma } } } - elem := reflect.ValueOf(object).Elem() dmap := make(map[string]bool) // 首先按照传递的映射关系进行匹配 - if len(mapping) > 0 && len(mapping[0]) > 0 { - for mappingk, mappingv := range mapping[0] { - if v, ok := params[mappingk]; ok { + if len(attrMapping) > 0 && len(attrMapping[0]) > 0 { + for mappingk, mappingv := range attrMapping[0] { + if v, ok := paramsMap[mappingk]; ok { dmap[mappingv] = true bindVarToStruct(elem, mappingv, v) } @@ -45,13 +69,13 @@ func MapToStruct(params map[string]interface{}, object interface{}, mapping...ma if _, ok := dmap[tagv]; ok { continue } - if v, ok := params[tagk]; ok { + if v, ok := paramsMap[tagk]; ok { dmap[tagv] = true bindVarToStruct(elem, tagv, v) } } // 最后按照默认规则进行匹配 - for mapk, mapv := range params { + for mapk, mapv := range paramsMap { name := gstr.UcFirst(mapk) if _, ok := dmap[name]; ok { continue @@ -78,3 +102,19 @@ func bindVarToStruct(elem reflect.Value, name string, value interface{}) { // 必须将value转换为struct属性的数据类型,这里必须用到gconv包 structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String()))) } + +// 将参数值绑定到对象指定索引位置的属性上 +func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) { + structFieldValue := elem.FieldByIndex([]int{index}) + // 键名与对象属性匹配检测 + if !structFieldValue.IsValid() { + return + } + // CanSet的属性必须为公开属性(首字母大写) + if !structFieldValue.CanSet() { + return + } + // 必须将value转换为struct属性的数据类型,这里必须用到gconv包 + structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String()))) +} + diff --git a/geg/database/redis/config.tomll b/geg/database/redis/config.tomll new file mode 100644 index 000000000..5632e6444 --- /dev/null +++ b/geg/database/redis/config.tomll @@ -0,0 +1,4 @@ +# Redis数据库配置 +[redis] + default = "127.0.0.1:6379,0" + cache = "127.0.0.1:6379,1" \ No newline at end of file diff --git a/geg/database/redis/config.yml b/geg/database/redis/config.yml deleted file mode 100644 index 58a25f98f..000000000 --- a/geg/database/redis/config.yml +++ /dev/null @@ -1,4 +0,0 @@ -# Redis数据库配置 -redis: - default: 127.0.0.1:6379,0 - cache : 127.0.0.1:6379,1 diff --git a/geg/util/gconv/gconv_struct1.go b/geg/util/gconv/gconv_struct1.go index 4230d3230..2e6a971e7 100644 --- a/geg/util/gconv/gconv_struct1.go +++ b/geg/util/gconv/gconv_struct1.go @@ -24,7 +24,7 @@ func main() { "pass1" : "123", "pass2" : "123", } - if err := gconv.MapToStruct(params1, user); err == nil { + if err := gconv.Struct(params1, user); err == nil { fmt.Println(user) } @@ -36,7 +36,7 @@ func main() { "password1" : "456", "password2" : "456", } - if err := gconv.MapToStruct(params2, user); err == nil { + if err := gconv.Struct(params2, user); err == nil { fmt.Println(user) } } \ No newline at end of file diff --git a/geg/util/gconv/gconv_struct2.go b/geg/util/gconv/gconv_struct2.go index bcb40d688..8e833eaef 100644 --- a/geg/util/gconv/gconv_struct2.go +++ b/geg/util/gconv/gconv_struct2.go @@ -15,10 +15,15 @@ func main() { user := new(User) scores := []int{99, 100, 60, 140} - err := gconv.MapToStruct(g.Map{ - "Scores" : scores, - }, user) - if err != nil { + // 通过map映射转换 + if err := gconv.Struct(g.Map{"Scores" : scores}, user); err != nil { + fmt.Println(err) + } else { + g.Dump(user) + } + + // 通过变量映射转换 + if err := gconv.Struct(scores, user); err != nil { fmt.Println(err) } else { g.Dump(user) diff --git a/geg/util/gconv/gconv_struct3.go b/geg/util/gconv/gconv_struct3.go new file mode 100644 index 000000000..cf2e5f6e7 --- /dev/null +++ b/geg/util/gconv/gconv_struct3.go @@ -0,0 +1,26 @@ +package main + +import ( + "gitee.com/johng/gf/g/util/gconv" + "gitee.com/johng/gf/g" + "fmt" +) + +// 演示slice类型属性的赋值 +func main() { + type User struct { + Scores []int + } + + user := new(User) + scores := []int{99, 100, 60, 140} + + err := gconv.Struct(g.Map{ + "Scores" : scores, + }, user) + if err != nil { + fmt.Println(err) + } else { + g.Dump(user) + } +} \ No newline at end of file