文章目录
概要
使用golang对服务器进行部署时,常常涉及对json数据的处理。在golang结构体中提供了json tag,可快速实现对json和struct数据类型之间的快速绑定。本文将探讨golang对json的一些处理技巧
结构体绑定json
使用结构体的tag标签,实现结构体绑定json
- marshal:序列化,将结构体类型转换成为json协议的byte数组
- unmarshal:反序列化,将json协议的byte数组转换成为相应的结构体
type Person struct {
Name string `json:"name"`
Age string `json:"age"`
Weight string `json:"weight"`
}
func transformation() {
data_struct := Person{
Name: "bob",
Age: "23",
Weight: "160",
}
// 将结构体转换成为json
data_byte, _ := json.Marshal(data_struct)
fmt.Printf("str:%v\n", string(data_byte))
var p2 Person
json.Unmarshal(data_byte, &p2)
fmt.Printf("struct:%v\n", p2)
}
结构体绑定json——omitempty标签
编写结构体中,如果绑定的json没有对应字段,结构体的字段将会采用默认值
为了更加严格的规定,给结构体加上omitempty标签,如果绑定的json没有对应字段,结构体中将不会出现该字段
// 在tag中不带omitempty,采用默认值
type Game1 struct {
Name string `json:"name"`
Value string `json:"value"`
}
// 在tag中带omitempty忽略空值
type Game2 struct {
Name string `json:"name"`
Value string `json:"value,omitempty"`
}
func emptyOperation() {
var game1 Game1
var game2 Game2
game1 = Game1{
Name: "bob",
}
game2 = Game2{
Name: "james",
}
game1_json, _ := json.Marshal(game1)
game2_json, _ := json.Marshal(game2)
fmt.Printf("game1 without omitempty:%v\n", string(game1_json))
fmt.Printf("game2 with omitempty:%v\n", string(game2_json))
}
嵌套结构体绑定json
- 匿名嵌套无json标签,序列化之后的json仅有单层结构(非嵌套结构)
- 匿名嵌套带json标签,序列化之后的json有嵌套结构
- 具名嵌套带json标签,序列化之后的json有嵌套结构
// 匿名嵌套,指的是在结构体中不指定字段名,只是指定类型的字段
type User struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
Hobby []string `json:"hobby,omitempty"`
Profile
}
type User2 struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
Hobby []string `json:"hobby,omitempty"`
Profile `json:"profile"`
}
type Profile struct {
Website string `json:"website"`
Slogan string `json:"slogan"`
}
func embededStruct() {
// 匿名嵌套在josn序列化时,会直接输出类型对应的字段(没有相应的嵌套层级)
profile := Profile{
Website: "http://www.baidu.com",
Slogan: "happpy everyday",
}
user := User{
Name: "bob",
Profile: profile,
}
user_json, _ := json.Marshal(user)
fmt.Printf("embededStruct1:%v\n", string(user_json))
// 具名嵌套或者加入tag标签时,会输出有嵌套层级的json结构
user2 := User2{
Name: "james",
Profile: profile,
}
user2_json, _ := json.Marshal(user2)
fmt.Printf("embededStruct2:%v\n", string(user2_json))
}
结构体绑定json——指定解析相应的数据类型
如果struct和json的数据类型不同,但是需要相应的字段进行映射。
此时,可以在标签中指定解析相应的数据类型
// 添加string tag,告诉json包从字符串中解析相应字段的数据
type Card struct {
ID int64 `json:"id,string"`
Score float64 `json:"score,string"`
}
func intAndStringDemo() {
jsonStr1 := `{"id":"233","score":"100"}`
var c1 Card
json.Unmarshal([]byte(jsonStr1), &c1)
fmt.Printf("card:%v\n", c1)
}
结构体绑定json-数据类型转换
由于json中只有number类型,在golang的反序列化过程中,将json的number类型转换为float型
// json协议中没有int、float型,只有number型,在反序列化后,number型将会被转换成为float型
func jsonDemo() {
var m = make(map[string]interface{}, 1)
m["count"] = 1
b, _ := json.Marshal(m)
fmt.Printf("str:%#v\n", string(b))
var m2 map[string]interface{}
json.Unmarshal(b, &m2)
fmt.Printf("value:%v\n", m2["count"])
fmt.Printf("type:%t\n", m2["count"])
}
自定义marshalJSON、unmarshalJSON方法
在json序列化、反序列化的过程中,需要对一些特殊的字段进行处理。我们可以自定义marshalJSON、unmarshalJSON方法,对time的数据类型进行处理(原json的marshal、unmarshal不支持对 "2006-01-02 15:04:05"的时间格式进行处理)
// 自定义marshalJSON方法和unmarshalJSON方法
type Order struct {
ID int `json:"id"`
Title string `json:"title"`
CreatedTime time.Time `json:"created_time"`
}
const layout = "2006-01-02 15:04:05"
// 自定义序列化操作
func (o *Order) MarshalJSON() ([]byte, error) {
type TempOrder Order
return json.Marshal(struct {
CreatedTime string `json:"created_time"`
*TempOrder
}{
CreatedTime: o.CreatedTime.Format(layout),
TempOrder: (*TempOrder)(o),
})
}
// 自定义反序列化操作
func (o *Order) UnmarshalJSON(data []byte) error {
type TempOrder Order
ot := struct {
CreatedTime string `json:"created_time"`
*TempOrder
}{
TempOrder: (*TempOrder)(o),
}
if err := json.Unmarshal(data, &ot); err != nil {
return err
}
var err error
o.CreatedTime, err = time.Parse(layout, ot.CreatedTime)
if err != nil {
return err
}
return nil
}
func customMethodDemo() {
ol := Order{
ID: 123456,
Title: "Go学习之路",
CreatedTime: time.Now(),
}
b, _ := json.Marshal(&ol)
fmt.Printf("str:%s\n", b)
jsonStr := `{"created_time":"2020-04-05 10:18:20","title":"go learning","id":123456}`
var o2 Order
if err := json.Unmarshal([]byte(jsonStr), &o2); err != nil {
fmt.Printf("json.Unmarshal failed, err:%v\n", err)
}
fmt.Printf("o2:%v\n", o2)
}
处理不确定层级的json
如果不确定json的层级,可以使用json.RawMessage进行处理
// 处理不确定层级得json
type sendMSG struct {
User string `json:"user"`
Msg string `json:"msg"`
}
func rawMessageDemo(){
jsonStr:=`{"sendMSG":{"user":"bob", "msg":"golang learn"}, "say":"hello"}`
// 定义一个map,value类型为json.RawMessage,方便后续更加灵活的处理
var data map[string]json.RawMessage
if err:=json.Unmarshal([]byte(jsonStr), &data);err!=nil{
fmt.Printf("json.Umarshal jsonStr failed, err:%v\n", err)
return
}
var msg sendMSG
if err:=json.Unmarshal(data["sendMSG"], &msg);err!=nil{
fmt.Printf("json.Umarshal jsonStr failed, err:%v\n", err)
return
}
fmt.Printf("msg:%v\n", msg)
}
总结
以上是golang对json的一些操作,经常用于服务器开发对json的处理中