JSON
JSON是一种轻量级的数据交换格式,易于编写也易于机器解析和生成。
JSON格式可以有效提高网络传输效率。在传输过程中,可以将程序中的数据类型序列化为json字符串,在接收端通过反序列化恢复原来的数据格式。
JSON是一种键值对格式,如下:
{
"name":"小许",
"sex" : "男",
"age" : 18,
"address":["北京","天津","河北"]
}
JSON格式简单、传输速度快,是数据传输的主要格式。基本上,编程语言都支持将编程语言中内置结构的数据转换为json字符串。
序列化
在不同语言中有不同的方式,下面将介绍Java与Go语言的序列化与反序列化。在Java中一切皆对象,所以序列化非常容易,直接继承java.io.Serializable
。一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
public class Person implements java.io.Serializable{
private int id;
private String name;
private String sex;
private String address;
/** 省略setter和getter */
}
继承对象后,可以调用以下函数来序列化Java对象
public final void writeObject(Object x) throws IOException
并通过以下函数反序列化
public final Object readObject() throws IOException, ClassNotFoundException
Go语言对JSON操作的包均在encoding/json
包下,包下提供了Marshal
方法来序列化Go内置对象。Marshal函数返回v的json编码。
func Marshal(v interface{}) ([]byte, error)
//创建结构体
type Person struct {
name string
address string
}
//序列化
per := Person{
name: "钢铁侠",
address: "漫威",
}
perjson, err := json.Marshal(&per)
if err != nil {
panic(err)
}
fmt.Printf("per序列化的json数据为为:%v", perjson)
fmt.Printf("per序列化的json字符串为:%v", string(perjson))
上面的代码中序列化了一个Person对象,但是打印时打印失败。这是因为结构体成员都是小写的,只能在这个包内访问。序列化没有意义,不支持私有类的序列化。
type Person struct {
Name string
Address string
}
将结构体改为公共类时就可以序列化了。
与 Java 万物皆对象的本质不同,Go 除了结构体之外,还有映射、数组、切片等。
//定义一个map类型
func initMap() map[string]string {
var tmp map[string]string = map[string]string{
}
tmp["1"] = "aaa"
tmp["2"] = "bbb"
tmp["3"] = "ccc"
return tmp
}
//对map序列化
a := initMap()
ajson, err := json.Marshal(&a)
if err != nil {
panic("ajson序列化失败")
}
fmt.Printf("%v\n", ajson)
fmt.Println(string(ajson))
//输出序列化时的数据类型
fmt.Printf("%T\n", ajson)
fmt.Printf("%T\n", string(ajson))
可以看出序列化后时一个字节数组,通过string()函数将其转化为字符串,即为json字符串。
Go序列化时tag标签的使用
序列化时,成员变量的名称全部大写。但在实际使用中,需要统一的书写标准和具体的名称,这就需要在序列化时使用标签。
{
"Name":"钢铁侠","Address":"漫威"}
Go语言结构体序列化tag
使用规则是在结构体字段后添加json:"name"
并用反引号包裹。
type Person struct {
Name string `json:"person_name"`
Address string `json:"person_address"`
Age int
}
如果在“名称”和“地址”中使用标签,它们的序列化名称将成为自定义的 person_names。 Age成员不使用标签,因此不会改变。
per := Person{
Name: "钢铁侠",
Address: "漫威",
Age: 18,
}
perjson, err := json.Marshal(&per)
if err != nil {
panic(err)
}
fmt.Printf("per序列化的json数据为为:%v", perjson)
fmt.Printf("per序列化的json字符串为:%v", string(perjson))
struct的tag只会在序列化时起作用不会影响结构体的使用。
反序列化
反序列化就是将序列化后的json字符串或者字节数组转换成编程语言内置的数据结构。这种反序列化可以在相同语言或不同语言中发生。例如Java类被序列化并通过网络传输到前端进行json反序列化,或者任何其他后端语言将内置数据序列化并传输。到前端。
反序列化序列化数据的语言相同,Java实现和Go实现。
/** go语言实现 */
//定义结构体
type Person struct {
Name string `json:"person_name"`
Address string `json:"person_address"`
Age int `json:"person_age"`
}
//序列化
per := Person{
Name: "钢铁侠",
Address: "漫威",
Age: 18,
}
perjson, err := json.Marshal(&per)
if err != nil {
panic(err)
}
fmt.Printf("per序列化的json数据为为:%v", perjson)
fmt.Printf("per序列化的json字符串为:%v", string(perjson))
序列化后为一个字节数组,可以通过string()
方法转化为字符串。
func json.Unmarshal(data []byte, v any) error
该方法时反序列化方法,第一个参数为需要反序列化的字节数组,第二个参数为反序列化后数据的赋值变量。
//反序列化赋值变量
var per1 Person
err1 := json.Unmarshal(perjson, &per1)
if err1 != nil {
panic(err1)
}
fmt.Printf("反序列化的数据per1%s,%s,%d", per1.Name, per1.Address, per1.Age)
str := `{"person_name":"钢铁侠","person_address":"漫威","person_age":18}`
var per2 Person
err2 := json.Unmarshal([]byte(str), &per2)
if err2 != nil {
panic(err2)
}
fmt.Println(per2)
对字符串也可以反序列化,需要将字符串转化为字节数组,通过[]byte()
方法。
/** Java实现 */
//定义类实现序列化接口java.io.Serializable
public class Person implements java.io.Serializable
{
public String name;
public String address;
public int id;
/* getter setter toString ... */
}
//实例化类并序列化类
Person per = new Person();
per.name = "小许";
per.address = "中国";
per.id = 111111;
FileOutputStream fs = new FileOutputStream("./tmp/per.txt");
ObjectOutputStream out = new ObjectOutputStream(fs);
out.writeObject(e);
out.close();
fs.close();
System.out.printf("data is saved in ./tmp/per.txt");
//反序列化
Person e = null;
FileInputStream fileIn = new FileInputStream("./tmp/Person.txt");
ObjectInputStream in = new ObjectInputStream(fileIn);
e = (Person) in.readObject();
in.close();
fileIn.close();
System.out.println("反序列化的对象",e);
System.out.println("name: " + e.name);
System.out.println("address: " + e.address);
System.out.println("id: " + e.id);
这个序列化的字节数组直接存储在文件中。一般情况下是直接通过http协议等网络传输到浏览器,由浏览器内置的解析器,即js进行反序列化。
在前后端交互的过程中主要的数据传输方式就是json字符串串,一般将后端语言的内置对象及数据结构都序列化为json字符串,再由Javascript的JSON,parse()
方法将json字符串转化为js的内置对象。
JS中内置了json字符串与json数据的转化方法,因此只需要再后端语言中将内置数据序列化为json字符串即可,这个过程是统一的,因此诞生了很多序列化工具,仅需少量的代码即可序列化,如阿里巴巴的fastjson
,apache的jackson
等。