一、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时的注解)
参考