golang中的json标签

golang 中的 json 标签使用

golang 的结构体可以在字段里加 tag,网上资料又看到一句“运行时”通过反射机制读取?这还没研究过,就刚好有需求的时候查一下,记录下遇到的问题和对应的tag使用吧

导出字段名

golang 中结构体,如果要导出(包括序列化、反序列化等),字段名是要大写开头的嘛,一开始没注意,反正就这样定义的结构体

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
type FwItem struct {
	ID        int    `gorm:"column:id;primary_key"`
	TypeID    int    `gorm:"column:typeid"`
	Url       string `gorm:"column:url"`
	Hash      string `gorm:"column:hash"`
	Name      string `gorm:"column:name"`
	ChangeLog string `gorm:"column:changelog"`
	Size      int64  `gorm:"column:size"`
	Serv      int    `gorm:"column:serv"`
	ModelID   int    
	localPath string
	fileType  int
	tf        *TempFile
}

但是这样,用 json.Marshal() 导出的字节数组,再用 string() 输出的字符串是大写开头的,就跟定义里字段名一致

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
    "2": {
        "ChangeLog": "just a change log",
        "Hash": "9BF539D9E1448274992D004A00B994F5",
        "ID": 2,
        "ModelID": 0,
        "Name": "bookinfo3748.json",
        "Serv": 13,
        "Size": 109234,
        "TypeID": 1,
        "Url": "/fileserv/bin/20220922/20/49/3/bookinfo3748.json"
    },
    "3": {
        "ChangeLog": "just two change logs",
        "Hash": "D9F34BB709D97A70F50AB9C6EFB882B2",
        "ID": 3,
        "ModelID": 0,
        "Name": "Education.html",
        "Serv": 13,
        "Size": 28307,
        "TypeID": 2,
        "Url": "/fileserv/bin/20220922/20/54/3/Education.html"
    }
}

要说这样也是没问题的,但是客户端同事说这玩意要小写,我要是字段名起的小写那怎么导出嘛,所以就要加 json tag

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
type FwItem struct {
	ID        int    `gorm:"column:id;primary_key" json:"id"`
	TypeID    int    `gorm:"column:typeid" json:"type_id"`
	Url       string `gorm:"column:url" json:"url"`
	Hash      string `gorm:"column:hash" json:"hash"`
	Name      string `gorm:"column:name" json:"name"`
	ChangeLog string `gorm:"column:changelog" json:"changelog"`
	Size      int64  `gorm:"column:size" json:"size"`
	Serv      int    `gorm:"column:serv" json:"serv"`
	ModelID   int    `gorm:"-" json:"model_id"`
	localPath string
	fileType  int
	tf        *TempFile
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
    "2": {
        "changelog": "just a change log",
        "hash": "9BF539D9E1448274992D004A00B994F5",
        "id": 2,
        "model_id": 0,
        "name": "bookinfo3748.json",
        "serv": 13,
        "size": 109234,
        "type_id": 1,
        "url": "/fileserv/bin/20220922/20/49/3/bookinfo3748.json"
    },
    "3": {
        "changelog": "just two change logs",
        "hash": "D9F34BB709D97A70F50AB9C6EFB882B2",
        "id": 3,
        "model_id": 0,
        "name": "Education.html",
        "serv": 13,
        "size": 28307,
        "type_id": 2,
        "url": "/fileserv/bin/20220922/20/54/3/Education.html"
    }
}

然后导出的字段就是小写了,然后有了下一个问题

有些字段并不需要被序列化出来

在写相关有很多字段的 CURD 接口时,要是每个字段都从post请求里面一个个取出来,再校验,那可太麻烦了,而且又臭又长,垃圾才用的垃圾写法🤡

请求上传的时候整一个 json 参数反序列化成结构实例,实例再通过 gorm:“column:xxx” 就简单好多了,但是有这样的情况,我需要这个字段在反序列化的时候使用(定义的时候字段名大写),在序列化的时候不使用(小写的字段名肯定不被序列化),没法又大写又小写,那不精神分裂嘛

gorm 是有这个 "-" 标签的,就是显式地忽略这个字段,json 果然也有这个用法,而且有个 omitempty ,有些字段是空值,就没必要序列化了(ModelID字段是从网络请求中反序列化后的,加了 gorm:"-" 不保存到数据库,所以从数据库反序列化必然是空值的,序列化完也没意义,但是我在上传的时候又需要这个参数)刚好满足这个需求

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
type Fw__Item struct {
	ID        int    `gorm:"column:id;primary_key" json:"id"`
	TypeID    int    `gorm:"column:typeid" json:"type_id"`
	Url       string `gorm:"column:url" json:"-"`
	Hash      string `gorm:"column:hash" json:"-"`
	Name      string `gorm:"column:name" json:"name"`
	ChangeLog string `gorm:"column:changelog" json:"changelog"`
	Size      int64  `gorm:"column:size" json:"-"`
	Serv      int    `gorm:"column:serv" json:"-"`
	ModelID   int    `gorm:"-" json:"model_id,omitempty"`
	localPath string
	fileType  int
	tf        *TempFile
}

这个导出就很干净了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
    "2": {
        "changelog": "just a change log",
        "id": 2,
        "name": "bookinfo3748.json",
        "type_id": 1
    },
    "3": {
        "changelog": "just two change logs",
        "id": 3,
        "name": "Education.html",
        "type_id": 2
    }
}

还有暂时没用到的标签用法,也记录一下吧,会用上的

inline 用于内嵌的结构体

定义两个结构体,Outer嵌套Project

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
type Project struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

type Outer struct {
	Project `json:"project"`
	Summary string `json:"summary"`
	Desc    string `json:"desc"`
}

打印得序列化一个结构体的json如下:

1
2
3
4
5
6
7
8
{
    "project": {
        "key": "name",
        "value": "坤坤"
    },
    "summary": "ikun summary",
    "desc": "ikun desc"
}

将Outer内Project字段的tag改为 ‘Project json:",inline" ‘,再次打印相同结构体的序列化得json如下:

1
2
3
4
5
6
{
    "key": "name",
    "value": "坤坤",
    "summary": "ikun summary",
    "desc": "ikun desc"
}

相比之前的json,加了inline之后project字段被展开了

尝试一下展开的json能不能反序列化回去

1
2
3
4
5
6
7
8
9
    var outer Outer
	ori := "{\"key\":\"name\",\"value\":\"坤坤\",\"summary\":\"ikun summary\",\"desc\":\"ikun desc\"}"
	err := json.Unmarshal([]byte(ori), &outer)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(outer)
		fmt.Println(outer.Project)
	}

output:

1
2
{{name 坤坤} ikun summary ikun desc}
{name 坤坤}

指定string,number和boolean类型反序列化

没空写了,有空再试下补充

Licensed under CC BY-NC-SA 4.0
this is the way