JSON(JavaScript Object Notation,JS对象简谱)是一种轻量级的数据交换格式。它基于 ECMAScript(欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据,但是也使用了类似于 C 语言家族的习惯(包括 C
, C++
, C#
, Java
, JavaScript
, Perl
, Python
等)。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
JSON的本质就是一个对象序列化后的字符串
JSON广泛应用于Web开发和数据交换。它是一种通用的数据格式,常用于前后端之间的数据传输,如将服务器返回的数据转换为JSON格式在客户端进行处理。
在Java中,常用的JSON库包括Jackson
,fastjson
等,它们提供了方便的API来解析、生成和操作JSON数据。
JSON使用类似于JavaScript的语法规则,包括对象和数组的表示方式。
{
"name": "John",
"age": 30,
"isStudent": true,
"address": {
"street": "123 Main St",
"city": "New York"
},
"hobbies": ["reading", "coding", "traveling"]
}
"Hello, World!"
42
3.14
true
false
由键值对组成的无序集合。
{
"name": "John",
"age": 30
}
由值组成的有序集合
["red", "green", "blue"]
null
// json字符串转js对象
var jsObj = JSON.parse(jsonStr)
// js对象转json字符串
var jsonStr = JSON.stringify(jsObj)
Jackson是Java中一个流行的JSON处理库,它提供了一组功能强大的API,用于解析、生成和操作JSON数据,具有以下特点
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
Jackson 最常用的 API 就是基于对象绑定的 ObjectMapper
public class Stu {
private String name;
private int age;
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;
}
}
String json = "{\"name\": \"lucy\",\"age\": 18}";
ObjectMapper objectMapper = new ObjectMapper();
// 字符串转Object
Stu s1 = objectMapper.readValue(json, Stu.class);
System.out.println(s1);
// 字符输入流转Object
StringReader reader = new StringReader(json);
Stu s2 = objectMapper.readValue(reader, Stu.class);
System.out.println(s1);
// json文件转Object
File file = new File("stu.json");
Stu s3 = objectMapper.readValue(file, Stu.class);
System.out.println(s3);
// url读取json转Object
URL url = new URL("http://localhost/stu.json");
Stu s4 = objectMapper.readValue(url, Stu.class);
System.out.println(s4);
// 字节输入流转Object
InputStream inputStream = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
Stu s5 = objectMapper.readValue(inputStream, Stu.class);
System.out.println(s5);
// 字节数组转Object
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
Stu s6 = objectMapper.readValue(bytes, Stu.class);
System.out.println(s6);
String jsonArray = "[\"lucy\",\"tom\",\"grady\"]";
// json转List
List<String> list = objectMapper.readValue(jsonArray, new TypeReference<List<String>>() {});
System.out.println(list);
// json转Map
Map<String,Object> map = objectMapper.readValue(json,new TypeReference<Map<String,Object>>() {});
System.out.println(map);
有时候,与要从JSON读取的Java对象相比,JSON中的字段更多。 默认情况下,Jackson在这种情况下会抛出异常UnrecognizedPropertyException
,因为在Java对象中找不到该字段。
但是,有时应该允许JSON中的字段多于相应的Java对象中的字段。 例如,要从REST服务解析JSON,而该REST服务包含的数据远远超出所需的。 在这种情况下,可以使用Jackson配置忽略这些额外的字段。 以下是配置Jackson ObjectMapper忽略未知字段的示例:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
如果Java对象的某个属性为基本数据类型,但是对应的json中该属性为null
,那么Jackson默认会忽略这个字段。我们可以通过配置,在基本属性值为null的情况下,抛出异常
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
ObjectMapper objectMapper = new ObjectMapper();
Stu stu = new Stu();
stu.setAge(18);
stu.setName("lucy");
String s = objectMapper.writeValueAsString(stu);
System.out.println(s);
默认情况下,Jackson会将java.util.Date
对象序列化为其long型的值,该值是自1970年1月1日以来的毫秒数。
public class MyObj {
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
MyObj myObj = new MyObj();
myObj.setDate(new Date());
ObjectMapper objectMapper = new ObjectMapper();
// 序列化
String s = objectMapper.writeValueAsString(myObj);
System.out.println(s); // {"date":1689043359773}
// 反序列化
MyObj mo = objectMapper.readValue(s, MyObj.class);
System.out.println(mo); // MyObj{date=Tue Jul 11 10:43:35 CST 2023}
对于实体类如果需要序列化以及序列化使用自定义格式,那么可以使用@JsonFormat
注解进行定义,该注解可以作用于方法、属性。
public class MyObj {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "Asia/Shanghai")
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
MyObj myObj = new MyObj();
myObj.setDate(new Date());
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(myObj);
System.out.println(s); // {"date":"2023-07-11 10:49:02"}
MyObj mo = objectMapper.readValue(s, MyObj.class);
Date date = mo.getDate();
System.out.println(mo); // MyObj{date=Tue Jul 11 10:49:02 CST 2023}
例如自定义一个Double类型保留两位小数的序列化器
//修改JsonSerializer<Double> 到需要的类型,默认为JsonSerializer,参数为Object value
public class JsonSerializerUtils extends JsonSerializer<Double> {
@Override
public void serialize(Double value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if (Objects.nonNull(value)) {
//保留2位小数#代表末位是0舍去
DecimalFormat decimalFormat = new DecimalFormat("0.##");
//四舍五入
decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
String result = decimalFormat.format(value);
jsonGenerator.writeNumber(Double.valueOf(result));
} else {
jsonGenerator.writeNumber(Double.valueOf(0));
}
}
}
在需要进行格式化的实体类属性上添加注解
@JsonSerialize(using = JsonSerializerUtils.class)
private Double waterPrice;
作用范围:序列化及反序列化
Jackson注解@JsonIgnore用于告诉Jackson忽略Java对象的某个属性(字段)。
public class Stu {
private String name;
@JsonIgnore
private int age;
}
作用范围:序列化及反序列化
用于指定要忽略的类的属性列表。
@JsonIgnoreProperties({"id","age"})
public class Stu {
private int id;
private String name;
private int age;
}
作用范围:序列化及反序列化
用于将整个类型(类)标记为在使用该类型的任何地方都将被忽略。
@JsonIgnoreType
public class Stu {
private String name;
private int age;
}
用于告诉Jackson在读写对象时包括非public修饰的属性。
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY )
public class Stu {
private String name;
public int age;
}
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.7</version>
</dependency>
如果对象中属性为null,则不转化
String json = JSON.toJSONString(javaObject);
需要该类具有无参构造器
Person newPerson = JSON.parseObject(jsonString, Person.class);
JSONArray jsonArray = (JSONArray)JSON.toJSON(list);