首页 > 解决方案 > 在 go 中使用通用类型字段解组不同的 JSON 消息

问题描述

我已经基于 TCP 协议在 golang 中实现了一个聊天服务器。客户端到服务器的通信使用 JSON 并使用一个简单的协议,该协议通过换行符 (\n) 分隔消息。有几种有效的消息类型包含不同的字段,但它们都包含一个声明消息类型的通用类型字段。一些示例如下所示。

{"type" : "newidentity", "identity" : "Adel"}
{"type" : "newidentity", "approved" : "true"}
{
"type" : "roomlist",
"rooms" : ["MainHall-s1", "MainHall-s2", "jokes"]
}
{"type" : "createroom", "roomid" : "jokes"}

下面显示了在服务器上处理传入消息的部分(不是实际代码,只是一个示例)。

func handleConnection(c net.Conn) {
    fmt.Print(".")
    for {
        netData, err := bufio.NewReader(c).ReadString('\n')
        if err != nil {
            fmt.Println(err)
            return
        }

        res, err := json.Marshal(IdentitySuccess{MessageType: "newidentity", Approved: "approved"})
        if err != nil {
            fmt.Printf("Error: %v", err)
        }
        c.Write([]byte(string(res) + "\n"))
    }
    c.Close()
}

所以我想从这些 JSON 消息(上面代码片段中的 netData)创建结构并在应用程序中使用这些结构。用公共字段解组这些不同的 JSON 字符串并从中获取结构的最简单方法是什么?所以理想情况下,我想要一个函数,它输出接收到的 JSON 文本的类型和结构。

标签: jsongounmarshalling

解决方案


我建议您不要创建不同的结构,而是使用一个结构并将值解组到其中,在解组值之后,您可以根据您的要求编写自定义处理程序。

同样在上面的示例中,您没有用 . 分隔每条消息\n。但是,如果您在一行中有一条消息,那么您可以做的就是这样。

package main

import (
    "encoding/json"
    "fmt"
    "strings"
)

type IdentitySuccess struct {
    Type     string   `json:"type"`
    Identity string   `json:"identity,omitempty"`
    Approved string   `json:"approved,omitempty"`
    Rooms    []string `json:"rooms,omitempty"`
    Roomid   string   `json:"roomid,omitempty"`
}

func Process(data []byte) (IdentitySuccess, error) {
    var r IdentitySuccess
    err := json.Unmarshal(data, &r)
    return r, err
}

func main() {
    jsonData :=
        `{"type" : "newidentity", "identity" : "Adel"}
         {"type" : "newidentity", "approved" : "true"}
         {"type" : "roomlist","rooms" : ["MainHall-s1", "MainHall-s2", "jokes"]}
         {"type" : "createroom", "roomid" : "jokes"}`
    // Because you are taking \n as a seperator and all of this is coming in one response
    jsons := strings.Split(jsonData, "\n")
    for _, json := range jsons {
        identity, err := Process([]byte(json))
        if err != nil {
            panic(err)
        }
        // Custom handlers will be applied here on the basis of the struct values
        if identity.Type == "newidentity" && identity.Identity != "" {
            fmt.Printf("Got type= %v, with identity = %v\n", identity.Type, identity.Identity)
        } else if identity.Type == "newidentity" && identity.Approved != "" {
            fmt.Printf("Got type= %v, with approved status = %v\n", identity.Type, identity.Approved)
        } else if identity.Type == "roomlist" {
            fmt.Printf("Got type= %v, with rooms = %v\n", identity.Type, identity.Rooms)
        } else if identity.Type == "createroom" {
            fmt.Printf("Got type= %v, with roomid = %v\n", identity.Type, identity.Roomid)
        }
    }

}

上述片段的输出将是这个

Got type= newidentity, with identity = Adel
Got type= newidentity, with approved status = true
Got type= roomlist, with rooms = [MainHall-s1 MainHall-s2 jokes]
Got type=createroom, with roomid = jokes

下面也是操场链接

https://play.golang.org/p/eFPj3z-x39-


推荐阅读