JSON操作

一、JSON简介

JSON: JavaScript Object Notation(JavaScript 对象表示法)

JSON 是存储和交换文本信息的语法。类似 XML。

JSON 比 XML 更小、更快,更易解析。

JSON 使用 Javascript语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。 目前非常多的动态(PHP,JSP,.NET)编程语言都支持JSON。

1. JSON语法
JSON 语法规则
  • 数据在名称/值对中
  • 数据由逗号分隔
  • 花括号保存对象
  • 方括号保存数组
JSON 名称/值对

JSON 数据的书写格式是:名称/值对。

名称/值对包括字段名称(在双引号中),后面写一个冒号,然后是值:

“name” : “zhangsan”

这很容易理解,等价于这条 JavaScript 语句:

name = "zhangsan"
JSON 值类型

JSON 值可以是:

  • 字符串(在双引号中)
  • 数字(整数或浮点数)
  • 对象(在花括号中)
  • 数组(在方括号中)
  • 逻辑值(true 或 false)
  • Null
2. JSON的数据结构

JSON有两种数据结构:对象和数组。

JSON对象

对象是一个无序的“‘名称/值’对”集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。

一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。

JSON 对象在花括号中书写:

{ "name":"zhangsan" , "age":24 }

这一点也容易理解,与这条 JavaScript 语句等价:

name = "zhangsan"
age = 24
JSON数组

值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。

JSON 数组在方括号中书写:

数组可包含多个对象:

{
         "people": [
                   { "namr":"zhangsan" , "age":22 },
                   { "name":"lisi" , "age":24 },
                   { "name":"wangwu" , "age":27 }
         ]
}

在上面的例子中,对象 "employees" 是包含三个对象的数组。每个对象代表一条关于某人(有姓和名)的记录。

二、Java 中操作 JSON 数据

网上有很多JAVA种操作JSON的jar包,比较流行的类库Jackson、Gson和FastJSON。

注意:在Maven的中的引用量,FastJSON和Jackson和Gson不在一个数量级,据说是一个代码质量不高的国产类库,还是存在较多的问题的。

这里就介绍下Jackson和Gson。

1. Jackson

Jackson提供了三种可选的JSON处理方法:

流式API

com.fasterxml.jackson.core.JsonParser读 -- 通过JsonFactory构建
com.fasterxml.jackson.core.JsonGenerator写 -- 通过JsonFactory构建

树模型:提供一个 JSON 文档可变内存树的表示形式 

com.fasterxml.jackson.databind.ObjectMapper生成树 ;树组成 JsonNode 节点集
树模型类似于 XML DOM。

数据绑定:JSON和POJO相互转换,基于属性访问器规约或注解

有两种变体:简单和完整的数据绑定

  • 简单数据绑定:是指从Java Map、List、String、Numbers、Boolean和空值进行转换
  • 完整数据绑定:是指从任何Java bean 类型(及上文所述的"简单"类型)进行转换

com.fasterxml.jackson.databind.ObjectMapper对两个变种进行编排(marshalling)处理(写入JSON)和反编排(unmarshalling读JSON)。

3 种方法的用法如下 

  • 流 API: 性能最佳的方式 (最低开销、 速度最快的读/写; 其它二者基于它实现)。
  • 数据绑定 :使用最方便的方式。
  • 树模型: 最灵活的方式。
添加依赖
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.11.0</version>
</dependency>
流API

使用JsonGenerator写入JSON

写入对象

JsonFactory factory = new JsonFactory();
//JsonGenerator 定义公共API编写的Json内容的基类。使用JsonFactory实例的工厂方法创建实例(createGenerator)。
JsonGenerator jsonGenerator = factory.createGenerator(new File("D:\\idea_workspace\\springboot\\ComJava\\src\\main\\resources\\student.json"), JsonEncoding.UTF8);
// {
jsonGenerator.writeStartObject();
// "name" : "harvey"
jsonGenerator.writeStringField("name", "harvey");
// "age" : 20
jsonGenerator.writeNumberField("age", 20);
// "isMan" : false
jsonGenerator.writeBooleanField("isMan", false);
// "marks" : [20, 5, 40]
jsonGenerator.writeFieldName("marks");
// [
jsonGenerator.writeStartArray();
//20, 5, 40
jsonGenerator.writeNumber(20);
jsonGenerator.writeNumber(5);
jsonGenerator.writeNumber(40);
// ]
jsonGenerator.writeEndArray();
// }
jsonGenerator.writeEndObject();
jsonGenerator.close();

写入数组

JsonFactory factory = new JsonFactory();
//JsonGenerator 定义公共API编写的Json内容的基类。使用JsonFactory实例的工厂方法创建实例(createGenerator)。
JsonGenerator jsonGenerator = factory.createGenerator(new File("D:\\idea_workspace\\springboot\\ComJava\\src\\main\\resources\\student.json"), JsonEncoding.UTF8);
// {
jsonGenerator.writeStartObject();;
// "students": []
jsonGenerator.writeFieldName("students");
// [
jsonGenerator.writeStartArray();
//如果有多个对象,这里循环即可
// {
jsonGenerator.writeStartObject();;
// "name" : "harvey"
jsonGenerator.writeStringField("name", "harvey");
// "age" : 20
jsonGenerator.writeNumberField("age", 20);
// "isMan" : false
jsonGenerator.writeBooleanField("isMan", false);
// }
jsonGenerator.writeEndObject();;
// ]
jsonGenerator.writeEndArray();
// }
jsonGenerator.writeEndObject();;
jsonGenerator.close();

使用JsonParser 读取JSON

JsonFactory factory = new JsonFactory();
//JsonParser 定义公共API用于读取的Json内容的基类。使用JsonFactory实例的工厂方法创建实例(createParser)。
JsonParser jsonParser = factory.createParser(new File("D:\\idea_workspace\\springboot\\ComJava\\src\\main\\resources\\student.json"));
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
    //get the current token
    String fieldName = jsonParser.getCurrentName();
    if ("name".equals(fieldName)) {
        //move to next token
        jsonParser.nextToken();
        System.out.println(jsonParser.getText());
    }
    if("age".equals(fieldName)){
        //move to next token
        jsonParser.nextToken();
        System.out.println(jsonParser.getNumberValue());
    }
    if("isMan".equals(fieldName)){
        //move to next token
        jsonParser.nextToken();
        System.out.println(jsonParser.getBooleanValue());
    }
    if("marks".equals(fieldName)){
        //move to [
        jsonParser.nextToken();
        // loop till token equal to "]"
        while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
            System.out.println(jsonParser.getNumberValue());
        }
    }
}
树模型

树到JSON转换

ObjectMapper mapper = new ObjectMapper();
String jsonString = "{\"name\":\"Mahesh Kumar\", \"age\":21,\"verified\":false,\"marks\": [100,90,85]}";
JsonNode rootNode = mapper.readTree(jsonString);

JsonNode nameNode = rootNode.path("name");
System.out.println("Name: "+ nameNode.asText());

JsonNode ageNode = rootNode.path("age");
System.out.println("Age: " + ageNode.asInt());

JsonNode verifiedNode = rootNode.path("verified");
System.out.println("Verified: " + (verifiedNode.asBoolean() ? "Yes":"No"));

JsonNode marksNode = rootNode.path("marks");
Iterator<JsonNode> iterator = marksNode.iterator();
System.out.print("Marks: [ ");
while (iterator.hasNext()) {
    JsonNode marks = iterator.next();
    System.out.print(marks.asInt() + " ");
}
System.out.println("]");
数据绑定

通常都是json字符串与对象的相互转换。

ObjectMapper convertMapper = new ObjectMapper();
//对象转json
convertMapper.writeValueAsString(Object value);
//json转对象
convertMapper.readValue(String content, Class<T> valueType)
对象序列化
Student student = new Student();
student.setAge(10);
student.setName("Harvey");

//对象序列化
ObjectMapper mapper = new ObjectMapper();
//示例一
mapper.writeValue(new File("D:\\idea_workspace\\springboot\\ComJava\\src\\main\\resources\\student.json"), student);
// 还有其他形式
// void writeValue(OutputStream out, Object value)
// void writeValue(Writer w, Object value)
// String writeValueAsString(Object value)
// byte[] writeValueAsBytes(Object value)

//示例二
Student readStudent = mapper.readValue(new File("D:\\idea_workspace\\springboot\\ComJava\\src\\main\\resources\\student.json"), Student.class);
System.out.println(readStudent.getName());
// 还有其他形式
// <T> T readValue(String content, Class<T> valueType)
// <T> T readValue(byte[] src, Class<T> valueType)


//实体类
class Student {
    private String name;
    private int age;
    public Student(){}
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String toString(){
        return "Student [ name: "+name+", age: "+ age+ " ]";
    }
}
2. Gson
添加依赖
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.6</version>
</dependency>
gson实例化的两种方式

第一种

Gson gson  = new Gson();

第二种

Gson gson = new GsonBuilder()
            .setLenient()// json宽松
            .enableComplexMapKeySerialization()//支持Map的key为复杂对象的形式
            .serializeNulls() //智能null
            .setPrettyPrinting()// 调教格式
            .disableHtmlEscaping() //默认是GSON把HTML转义的
            .create();
Bean、Map、List的相互转换

Gson提供了fromJson() 和toJson() 两个直接用于解析和生成的方法,前者实现反序列化,后者实现了序列化;同时每个方法都提供了重载方法。

Gson的注解

注:在Gson中有5类注解 。

@SerializedName注解(JSON字段重命名)

该注解能指定该字段在JSON中对应的字段名称,就是将POJO中的字段与JSON字符串中的字段对应起来。
输出的json使用另外一个名字,默认转换出来的json中和对象的字段是一样的,当然也可以设置成不同,使用SerializedName 注解 。

@Expose注解(字段过滤)

指定哪些是要暴露转换的属性。有时候我们不需要把实体的所有属性都导出,只想把一部分属性导出为Json,或只想对一部分POJO的字段进行反序列化。

@Since(double v) 与 @Until(double v)注解 (版本控制)

有时候我们的实体类会随着版本的升级而修改。一些新的字段是后续加进来的,在新的版本软件中才使用。

JsonAdapter注解 (使用TypeAdapter时的注解)

 

参考

https://www.cnblogs.com/jingmoxukong/p/4664224.html

posted @ 2020-05-24 20:56  codedot  阅读(560)  评论(0编辑  收藏  举报