Contents
10.4. Json¶
JSON是一种常见的数据交换格式,也是后端编写RESTful风格API时常采用的数据格式。JSON数据格式通常包含两个操作:
序列化(把对象转换成JSON数据类型)
反序列化(把JSON数据类型转换成对象),这是两个互逆的操作。
在Go语言中,json操作的内置库名为
encoding/json,常见的用法如图
10.4.1. 1.Json示例¶
package main
import (
"encoding/json"
"fmt"
)
type JsonExample struct {
//序列化后显示name,如果为空就不显示
Name string `json:"name,omitempty"`
//序列化后显示age
Age int `json:"age"`
//序列化后显示university
School string `json:"university"`
}
//序列化
func JsonMarshal() {
var jex JsonExample
jex = JsonExample{
Name: "Go",
Age: 10,
School: "Google",
}
by, _ := json.Marshal(jex)
fmt.Println(string(by))
}
//反序列化
func JsonUnmarshal() {
var v JsonExample
by := []byte(`{"name":"Go","age":10, "university":"google"}`)
json.Unmarshal(by, &v)
fmt.Println(v)
var vother JsonExample
byOther := []byte(`{"name":"","age":10, "school":"google"}`)
json.Unmarshal(byOther, &vother)
fmt.Println(vother)
}
func main() {
JsonMarshal()
JsonUnmarshal()
}
输出
{"name":"Go","age":10,"university":"Google"}
{Go 10 google}
{ 10 }
使用过程中需注意以下几点:
如果知道反序列化之后的具体结构,那么应该先定义一个符合反序列之后的结构体。
如果不知道反序列化之后的具体结构,那么应该使用interface来表示任意类型。
结构体定义时的标签指定序列化之后的显示,比如上文的json:“name, omitempty”,序列化之后该字段显示name,如果为空值,就不显示(omitempty)。
10.4.2. 2.Json序列化与反序列化¶
import "encoding/json"
json包实现了json对象的编解码。
Marshal函数
Unmarshal函数
Marshal函数返回v的json编码:
type ColorGroup struct {
ID int
Name string
Colors []string
}
group := ColorGroup{
ID: 1,
Name: "Reds",
Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
}
b, err := json.Marshal(group)
if err != nil {
fmt.Println("error:", err)
}
os.Stdout.Write(b)
//{"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
Unmarshal函数解析json编码的数据并将结果存入v指向的值:
var jsonBlob = []byte(`[
{"Name": "Platypus", "Order": "Monotremata"},
{"Name": "Quoll", "Order": "Dasyuromorphia"}
]`)
type Animal struct {
Name string
Order string
}
var animals []Animal
err := json.Unmarshal(jsonBlob, &animals)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("%+v", animals)
//[{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"userName"`
Age int
}
func main() {
u1 := &User{Name: "nick", Age: 18}
u1Str, err := json.Marshal(u1)
fmt.Println(err)
fmt.Println(u1Str)
var u User
err = json.Unmarshal([]byte(u1Str), &u)
fmt.Println(err)
fmt.Println(u)
}
2.1 struct tag介绍:¶
// 字段被本包忽略
Field int `json:"-"`
// 字段在json里的键为"myName"
Field int `json:"myName"`
// 字段在json里的键为"myName"且如果字段为空值将在对象中省略掉
Field int `json:"myName,omitempty"`
// 字段在json里的键为"Field"(默认值),但如果字段为空值会跳过;注意前导的逗号
Field int `json:",omitempty"`
2.2 time时间处理¶
type TimeBirthday time.Time
func (obj TimeBirthday) MarshalJSON() ([]byte, error) {
seconds := time.Time(obj).Format("2006-01-02")
return []byte(fmt.Sprintf(`"%s"`, seconds)), nil
}
type Account struct {
Birthday TimeBirthday `json:"birthday"`
LastLoginTime time.Time `json:"-"`
}
10.4.3. 3.应用案例-Json序列化¶
这里我们介绍一下结构体、map和切片的序列化,其它数据类型的序列化类似。
3.1 Marshal函数¶
代码示例
package main
import (
"encoding/json"
"fmt"
"os"
)
//定义一个结构体
type Monster struct {
Name string `json:"monster_name"` //反射机制
Age int `json:"monster_age"`
Birthday string //....
Sal float64
Skill string
}
func testStruct() {
//演示
monster := Monster{
Name: "牛魔王",
Age: 500,
Birthday: "2011-11-11",
Sal: 8000.0,
Skill: "牛魔拳",
}
//将monster 序列化
data, err := json.Marshal(&monster) //..
if err != nil {
fmt.Printf("序列号错误 err=%v\n", err)
}
//输出序列化后的结果
fmt.Printf("monster序列化后=%v\n", string(data))
// 创建文件,将json数据写入到文件中
file := "info.json"
filePtr, err1 := os.Create(file)
if err1 != nil {
fmt.Println("文件创建失败", err.Error())
return
}
defer filePtr.Close()
// 创建Json编码器
encoder := json.NewEncoder(filePtr)
err = encoder.Encode(string(data))
if err != nil {
fmt.Println("编码错误", err.Error())
} else {
fmt.Printf("json 文件 %s 编码成功\n", file)
}
}
//将map进行序列化
func testMap() {
//定义一个map
var a map[string]interface{}
//使用map,需要make
a = make(map[string]interface{})
a["name"] = "红孩儿"
a["age"] = 30
a["address"] = "洪崖洞"
//将a这个map进行序列化
//将monster 序列化
data, err := json.Marshal(a)
if err != nil {
fmt.Printf("序列化错误 err=%v\n", err)
}
//输出序列化后的结果
fmt.Printf("a map 序列化后=%v\n", string(data))
}
//演示对切片进行序列化, 我们这个切片 []map[string]interface{}
func testSlice() {
var slice []map[string]interface{}
var m1 map[string]interface{}
//使用map前,需要先make
m1 = make(map[string]interface{})
m1["name"] = "jack"
m1["age"] = "7"
m1["address"] = "北京"
slice = append(slice, m1)
var m2 map[string]interface{}
//使用map前,需要先make
m2 = make(map[string]interface{})
m2["name"] = "tom"
m2["age"] = "20"
m2["address"] = [2]string{"墨西哥", "夏威夷"}
slice = append(slice, m2)
//将切片进行序列化操作
data, err := json.Marshal(slice)
if err != nil {
fmt.Printf("序列化错误 err=%v\n", err)
}
//输出序列化后的结果
fmt.Printf("slice 序列化后=%v\n", string(data))
}
//对基本数据类型序列化,对基本数据类型进行序列化意义不大
func testFloat64() {
var num1 float64 = 2345.67
//对num1进行序列化
data, err := json.Marshal(num1)
if err != nil {
fmt.Printf("序列化错误 err=%v\n", err)
}
//输出序列化后的结果
fmt.Printf("num1 序列化后=%v\n", string(data))
}
func main() {
//演示将结构体, map , 切片进行序列号
testStruct()
testMap()
testSlice() //演示对切片的序列化
testFloat64() //演示对基本数据类型的序列化
}
10.4.4. 4.应用案例-JSON反序列化¶
4.1 Unmarshal函数¶
代码示例
我们演示json字符串反序列化成结构体、map和切片
package main
import (
"fmt"
"encoding/json"
)
//定义一个结构体
type Monster struct {
Name string
Age int
Birthday string //....
Sal float64
Skill string
}
//演示将json字符串,反序列化成struct
func unmarshalStruct() {
//说明str 在项目开发中,是通过网络传输获取到.. 或者是读取文件获取到
str := "{\"Name\":\"牛魔王~~~\",\"Age\":500,\"Birthday\":\"2011-11-11\",\"Sal\":8000,\"Skill\":\"牛魔拳\"}"
//定义一个Monster实例
var monster Monster
err := json.Unmarshal([]byte(str), &monster)
if err != nil {
fmt.Printf("unmarshal err=%v\n", err)
}
fmt.Printf("反序列化后 monster=%v monster.Name=%v \n", monster, monster.Name)
}
//将map进行序列化
func testMap() string {
//定义一个map
var a map[string]interface{}
//使用map,需要make
a = make(map[string]interface{})
a["name"] = "红孩儿~~~~~~"
a["age"] = 30
a["address"] = "洪崖洞"
//将a这个map进行序列化
//将monster 序列化
data, err := json.Marshal(a)
if err != nil {
fmt.Printf("序列化错误 err=%v\n", err)
}
//输出序列化后的结果
//fmt.Printf("a map 序列化后=%v\n", string(data))
return string(data)
}
//演示将json字符串,反序列化成map
func unmarshalMap() {
//str := "{\"address\":\"洪崖洞\",\"age\":30,\"name\":\"红孩儿\"}"
str := testMap()
//定义一个map
var a map[string]interface{}
//反序列化
//注意:反序列化map,不需要make,因为make操作被封装到 Unmarshal函数
err := json.Unmarshal([]byte(str), &a)
if err != nil {
fmt.Printf("unmarshal err=%v\n", err)
}
fmt.Printf("反序列化后 a=%v\n", a)
}
//演示将json字符串,反序列化成切片
func unmarshalSlice() {
str := "[{\"address\":\"北京\",\"age\":\"7\",\"name\":\"jack\"}," +
"{\"address\":[\"墨西哥\",\"夏威夷\"],\"age\":\"20\",\"name\":\"tom\"}]"
//定义一个slice
var slice []map[string]interface{}
//反序列化,不需要make,因为make操作被封装到 Unmarshal函数
err := json.Unmarshal([]byte(str), &slice)
if err != nil {
fmt.Printf("unmarshal err=%v\n", err)
}
fmt.Printf("反序列化后 slice=%v\n", slice)
}
func main() {
unmarshalStruct()
unmarshalMap()
unmarshalSlice()
}
10.4.5. 5. Json编解码案例1¶
准备测试数据
data.json
{
"data": {
"directors": [
"奉俊昊"
],
"rate": "8.9",
"cover_x": 1500,
"star": "45",
"title": "寄生虫",
"url": "https://movie.douban.com/subject/27010768/",
"casts": [
"宋康昊",
"李善均",
"赵汝贞",
"崔宇植",
"朴素丹"
]
}
}
json.go
package jsonExplain
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
)
type ResultForJSON struct {
Data struct {
Directors []string `json:"directors"`
Rate string `json:"rate"`
Cover int `json:"cover_x"`
Star string `json:"star"`
Title string `json:"title"`
URL string `json:"url"`
Casts []string `json:"casts"`
} `json:"data"`
}
// 解析json
func ParseJSON() {
file, err := ioutil.ReadFile("data.json")
if err != nil {
log.Println(err)
return
}
var result ResultForJSON
err = json.Unmarshal(file, &result)
if err != nil {
log.Println(err)
return
}
fmt.Println(result)
}
// 封装json
func MarshalJSON() {
var object ResultForJSON
object.Data.Directors = []string{"郑伟文", "陈家霖"}
object.Data.Casts = []string{"肖战", "王一博", "孟子义", "宣璐", "于斌"}
object.Data.Title = "陈情令"
object.Data.Rate = "7.7"
object.Data.Star = "40"
object.Data.Cover = 3000
object.Data.URL = "https://movie.douban.com/subject/27195020/"
content, err := json.Marshal(object)
if err != nil {
log.Println(err)
return
}
fmt.Println(string(content))
}
10.4.6. 6. Json编解码案例2¶
6.1 JSON序列化¶
package main
import (
"encoding/json"
"fmt"
"log"
)
type Movie struct {
Title string
Year int `json:"released"`
Color bool `json:"color,omitempty"`
Actors []string
}
var movies = []Movie{
{Title: "Casablanca", Year: 1942, Color: false,
Actors: []string{"Humphrey Bogart", "Ingrid Bergman"}},
{Title: "Cool Hand Luke", Year: 1967, Color: true,
Actors: []string{"Paul Newman"}},
{Title: "Bullitt", Year: 1968, Color: true,
Actors: []string{"Steve McQueen", "Jacqueline Bisset"}},
}
func main() {
// Marshal
data, err := json.Marshal(movies)
if err != nil {
log.Fatalf("JSON marshaling failed: %s", err)
}
fmt.Printf("%s\n", data)
}
这种类型的结构体最适合JSON,无论是Go转JSON还是从JSON转为Go对象都很容易,转换为JSON结构,使用json.Marshal函数来实现,输出结果:
[{"Title":"Casablanca","released":1942,"Actors":["Humphrey Bogart","Ingrid Bergman"]},{"Title":"Cool Hand Luke","released":1967,"color":true,"Actors":["Paul Newman"]},{"Title":"Bullitt","released":1968,"color":true,"Actors":["Steve McQueen","Jacqueline Bisset"]}]
这种紧凑的包含了所有信息,但是难以阅读。为了方便阅读可以使用 json.MarshalIndent函数来输出整齐格式化的结果。
这个函数有两个参数,一个是定义每行输出的前缀字符串,另外一个是定义缩进的字符串。
// MarshalIndent
data, err := json.MarshalIndent(movies, "", " ")
if err != nil {
log.Fatalf("JSON marshaling failed: %s", err)
}
fmt.Printf("%s\n", data)
上面的代码输出:
[
{
"Title": "Casablanca",
"released": 1942,
"Actors": [
"Humphrey Bogart",
"Ingrid Bergman"
]
},
{
"Title": "Cool Hand Luke",
"released": 1967,
"color": true,
"Actors": [
"Paul Newman"
]
},
{
"Title": "Bullitt",
"released": 1968,
"color": true,
"Actors": [
"Steve McQueen",
"Jacqueline Bisset"
]
}
]
6.2 JSON反序列化¶
将JSON字符串解码为Go数据结构,使用json.Unmarshal函数实现。
mo := &movies
// Unmarshal
if err := json.Unmarshal(data, &mo); err != nil {
log.Fatalf("JSON unmarshaling failed: %s", err)
}
// fmt.Println(*mo)
for _, m := range *mo {
fmt.Println(m.Title)
}