diff --git a/g/database/gdb/gdb.go b/g/database/gdb/gdb.go index 9a9c61771..fb243c025 100644 --- a/g/database/gdb/gdb.go +++ b/g/database/gdb/gdb.go @@ -13,6 +13,7 @@ import ( "database/sql" "gitee.com/johng/gf/g/util/gconv" "gitee.com/johng/gf/g/util/grand" + "gitee.com/johng/gf/g/util/gutil" _ "github.com/lib/pq" _ "github.com/go-sql-driver/mysql" ) @@ -201,10 +202,15 @@ func newDb (masterNode *ConfigNode, slaveNode *ConfigNode) (*Db, error) { }, nil } +// 将Map变量映射到指定的struct对象中,注意参数应当是一个对象的指针 +func (m Map) ToStruct(obj interface{}) error { + return gutil.MapToStruct(m, obj) +} + // 将结果列表按照指定的字段值做map[string]Map -func (list List) ToStringMap(key string) map[string]Map { +func (l List) ToStringMap(key string) map[string]Map { m := make(map[string]Map) - for _, item := range list { + for _, item := range l { if v, ok := item[key]; ok { m[gconv.String(v)] = item } @@ -213,9 +219,9 @@ func (list List) ToStringMap(key string) map[string]Map { } // 将结果列表按照指定的字段值做map[int]Map -func (list List) ToIntMap(key string) map[int]Map { +func (l List) ToIntMap(key string) map[int]Map { m := make(map[int]Map) - for _, item := range list { + for _, item := range l { if v, ok := item[key]; ok { m[gconv.Int(v)] = item } @@ -224,9 +230,9 @@ func (list List) ToIntMap(key string) map[int]Map { } // 将结果列表按照指定的字段值做map[uint]Map -func (list List) ToUintMap(key string) map[uint]Map { +func (l List) ToUintMap(key string) map[uint]Map { m := make(map[uint]Map) - for _, item := range list { + for _, item := range l { if v, ok := item[key]; ok { m[gconv.Uint(v)] = item } diff --git a/g/encoding/gjson/gjson.go b/g/encoding/gjson/gjson.go index 1f361f921..cb754b314 100644 --- a/g/encoding/gjson/gjson.go +++ b/g/encoding/gjson/gjson.go @@ -16,6 +16,7 @@ import ( "encoding/json" "gitee.com/johng/gf/g/os/gfile" "gitee.com/johng/gf/g/util/gconv" + "gitee.com/johng/gf/g/util/gutil" "gitee.com/johng/gf/g/encoding/gxml" "gitee.com/johng/gf/g/encoding/gyaml" "gitee.com/johng/gf/g/encoding/gtoml" @@ -240,7 +241,7 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error { value = j.convertValue(value) // 初始化判断 if *j.p == nil { - if isNumeric(array[0]) { + if gutil.IsNumeric(array[0]) { *j.p = make([]interface{}, 0) } else { *j.p = make(map[string]interface{}) @@ -267,7 +268,7 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error { goto done } // 创建新节点 - if isNumeric(array[i + 1]) { + if gutil.IsNumeric(array[i + 1]) { // 创建array节点 n, _ := strconv.Atoi(array[i + 1]) var v interface{} = make([]interface{}, n + 1) @@ -287,7 +288,7 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error { case []interface{}: // 键名与当前指针类型不符合,需要执行**覆盖操作** - if !isNumeric(array[i]) { + if !gutil.IsNumeric(array[i]) { if i == length - 1 { *pointer = map[string]interface{}{ array[i] : value } } else { @@ -319,7 +320,7 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error { j.setPointerWithValue(pointer, array[i], value) } } else { - if isNumeric(array[i + 1]) { + if gutil.IsNumeric(array[i + 1]) { n, _ := strconv.Atoi(array[i + 1]) if len((*pointer).([]interface{})) > valn { (*pointer).([]interface{})[valn] = make([]interface{}, n + 1) @@ -346,7 +347,7 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error { if removed && value == nil { goto done } - if isNumeric(array[i]) { + if gutil.IsNumeric(array[i]) { n, _ := strconv.Atoi(array[i]) s := make([]interface{}, n + 1) if i == length - 1 { @@ -518,7 +519,7 @@ func (j *Json) checkPatternByPointer(key string, pointer *interface{}) *interfac return &v } case []interface{}: - if isNumeric(key) { + if gutil.IsNumeric(key) { n, err := strconv.Atoi(key) if err == nil && len((*pointer).([]interface{})) > n { return &(*pointer).([]interface{})[n] @@ -584,12 +585,9 @@ func (j *Json) ToToml() ([]byte, error) { return gtoml.Encode(*(j.p)) } -// 判断所给字符串是否为数字 -func isNumeric(s string) bool { - for i := 0; i < len(s); i++ { - if s[i] < byte('0') || s[i] > byte('9') { - return false - } - } - return true +// 转换为指定的struct对象 +func (j *Json) ToStruct(o interface{}) error { + j.mu.RLock() + defer j.mu.RUnlock() + return gutil.MapToStruct(j.ToMap(), o) } \ No newline at end of file diff --git a/g/encoding/gparser/gparser.go b/g/encoding/gparser/gparser.go index 83dc8ff28..42264490e 100644 --- a/g/encoding/gparser/gparser.go +++ b/g/encoding/gparser/gparser.go @@ -9,7 +9,6 @@ package gparser import ( "gitee.com/johng/gf/g/encoding/gjson" - "encoding/json" ) type Parser struct { @@ -151,12 +150,8 @@ func (p *Parser) ToToml() ([]byte, error) { } // 将变量解析为对应的struct对象,注意传递的参数为struct对象指针 -func (p *Parser) ToStruct(v interface{}) error { - if c, e := p.ToJson(); e == nil { - return json.Unmarshal(c, v) - } else { - return e - } +func (p *Parser) ToStruct(o interface{}) error { + return p.json.ToStruct(o) } func VarToXml(value interface{}, rootTag...string) ([]byte, error) { diff --git a/g/util/gconv/gconv.go b/g/util/gconv/gconv.go index eaad03ecc..1a48832ff 100644 --- a/g/util/gconv/gconv.go +++ b/g/util/gconv/gconv.go @@ -14,6 +14,29 @@ import ( "gitee.com/johng/gf/g/encoding/gbinary" ) +// 将变量i转换为字符串指定的类型t +func Convert(i interface{}, t string) interface{} { + switch t { + case "int": return Int(i) + case "int8": return Int8(i) + case "int16": return Int16(i) + case "int32": return Int32(i) + case "int64": return Int64(i) + case "uint": return Uint(i) + case "uint8": return Uint8(i) + case "uint16": return Uint16(i) + case "uint32": return Uint32(i) + case "uint64": return Uint64(i) + case "float32": return Float32(i) + case "float64": return Float64(i) + case "bool": return Bool(i) + case "string": return String(i) + case "[]byte": return Bytes(i) + default: + return i + } +} + func Bytes(i interface{}) []byte { if i == nil { return nil @@ -233,3 +256,4 @@ func Float64 (i interface{}) float64 { return v } + diff --git a/g/util/gutil/gutil.go b/g/util/gutil/gutil.go index 5eed0b98e..9448bec6e 100644 --- a/g/util/gutil/gutil.go +++ b/g/util/gutil/gutil.go @@ -7,6 +7,33 @@ // 其他工具包 package gutil +import ( + "reflect" + "gitee.com/johng/gf/g/util/gconv" +) + +// 字符串首字母转换为大写 +func UcFirst(s string) string { + if len(s) == 0 { + return s + } + if IsLetterLower(s[0]) { + return string(s[0] - 32) + s[1 :] + } + return s +} + +// 字符串首字母转换为小写 +func LcFirst(s string) string { + if len(s) == 0 { + return s + } + if IsLetterUpper(s[0]) { + return string(s[0] + 32) + s[1 :] + } + return s +} + // 便利数组查找字符串索引位置,如果不存在则返回-1,使用完整遍历查找 func StringSearch (a []string, s string) int { for i, v := range a { @@ -47,3 +74,30 @@ func IsNumeric(s string) bool { } return true } + +// 将map键值对映射到对应的struct对象属性上,需要注意: +// 1、第二个参数为struct对象指针; +// 2、struct对象的公开属性才能被映射赋值; +// 3、map中的键名可以为小写,映射转换时会自动将键名首字母转为大写做匹配映射,如果无法匹配则忽略; +func MapToStruct(m map[string]interface{}, o interface{}) error { + for k, v := range m { + _MapToStructSetField(o, k, v) + } + return nil +} +func _MapToStructSetField(obj interface{}, name string, value interface{}) { + structValue := reflect.ValueOf(obj).Elem() + structFieldValue := structValue.FieldByName(UcFirst(name)) + // 键名与对象属性匹配检测 + if !structFieldValue.IsValid() { + //return fmt.Errorf("No such field: %s in obj", name) + return + } + // CanSet的属性必须为公开属性(首字母大写) + if !structFieldValue.CanSet() { + //return fmt.Errorf("Cannot set %s field value", name) + return + } + // 必须将value转换为struct属性的数据类型,这里必须用到gconv包 + structFieldValue.Set(reflect.ValueOf(gconv.Convert(value, structFieldValue.Type().String()))) +} \ No newline at end of file diff --git a/geg/database/mysql/mysql.go b/geg/database/mysql/mysql.go index 023807aa5..2e6f3a81e 100644 --- a/geg/database/mysql/mysql.go +++ b/geg/database/mysql/mysql.go @@ -445,29 +445,39 @@ func keepPing() { } } -// 数据库单例测试,在mysql中使用 show full processlist 查看链接信息 -func instance() { - fmt.Println("instance:") - db1, _ := gdb.New() - db2, _ := gdb.New() - db3, _ := gdb.New() - for { - fmt.Println("ping...") - db1.PingMaster() - db1.PingSlave() - db2.PingMaster() - db2.PingSlave() - db3.PingMaster() - db3.PingSlave() - time.Sleep(1*time.Second) +// like语句查询 +func likeQuery() { + fmt.Println("likeQuery:") + if r, err := db.Table("user").Where("name like ?", "%john%").Select(); err == nil { + fmt.Println(r) + } else { + fmt.Println(err) } } +// mapToStruct +func mapToStruct() { + type User struct { + Uid int + Name string + } + fmt.Println("mapToStruct:") + if r, err := db.Table("user").Where("uid=?", 1).One(); err == nil { + u := User{} + if err := r.ToStruct(&u); err == nil { + fmt.Println(r) + fmt.Println(u) + } else { + fmt.Println(err) + } + } else { + fmt.Println(err) + } +} + func main() { - r, e := db.Table("user").Where("name like ?", "%john%").Select() - fmt.Println(e) - fmt.Println(r) + mapToStruct() //create() //create() //insert() diff --git a/geg/frame/config.yml b/geg/frame/config.yml index 550d322b1..2cef71b90 100644 --- a/geg/frame/config.yml +++ b/geg/frame/config.yml @@ -6,7 +6,7 @@ database: - host: 127.0.0.1 port: 3306 user: root - pass: "123456" + pass: "8692651" name: test type: mysql role: master @@ -15,7 +15,7 @@ database: - host: 127.0.0.1 port: 3306 user: root - pass: "123456" + pass: "8692651" name: test type: mysql role: master diff --git a/geg/other/reflect.go b/geg/other/reflect.go index e528f6e28..a2a8da6da 100644 --- a/geg/other/reflect.go +++ b/geg/other/reflect.go @@ -13,7 +13,7 @@ type gtInterface interface { type st struct { age int - name string + Name string } type mySt struct { @@ -53,7 +53,7 @@ func main() { //// 我们需要调用的是实体结构体指针的方法,注意v2与v2的区别,以及方法定义的区别 //v2.MethodByName("Echo2").Call([]reflect.Value{p}) //v.MethodByName() - fmt.Println(v.Type()) + fmt.Println(v.FieldByName("name")) diff --git a/geg/other/test.go b/geg/other/test.go index 5aa12c1dc..520578049 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -2,11 +2,10 @@ package main import ( "fmt" - "math/rand" + "gitee.com/johng/gf/g/util/gutil" ) func main() { - for i := 0; i < 100; i++ { - fmt.Println(rand.Intn(200)) - } + fmt.Println(gutil.LcFirst("ABC")) + fmt.Println(gutil.UcFirst("abc")) } \ No newline at end of file