1. 使用标准库
1.1. json序列化相关方法
1. Marshal()
Syntax: func Marshal(v interface{}) ([]byte, error)
Man: 将Go中数据类型转换为 json 字符串的字节切片
2. Unmarshal()
Syntax: func Unmarshal(data []byte, v interface{}) error
Man: 反序列化json字符串
3. Indent()
Syntax: func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error
Man: 缩进显示json字符串
4. Compact()
Syntax: func Compact(dst *bytes.Buffer, src []byte) error
Man: 压缩无效空白符
1.2. json序列化
序列化中需要注意的点:
- 因为是调用
json.Mashal()
,如果结构体字段使用小写将因为不可导出,而无法完成序列化。 json.Mashal()
可以接收指针,因此实际操作中,都是传递指针而不是值如果要对结构体中字段名和json中不一致,需要在结构体定义时指定json中显示的名称
1.2.1. 序列化基本案例
Id和Name有明确指定 json 序列化后的字段名,因此按小写显示
- Hobby中的describe字段小写开头,因此不可导出,在json序列化后的结果中不可见 ```go package main
import ( “encoding/json” “fmt” )
type Student struct {
Id int json:"id"
Name string json:"name"
Hobby []Hobby
}
type Hobby struct { Name string describe string }
func main() { var s0 = Student{ Id: 10001, Name: “张三”, Hobby: []Hobby{ { Name: “游泳”, describe: “游泳。。。。”, }, { Name: “钓鱼”, describe: “台钓”, }, }, } ret, err := json.Marshal(&s0) if err != nil { fmt.Println(“序列化失败”) return } fmt.Println(string(ret)) }
```
[root@heyingsheng models]# go run json/marshal.go
{"id":10001,"name":"张三","Hobby":[{"Name":"游泳"},{"Name":"钓鱼"}]}
1.2.2. 格式化json
package main
import (
"bytes"
"encoding/json"
"fmt"
"strings"
)
func main() {
var str = `{"id":10001,"name":"张三","Hobby":[{"Name":"游泳"},{"Name":"钓鱼"}]}`
// 格式化显示json字符串
var s = bytes.Buffer{}
err := json.Indent(&s, []byte(str), " ", "\t")
if err != nil {
fmt.Println("格式化失败,err=",err)
return
}
ret := s.String()
fmt.Println(ret)
fmt.Println(strings.Repeat("##", 20))
// 压缩无用的空白符号
res := bytes.Buffer{}
err = json.Compact(&res, []byte(ret))
if err != nil {
fmt.Println("格式化失败,err=",err)
return
}
fmt.Println(res.String())
}
[root@heyingsheng models]# go run json/json.go
{
"id": 10001,
"name": "张三",
"Hobby": [
{
"Name": "游泳"
},
{
"Name": "钓鱼"
}
]
}
########################################
{"id":10001,"name":"张三","Hobby":[{"Name":"游泳"},{"Name":"钓鱼"}]}
1.3. json反序列化
1.3.1. 简单反序列化
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name"`
Class []string `json:"class"`
}
func main() {
str := `{"10001": {"name": "张三", "class": ["物理","化学","生物"]}}`
var user01 map[string]User
if err := json.Unmarshal([]byte(str), &user01); err != nil {
fmt.Println("反序列化失败,err=", err)
return
}
fmt.Printf("type:%T, value:%v\n", user01, user01)
fmt.Println(user01["10001"].Class[0])
}
[root@heyingsheng models]# go run json/unmarshal.go
type:map[string]main.User, value:map[10001:{张三 [物理 化学 生物]}]
物理
1.3.2. 使用空接口接收数据
空接口可以接收任何结构的json字符串,但是非常难以转换为可操作的go语言数据类型,因为涉及到类型的断言!
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name"`
Class []string `json:"class"`
}
func main() {
str := `{"10001": {"name": "张三", "class": ["物理","化学","生物"]}}`
var user01 interface{}
if err := json.Unmarshal([]byte(str), &user01); err != nil {
fmt.Println("反序列化失败,err=", err)
return
}
fmt.Printf("type:%T, value:%v\n", user01, user01)
// 使用类型断言才能取值
if user, ok := user01.(map[string]interface {}); ok {
fmt.Printf("type:%T, value:%v\n", user["10001"], user["10001"])
}
}
[root@heyingsheng models]# go run json/unmarshal.go
type:map[string]interface {}, value:map[10001:map[class:[物理 化学 生物] name:张三]]
type:map[string]interface {}, value:map[class:[物理 化学 生物] name:张三]
1.4. json的tag
1.4.1. 忽略字段
type User struct {
Name string `json:"name"`
UID string `json:"uid"`
Address string `json:"-"` // 忽略该字段
Password string `json:"password,omitempty"` // 忽略零值字段
Phone `json:"phone"` // 指定json后,将单层结构转为多层结构
*Score `json:"score,omitempty"` // 如果字段为空则忽略,必须使用结构体指针,否则不行
}
type Phone struct {
TelPhone string `json:"tel_phone,omitempty"`
Mobile string `json:"mobile,omitempty"`
}
type Score struct {
MathScore int `json:"math_score"`
MusicScore int `json:"music_score"`
}
func main() {
user01 := User{
Name: "ZhangSan",
UID: "0001",
Address: "南京",
Password: "",
}
ret, _ := json.Marshal(user01)
fmt.Println(string(ret))
}
[root@duduniao json]# go run main.go
{"name":"ZhangSan","uid":"0001","phone":{}}
1.4.2. 类型转换
在开发中,经常会出现服务调用接口,要求传递json中value为字符串,而代码结构体中为 bool 或者 int等其它类型。这种需求可以通过自定义的方法来实现转换,但是也有根据简单的方法,就是使用 tag 处理。
type Student struct {
Name string `json:"name"`
Age int8 `json:"age,string"`
IsAdmin bool `json:"is_admin,string"`
}
func main() {
s1 := Student{
"张三",
int8(18),
false,
}
ret, _ := json.Marshal(s1)
fmt.Println(string(ret))
fmt.Println(strings.Repeat("--", 20))
str := `{"name":"李四","age":"39","is_admin":"true"}`
_ = json.Unmarshal([]byte(str), &s1)
fmt.Printf("%#v\n", s1)
}
[root@duduniao json]# go run main.go
{"name":"张三","age":"18","is_admin":"false"}
----------------------------------------
main.Student{Name:"李四", Age:39, IsAdmin:true}
2. 使用simpleJson处理json
在对象序列化为 json 字符串时,或者将json对象反序列化并赋值给一个结构体指针,这两种场景很适合使用标准库中得 json 包,但是如果只是从现有得 json 中某一些字段得值,那么可以考虑使用 simplejson 的链式调用完成处理。
2.1. simplejson常用方法
# "github.com/bitly/go-simplejson"
1. Json 结构体
type Json struct {
// contains filtered or unexported fields
}
2. 构造函数
func NewJson(body []byte) (*Json, error)
3. 从 io.Reader 接口构造 Json对象
func NewFromReader(r io.Reader) (*Json, error)
4. 断言相关的方法
func (j *Json) String() (string, error)
func (j *Json) Int() (int, error)
func (j *Json) Int64() (int64, error)
func (j *Json) Uint64() (uint64, error)
func (j *Json) Bool() (bool, error)
func (j *Json) Bytes() ([]byte, error)
func (j *Json) StringArray() ([]string, error)
func (j *Json) Interface() interface{}
func (j *Json) Map() (map[string]interface{}, error)
func (j *Json) Array() ([]interface{}, error)
5. 保证返回指定类型的结果, args 设定默认值
func (j *Json) MustInt(args ...int) int
func (j *Json) MustString(args ...string) string
func (j *Json) MustFloat64(args ...float64) float64
func (j *Json) MustBool(args ...bool) bool
func (j *Json) MustStringArray(args ...[]string) []string
func (j *Json) MustMap(args ...map[string]interface{}) map[string]interface{}
func (j *Json) MustArray(args ...[]interface{}) []interface{}
6. 在map类型中,根据key取值
func (j *Json) Get(key string) *Json
7. 更新json
func (j *Json) Del(key string)
func (j *Json) Set(key string, val interface{})
8. 序列化
func (j *Json) Encode() ([]byte, error)
func (j *Json) EncodePretty() ([]byte, error) // 带缩进
2.2. 案例
测试的 Json 字符串如下
{
"deploy_type":"task",
"uniqid":"task-01",
"labels":{
"deploy_type":"db"
},
"callback_url":"https://xxx.xxx.xxx",
"tasks":[
{
"cluster_type":"vm_cluster",
"deploy_type":"vm_cluster",
"action":"create",
"labels":{
"deploy_type":"cluster"
},
"uniqid":"cluster01",
"name":"cluster01",
"options":{
"cadvisor":true
}
}
]
}
2.2.1. 取值
func main() {
sJson, err := simplejson.NewJson([]byte(str))
if err != nil {
fmt.Printf("New json failed, err:%s\n", err.Error())
return
}
// 取labels
res1 := sJson.Get("labels").Get("deploy_type").MustString("null")
tmp1, _ := json.Marshal(sJson.Get("tasks").MustArray()[0]) // 返回值为 interface,需要重新序列化
tmp2, _ := simplejson.NewJson(tmp1)
res2 := tmp2.Get("labels").Get("deploy_type").MustString()
fmt.Printf("res1:%s,res2:%s\n", res1, res2)
}
2.2.2 修改值
func main() {
sJson, err := simplejson.NewJson([]byte(str))
if err != nil {
fmt.Printf("New json failed, err:%s\n", err.Error())
return
}
// 删除值
sJson.Del("tasks") // 删除task字段
res1, _:= sJson.EncodePretty()
fmt.Println(string(res1))
// 修改值
sJson.Set("labels", false) // 修改labels字段
res2, _:= sJson.EncodePretty()
fmt.Println(string(res2))
}