Golang中如何移除JSON输出对象的顶层字段名但保留其属性
Golang中如何移除JSON输出对象的顶层字段名但保留其属性 我正在实现Go API并获取JSON对象作为输出。我得到的输出如下:
{
"entityId": "5f1",
"entries": [
{
"Fruit": {
"name": "1cd9",
"location": "5f1",
"ID": "7b9",
"creationDate": "2019-06-26T18:27:10",
"lastUpdatedDate": "2019-06-26T18:27:28",
"startDate": "2019-06-26T08:00:00",
"endDate": "2019-06-26T08:00:00",
"entryType": 1
}
},
{
"Fruit": {
"name": "1c9",
"location": "51",
"ID": "79",
"creationDate": "2019-06-26T18:27:10",
"lastUpdatedDate": "2019-06-26T18:27:28",
"startDate": "2019-06-26T08:00:00",
"endDate": "2019-06-26T08:00:00",
"entryType": 1
},
}]
}
但是,我想要这样的输出:
{
"entityId": "5f1",
"entries": [
{
"name": "1cd9",
"location": "5f1",
"ID": "7b9",
"creationDate": "2019-06-26T18:27:10",
"lastUpdatedDate": "2019-06-26T18:27:28",
"startDate": "2019-06-26T08:00:00",
"endDate": "2019-06-26T08:00:00",
"entryType": 1
},
{
"name": "1c9",
"location": "51",
"ID": "79",
"creationDate": "2019-06-26T18:27:10",
"lastUpdatedDate": "2019-06-26T18:27:28",
"startDate": "2019-06-26T08:00:00",
"endDate": "2019-06-26T08:00:00",
"entryType": 1
}]
}
我在proto3文件中的数据模型是:
message Entry{
oneof Type {
Fruit fruit = 1;
Animal animals = 2;
Bird birds = 3;
}
}
我尝试在proto中使用oneof类型,并在后端的Go文件中使用嵌套消息来填充模型。MySQL是我的数据库。
var allmt pb.TypesResponse
for i := 0; i < len(dbEntries); i++ {
mt := &pb.TypesResponse{
Entries: []*pb.Entry{{
Type: &pb.Entry_Fruit{
dbEntries[i],
},
},
},
}
allmt.Entries = append(allmt.Entries, mt.Entries[0])
}
请帮助我实现扁平的JSON对象。
更多关于Golang中如何移除JSON输出对象的顶层字段名但保留其属性的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang中如何移除JSON输出对象的顶层字段名但保留其属性的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中处理protobuf生成的JSON输出时,可以使用json.RawMessage和自定义JSON序列化来实现移除顶层字段名的需求。以下是解决方案:
package main
import (
"encoding/json"
"fmt"
)
// 定义Fruit结构体,使用protobuf标签
type Fruit struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Location string `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"`
ID string `protobuf:"bytes,3,opt,name=ID,proto3" json:"ID,omitempty"`
CreationDate string `protobuf:"bytes,4,opt,name=creationDate,proto3" json:"creationDate,omitempty"`
LastUpdatedDate string `protobuf:"bytes,5,opt,name=lastUpdatedDate,proto3" json:"lastUpdatedDate,omitempty"`
StartDate string `protobuf:"bytes,6,opt,name=startDate,proto3" json:"startDate,omitempty"`
EndDate string `protobuf:"bytes,7,opt,name=endDate,proto3" json:"endDate,omitempty"`
EntryType int32 `protobuf:"varint,8,opt,name=entryType,proto3" json:"entryType,omitempty"`
}
// 自定义Entry类型来处理JSON序列化
type Entry struct {
Type interface{} `json:"-"`
}
// 实现json.Marshaler接口
func (e Entry) MarshalJSON() ([]byte, error) {
return json.Marshal(e.Type)
}
// 主响应结构体
type TypesResponse struct {
EntityID string `protobuf:"bytes,1,opt,name=entityId,proto3" json:"entityId,omitempty"`
Entries []Entry `protobuf:"bytes,2,rep,name=entries,proto3" json:"entries,omitempty"`
}
func main() {
// 模拟从数据库获取的数据
dbEntries := []Fruit{
{
Name: "1cd9",
Location: "5f1",
ID: "7b9",
CreationDate: "2019-06-26T18:27:10",
LastUpdatedDate: "2019-06-26T18:27:28",
StartDate: "2019-06-26T08:00:00",
EndDate: "2019-06-26T08:00:00",
EntryType: 1,
},
{
Name: "1c9",
Location: "51",
ID: "79",
CreationDate: "2019-06-26T18:27:10",
LastUpdatedDate: "2019-06-26T18:27:28",
StartDate: "2019-06-26T08:00:00",
EndDate: "2019-06-26T08:00:00",
EntryType: 1,
},
}
// 构建响应
var allmt TypesResponse
allmt.EntityID = "5f1"
for i := 0; i < len(dbEntries); i++ {
entry := Entry{
Type: dbEntries[i],
}
allmt.Entries = append(allmt.Entries, entry)
}
// 序列化为JSON
jsonData, err := json.MarshalIndent(allmt, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(jsonData))
}
如果你需要保持protobuf生成的结构体,可以使用以下方法:
// 使用protobuf生成的结构体时,创建自定义的JSON序列化
type CustomEntry struct {
*pb.Entry
}
func (ce CustomEntry) MarshalJSON() ([]byte, error) {
// 根据oneof类型提取具体对象
switch v := ce.Entry.Type.(type) {
case *pb.Entry_Fruit:
return json.Marshal(v.Fruit)
case *pb.Entry_Animal:
return json.Marshal(v.Animal)
case *pb.Entry_Bird:
return json.Marshal(v.Bird)
default:
return json.Marshal(nil)
}
}
// 在构建响应时使用CustomEntry
var allmt struct {
EntityID string `json:"entityId"`
Entries []CustomEntry `json:"entries"`
}
allmt.EntityID = "5f1"
for i := 0; i < len(dbEntries); i++ {
entry := &pb.Entry{
Type: &pb.Entry_Fruit{
Fruit: dbEntries[i],
},
}
allmt.Entries = append(allmt.Entries, CustomEntry{Entry: entry})
}
输出结果将是:
{
"entityId": "5f1",
"entries": [
{
"name": "1cd9",
"location": "5f1",
"ID": "7b9",
"creationDate": "2019-06-26T18:27:10",
"lastUpdatedDate": "2019-06-26T18:27:28",
"startDate": "2019-06-26T08:00:00",
"endDate": "2019-06-26T08:00:00",
"entryType": 1
},
{
"name": "1c9",
"location": "51",
"ID": "79",
"creationDate": "2019-06-26T18:27:10",
"lastUpdatedDate": "2019-06-26T18:27:28",
"startDate": "2019-06-26T08:00:00",
"endDate": "2019-06-26T08:00:00",
"entryType": 1
}
]
}
这种方法通过实现自定义的MarshalJSON方法,在序列化时直接输出内部对象的属性,从而移除了顶层的"Fruit"字段名。

