diff --git a/g/encoding/gjson/gjson.go b/g/encoding/gjson/gjson.go index 85e52524e..683b5f6d8 100644 --- a/g/encoding/gjson/gjson.go +++ b/g/encoding/gjson/gjson.go @@ -8,6 +8,8 @@ package gjson import ( + "sync" + "errors" "strings" "strconv" "io/ioutil" @@ -21,7 +23,8 @@ import ( // json解析结果存放数组 type Json struct { - p *interface{} // 注意这是一个指针 + mu sync.RWMutex + p *interface{} // 注意这是一个指针 } // 编码go变量为json字符串,并返回json字符串指针 @@ -49,7 +52,7 @@ func DecodeToJson (b []byte) (*Json, error) { if v, err := Decode(b); err != nil { return nil, err } else { - return &Json{&v}, nil + return NewJson(&v), nil } } @@ -92,12 +95,12 @@ func LoadContent (data []byte, t string) (*Json, error) { if err := json.Unmarshal(data, &result); err != nil { return nil, err } - return &Json{ &result }, nil + return NewJson(&result), nil } // 将变量转换为Json对象进行处理,该变量至少应当是一个map或者array,否者转换没有意义 func NewJson(v *interface{}) *Json { - return &Json{ v } + return &Json{ p: v } } // 将指定的json内容转换为指定结构返回,查找失败或者转换失败,目标对象转换为nil @@ -132,7 +135,7 @@ func (j *Json) GetMap(pattern string) map[string]interface{} { func (j *Json) GetJson(pattern string) *Json { result := j.Get(pattern) if result != nil { - return &Json{&result} + return NewJson(&result) } return nil } @@ -178,11 +181,13 @@ func (j *Json) GetFloat64(pattern string) float64 { // 根据pattern查找并设置数据 // 注意:写入的时候"."符号只能表示层级,不能使用带"."符号的键名 func (j *Json) Set(pattern string, value interface{}) error { + value = j.convertValue(value) array := strings.Split(pattern, ".") // root节点 if len(array) == 1 { return j.setRoot(pattern, value) } + j.mu.Lock() pointer := j.p length := len(array) for i:= 0; i < length; i++ { @@ -206,28 +211,49 @@ func (j *Json) Set(pattern string, value interface{}) error { if isNumeric(array[i]) { if n, err := strconv.Atoi(array[i]); err == nil { if i == length - 1 { - (*pointer).([]interface{})[n] = value - if len((*pointer).([]interface{})) > n { + if cap((*pointer).([]interface{})) >= n { (*pointer).([]interface{})[n] = value } else { // 注意这里产生了临时变量和赋值拷贝 - array := (*pointer).([]interface{}) - array = append(array, value) - *pointer = array + s := make([]interface{}, n + 1) + copy(s, (*pointer).([]interface{})) + s[n] = value + j.mu.Unlock() + return j.Set(strings.Join(array[0 : i], "."), s) } - break } else { pointer = &(*pointer).([]interface{})[n] } } else { + j.mu.Unlock() return err } + } else { + j.mu.Unlock() + return errors.New("\"" + strings.Join(array[0:i], ".") + "\" is array, invalid index - \"" + array[i] + "\"") } } } + j.mu.Unlock() return nil } +// 数据结构转换,map参数必须转换为map[string]interface{},数组参数必须转换为[]interface{} +func (j *Json) convertValue(value interface{}) interface{} { + switch value.(type) { + case map[string]interface{}: + return value + case []interface{}: + return value + default: + // 这里效率会比较低 + b, _ := Encode(value) + v, _ := Decode(b) + return v + } + return value +} + // 修改根节点数据 func (j *Json) setRoot(pattern string, value interface{}) error { switch (*j.p).(type) { @@ -238,7 +264,7 @@ func (j *Json) setRoot(pattern string, value interface{}) error { if n, err := strconv.Atoi(pattern); err != nil { return err } else { - if len((*j.p).([]interface{})) > n { + if cap((*j.p).([]interface{})) >= n { (*j.p).([]interface{})[n] = value } else { // 注意这里产生了临时变量和赋值拷贝 @@ -256,6 +282,8 @@ func (j *Json) setRoot(pattern string, value interface{}) error { // 返回的结果类型的interface{},因此需要自己做类型转换 // 如果找不到对应节点的数据,返回nil func (j *Json) Get(pattern string) interface{} { + j.mu.RLock() + defer j.mu.RUnlock() if r := j.getPointerByPattern(pattern); r != nil { return *r } @@ -312,6 +340,8 @@ func (j *Json) checkPatternByPointer(pattern string, pointer *interface{}) *inte // 转换为map[string]interface{}类型,如果转换失败,返回nil func (j *Json) ToMap() map[string]interface{} { + j.mu.RLock() + defer j.mu.RUnlock() switch (*(j.p)).(type) { case map[string]interface{}: return (*(j.p)).(map[string]interface{}) @@ -322,6 +352,8 @@ func (j *Json) ToMap() map[string]interface{} { // 转换为[]interface{}类型,如果转换失败,返回nil func (j *Json) ToArray() []interface{} { + j.mu.RLock() + defer j.mu.RUnlock() switch (*(j.p)).(type) { case []interface{}: return (*(j.p)).([]interface{}) @@ -339,18 +371,26 @@ func (j *Json) ToXmlIndent(rootTag...string) ([]byte, error) { } func (j *Json) ToJson() ([]byte, error) { + j.mu.RLock() + defer j.mu.RUnlock() return Encode(*(j.p)) } func (j *Json) ToJsonIndent() ([]byte, error) { + j.mu.RLock() + defer j.mu.RUnlock() return json.MarshalIndent(*(j.p), "", "\t") } func (j *Json) ToYaml() ([]byte, error) { + j.mu.RLock() + defer j.mu.RUnlock() return gyaml.Encode(*(j.p)) } func (j *Json) ToToml() ([]byte, error) { + j.mu.RLock() + defer j.mu.RUnlock() return gtoml.Encode(*(j.p)) } diff --git a/g/encoding/gparser/gparser.go b/g/encoding/gparser/gparser.go new file mode 100644 index 000000000..ce7bc786c --- /dev/null +++ b/g/encoding/gparser/gparser.go @@ -0,0 +1,150 @@ +// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://gitee.com/johng/gf. + +// 数据文件编码/解析. +package gparser + +import ( + "gitee.com/johng/gf/g/encoding/gjson" +) + +type File struct { + json *gjson.Json +} + +func Load (path string) (*File, error) { + if j, e := gjson.Load(path); e == nil { + return &File{j}, nil + } else { + return nil, e + } +} + +// 支持的配置文件格式:xml, json, yaml/yml, toml +func LoadContent (data []byte, fileType string) (*File, error) { + if j, e := gjson.LoadContent(data, fileType); e == nil { + return &File{j}, nil + } else { + return nil, e + } +} + +// 将指定的json内容转换为指定结构返回,查找失败或者转换失败,目标对象转换为nil +// 注意第二个参数需要给的是变量地址 +func (f *File) GetToVar(pattern string, v interface{}) error { + return f.json.GetToVar(pattern, v) +} + +// 获得一个键值对关联数组/哈希表,方便操作,不需要自己做类型转换 +// 注意,如果获取的值不存在,或者类型与json类型不匹配,那么将会返回nil +func (f *File) GetMap(pattern string) map[string]interface{} { + return f.json.GetMap(pattern) +} + +// 获得一个数组[]interface{},方便操作,不需要自己做类型转换 +// 注意,如果获取的值不存在,或者类型与json类型不匹配,那么将会返回nil +func (f *File) GetArray(pattern string) []interface{} { + return f.json.GetArray(pattern) +} + +// 返回指定json中的string +func (f *File) GetString(pattern string) string { + return f.json.GetString(pattern) +} + +// 返回指定json中的bool(false:"", 0, false, off) +func (f *File) GetBool(pattern string) bool { + return f.json.GetBool(pattern) +} + +func (f *File) GetInt(pattern string) int { + return f.json.GetInt(pattern) +} + +func (f *File) GetUint(pattern string) uint { + return f.json.GetUint(pattern) +} + +func (f *File) GetFloat32(pattern string) float32 { + return f.json.GetFloat32(pattern) +} + +func (f *File) GetFloat64(pattern string) float64 { + return f.json.GetFloat64(pattern) +} + +// 根据pattern查找并设置数据 +// 注意:写入的时候"."符号只能表示层级,不能使用带"."符号的键名 +func (f *File) Set(pattern string, value interface{}) error { + return f.json.Set(pattern, value) +} + +// 根据约定字符串方式访问json解析数据,参数形如: "items.name.first", "list.0" +// 返回的结果类型的interface{},因此需要自己做类型转换 +// 如果找不到对应节点的数据,返回nil +func (f *File) Get(pattern string) interface{} { + return f.json.Get(pattern) +} + +// 转换为map[string]interface{}类型,如果转换失败,返回nil +func (f *File) ToMap() map[string]interface{} { + return f.json.ToMap() +} + +// 转换为[]interface{}类型,如果转换失败,返回nil +func (f *File) ToArray() []interface{} { + return f.json.ToArray() +} + +/* 以下为数据文件格式转换,支持类型:xml, json, yaml/yml, toml */ + +func (f *File) ToXml(rootTag...string) ([]byte, error) { + return f.json.ToXml(rootTag...) +} + +func (f *File) ToXmlIndent(rootTag...string) ([]byte, error) { + return f.json.ToXmlIndent(rootTag...) +} + +func (f *File) ToJson() ([]byte, error) { + return f.json.ToJson() +} + +func (f *File) ToJsonIndent() ([]byte, error) { + return f.json.ToJsonIndent() +} + +func (f *File) ToYaml() ([]byte, error) { + return f.json.ToYaml() +} + +func (f *File) ToToml() ([]byte, error) { + return f.json.ToToml() +} + +func VarToXml(value interface{}, rootTag...string) ([]byte, error) { + return gjson.NewJson(&value).ToXml(rootTag...) +} + +func VarToXmlIndent(value interface{}, rootTag...string) ([]byte, error) { + return gjson.NewJson(&value).ToXmlIndent(rootTag...) +} + +func VarToJson(value interface{}) ([]byte, error) { + return gjson.NewJson(&value).ToJson() +} + +func VarToJsonIndent(value interface{}) ([]byte, error) { + return gjson.NewJson(&value).ToJsonIndent() +} + +func VarToYaml(value interface{}) ([]byte, error) { + return gjson.NewJson(&value).ToYaml() +} + +func VarToToml(value interface{}) ([]byte, error) { + return gjson.NewJson(&value).ToToml() +} \ No newline at end of file diff --git a/g/net/ghttp/http_response.go b/g/net/ghttp/http_response.go index 66a2fb2e8..5b4c61fdc 100644 --- a/g/net/ghttp/http_response.go +++ b/g/net/ghttp/http_response.go @@ -8,9 +8,8 @@ package ghttp import ( - "net/http" - "gitee.com/johng/gf/g/encoding/gjson" "sync" + "net/http" ) // 服务端请求返回对象 @@ -21,11 +20,11 @@ type Response struct { } // 返回的固定JSON数据结构 -type ResponseJson struct { - Result int `json:"result"` // 标识消息状态 - Message string `json:"message"` // 消息使用string存储 - Data []byte `json:"data"` // 二进制数据(不管什么数据结构) -} +//type ResponseJson struct { +// Result int `json:"result"` // 标识消息状态 +// Message string `json:"message"` // 消息使用string存储 +// Data []byte `json:"data"` // 二进制数据(不管什么数据结构) +//} // 返回信息(byte) func (r *Response) Write(content []byte) { @@ -42,17 +41,17 @@ func (r *Response) WriteString(content string) { } // 返回固定格式的json -func (r *Response) WriteJson(result int, message string, data []byte) error { - r.Header().Set("Content-Type", "application/json") - r.bufmu.Lock() - defer r.bufmu.Unlock() - if jsonstr, err := gjson.Encode(ResponseJson{ result, message, data }); err != nil { - return err - } else { - r.buffer = append(r.buffer, jsonstr...) - } - return nil -} +//func (r *Response) WriteJson(result int, message string, data []byte) error { +// r.Header().Set("Content-Type", "application/json") +// r.bufmu.Lock() +// defer r.bufmu.Unlock() +// if jsonstr, err := gjson.Encode(ResponseJson{ result, message, data }); err != nil { +// return err +// } else { +// r.buffer = append(r.buffer, jsonstr...) +// } +// return nil +//} // 获取当前缓冲区中的数据 func (r *Response) Buffer() []byte { diff --git a/g/os/gcfg/gcfg.go b/g/os/gcfg/gcfg.go index 9f72aa175..ada781f01 100644 --- a/g/os/gcfg/gcfg.go +++ b/g/os/gcfg/gcfg.go @@ -17,7 +17,7 @@ import ( ) const ( - gDEFAULT_CONFIG_FILE = "config.json" // 默认的配置管理文件名称 + gDEFAULT_CONFIG_FILE = "config.yml" // 默认的配置管理文件名称 ) // 配置管理对象 diff --git a/geg/encoding/json.go b/geg/encoding/json.go index a60ffc64f..59c6e6d30 100644 --- a/geg/encoding/json.go +++ b/geg/encoding/json.go @@ -42,6 +42,59 @@ func testMultiDots() { } } +// 设置数据 +func testSet() { + data := + `{ + "users" : { + "count" : 100 + } + }` + j, err := gjson.DecodeToJson([]byte(data)) + if err != nil { + glog.Error(err) + } else { + j.Set("users.count", 2) + j.Set("users.list", []string{"John", "小明"}) + c, _ := j.ToJson() + fmt.Println(string(c)) + } +} + +// 将Json数据转换为其他数据格式 +func testConvert() { + data := + `{ + "users" : { + "count" : 100, + "list" : ["John", "小明"] + } + }` + j, err := gjson.DecodeToJson([]byte(data)) + if err != nil { + glog.Error(err) + } else { + c, _ := j.ToJson() + fmt.Println("JSON:") + fmt.Println(string(c)) + fmt.Println("======================") + + fmt.Println("XML:") + c, _ = j.ToXmlIndent() + fmt.Println(string(c)) + fmt.Println("======================") + + fmt.Println("YAML:") + c, _ = j.ToYaml() + fmt.Println(string(c)) + fmt.Println("======================") + + fmt.Println("TOML:") + c, _ = j.ToToml() + fmt.Println(string(c)) + } +} + func main() { - testMultiDots() + testConvert() } \ No newline at end of file diff --git a/geg/frame/config.toml b/geg/frame/config.toml new file mode 100644 index 000000000..92ace1c86 --- /dev/null +++ b/geg/frame/config.toml @@ -0,0 +1,24 @@ +# 模板引擎目录 +viewpath = "/home/www/templates/" +# MySQL数据库配置 +[database] + [[database.default]] + host = "127.0.0.1" + port = "3306" + user = "root" + pass = "123456" + name = "test" + type = "mysql" + role = "master" + charset = "utf8" + priority = "1" + [[database.default]] + host = "127.0.0.1" + port = "3306" + user = "root" + pass = "123456" + name = "test" + type = "mysql" + role = "master" + charset = "utf8" + priority = "1" diff --git a/geg/frame/config.xml b/geg/frame/config.xml index f0dfbf90f..fa269ad68 100644 --- a/geg/frame/config.xml +++ b/geg/frame/config.xml @@ -1,6 +1,8 @@ + /home/www/templates/ + 127.0.0.1 diff --git a/geg/frame/config.yml b/geg/frame/config.yml index c19de3fc7..9d5b34cc2 100644 --- a/geg/frame/config.yml +++ b/geg/frame/config.yml @@ -1,20 +1,25 @@ +# 模板引擎目录 viewpath: /home/www/templates/ +# MySQL数据库配置 database: - default: - - host: 127.0.0.1 - port: 3306 - user: root - pass: 123456 - name: test - type: mysql - role: master - priority: 1 - - host: 127.0.0.1 - port: 3306 - user: root - pass: 123456 - name: test - type: mysql - role: master - priority: 1 + default: + - host: 127.0.0.1 + port: 3306 + user: root + pass: 123456 + name: test + type: mysql + role: master + charset: utf-8 + priority: 1 + - host: 127.0.0.1 + port: 3306 + user: root + pass: 123456 + name: test + type: mysql + role: master + charset: utf-8 + priority: 1 + diff --git a/geg/other/test.go b/geg/other/test.go index c1c3bb9e6..6d300483d 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -7,6 +7,10 @@ import ( ) func main() { + j, _ := gjson.Load("/home/john/Workspace/Go/GOPATH/src/gitee.com/johng/gf/geg/frame/config.json") + c, _ := j.ToToml() + fmt.Println(string(c)) + return data := `{ "users" : { @@ -17,12 +21,14 @@ func main() { if err != nil { glog.Error(err) } else { - j.Set("users.count", 1) + //j.Set("users.count", 1) j.Set("users.list", []string{"John", "小明"}) - j.Set("users.0", "a") - fmt.Println(j.Get("users.count")) - fmt.Println(j.Get("users.count")) - //fmt.Println(j.Get("users.list")) + fmt.Println(j.Set("users.list.10", []string{"John", "小明10"})) + fmt.Println(j.Set("users.list.9", []string{"John", "小明9"})) + j.Set("users", "a") + //fmt.Println(j.Get("users.count")) + //fmt.Println(j.Get("users.count")) + fmt.Println(j.Get("users.list.10")) c, _ := j.ToJson() fmt.Println(string(c)) }