JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,相比xml数据交换格式来说,因为解析xml比较的复杂且需要编写大段的代码,所以客户端和服务器的数据交换格式往往通过JSON来进行交换。
json简单说就是javascript中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结构可以表示各种复杂的结构。
常用JSON解析框架
fastjson(阿里)
gson(谷歌)
jackson(SpringMVC自带)
XML与JSON的区别
Xml是重量级数据交换格式,占宽带比较大。
JSON是轻量级交换格式,占宽带小。
添加对fastjson的Maven依赖
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
//把JSON文本parse为JSONObject或者JSONArray
public static final Object parse(String text);
//把JSON文本parse成JSONObject
public static final JSONObject parseObject(String text);
//把JSON文本parse为JavaBean
public static final <T> T parseObject(String text, Class<T> clazz);
//把JSON文本parse成JSONArray
public static final JSONArray parseArray(String text);
//把JSON文本parse成JavaBean集合
public static final <T> List<T> parseArray(String text, Class<T> clazz);
//将JavaBean序列化为JSON文本
public static final String toJSONString(Object object);
//将JavaBean序列化为带格式的JSON文本
public static final String toJSONString(Object object, boolean prettyFormat);
//将JavaBean转换为JSONObject或者JSONArray。
public static final Object toJSON(Object javaObject);
public static void main(String[] args) {
String userJson = "{\"users\":[{\"name\":\"小白\",\"age\":\"12\"},{\"name\":\"大白\",\"age\":\"22\"}]}";
//将json字符串转换为jsonObject
JSONObject parseObject = JSON.parseObject(userJson);
// 获取json数组对象
JSONArray usersArray = parseObject.getJSONArray("users");
for (Object object : usersArray) {
JSONObject jsonObejct = (JSONObject) object;
String name = jsonObejct.getString("name");
String age = jsonObejct.getString("age");
System.out.println(name + "----" + age);
}
}
public static void main(String[] args) {
JSONObject jsonObject = new JSONObject();
JSONArray usersArray = new JSONArray();
JSONObject user1 = new JSONObject();
user1.put("name", "小白");
user1.put("age", "12");
usersArray.add(user1);
JSONObject user2 = new JSONObject();
user2.put("name", "大白");
user2.put("age", "22");
usersArray.add(user2);
jsonObject.put("users", usersArray);
System.out.println(jsonObject.toJSONString());
}
{"users":[{"age":"12","name":"小白"},{"age":"22","name":"大白"}]}
Gson是Java序列化/反序列化库,用于将 Java 对象转换为JSON并返回。 Gson由Google创建,供内部使用,后来开源。
Gson具有三种API:数据绑定 API、树模型 API、流 API
数据绑定 API 使用属性访问器将JSON与POJO之间进行转换。 Gson使用数据类型适配器处理 JSON 数据。 它类似于XML JAXB解析器。
树模型 API创建JSON 文档的内存树表示。 它构建JsonElements的树。 它类似于XML DOM解析器。
流 API是一种低级 API,它使用JsonReader和JsonWriter作为离散记号读取和写入 JSON 内容。 这些类将数据读取为JsonTokens。 该 API 具有最低的开销,并且在读/写操作中速度很快。 它类似于 XML 的 Stax 解析器
添加对Gson的Maven依赖
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>
Gson是使用Gson库的主要类
toJson()方法将指定的对象序列化为其等效的JSON表示形式
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
Gson gson = new Gson();
String output = gson.toJson(map);
System.out.println(output);
}
{"1":"a","2":"b","3":"c"}
fromJson()方法将JSON读取到Java对象中
public static void main(String[] args) {
String json_string = "{\"username\":\"Jack\", \"age\": \"20\"}";
Gson gson = new Gson();
User user = gson.fromJson(json_string, User.class);
System.out.println(user);
}
@ToString
@AllArgsConstructor
class User {
private String username;
private String age;
}
GsonBuilder可使用各种配置设置构建Gson。GsonBuilder遵循构建器模式,通常通过首先调用各种配置方法来设置所需的选项,最后调用create()来使用它。
public static void main(String[] args) throws UnsupportedEncodingException {
try (PrintStream prs = new PrintStream(System.out, true, "UTF8")) {
Gson gson = new GsonBuilder()
// 配置Gson在序列化和反序列化期间将特定的命名策略应用于对象的字段。
// 字段命名策略设置为FieldNamingPolicy.UPPER_CAMEL_CASE: 确保Java字段名称的第一个“字母”在序列化为其JSON形式时大写
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
.create();
User user = new User("Jack", 20);
gson.toJson(user, prs);
}
}
@ToString
@AllArgsConstructor
static
class User {
private String username;
private Integer age;
}
{"Username":"Jack","Age":20}
将JSON数据写入一个json文件。
public static void main(String[] args) throws IOException {
String filePath = "src/main/resources/users.json";
try (FileOutputStream fos = new FileOutputStream(filePath);
OutputStreamWriter isr = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
Gson gson = new Gson();
User user1 = new User("Jack", 23);
User user2 = new User("Jon", 22);
User user3 = new User("Tom", 33);
List<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);
gson.toJson(users, isr);
将json文件中的JSON数据读取到数组中,并打印到控制台。
public static void main(String[] args) throws IOException {
String filePath = "src/main/resources/users.json";
Path path = new File(filePath).toPath();
try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
User[] users = new Gson().fromJson(reader, User[].class);
Arrays.stream(users).forEach(e -> System.out.println(e));
}
}
ApplicationTests.User(username=Jack, age=23)
ApplicationTests.User(username=Jon, age=22)
ApplicationTests.User(username=Tom, age=33)
public static void main(String[] args) throws IOException {
String url = "xxx";
try (InputStream is = new URL(url).openStream();
Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
Gson gson = new Gson();
User user = gson.fromJson(reader, User.class);
System.out.println(user);
}
}
Gson 有两种输出模式:紧凑和漂亮。通过setPrettyPrinting()方法设置漂亮的打印模式。
public static void main(String[] args) {
Gson gson1 = new GsonBuilder().create();
Gson gson2 = new GsonBuilder().setPrettyPrinting().create();
Map<Integer, String> map = new HashMap<>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
gson1.toJson(map, System.out);
System.out.println("");
gson2.toJson(map, System.out);
}
{"1":"a","2":"b","3":"c"}
{
"1": "a",
"2": "b",
"3": "c"
}
默认情况下,Gson 不会将具有空值的字段序列化为 JSON。 如果 Java 对象中的字段为null,则 Gson 会将其排除。 我们可以使用serializeNulls()方法强制 Gson 通过 GsonBuilder 序列化null值。
public static void main(String[] args) {
Gson gson1 = new GsonBuilder().create();
Gson gson2 = new GsonBuilder().serializeNulls().create();
User user = new User("Jack", null);
System.out.println(gson1.toJson(user));
System.out.println(gson2.toJson(user));
}
{"username":"Jack"}
{"username":"Jack","age":null}
@Expose注解指定那些成员公开以进行JSON序列化或反序列化
@Expose注解可以采用两个布尔参数:serialize和deserialize进行控制
必须使用excludeFieldsWithoutExposeAnnotation()方法显式启用@Expose注解
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
User user = new User("Jack", 23);
gson.toJson(user, System.out);
}
@ToString
@AllArgsConstructor
static
class User {
@Expose
private String username;
private Integer age;
}
{"username":"Jack"}
Jackson有三个核包,分别是 Streaming、Databid、Annotations,通过这些包可以方便的对 JSON 进行操作。
Streaming (opens new window)在 jackson-core 模块。 定义了一些流处理相关的 API 以及特定的 JSON 实现。
Annotations (opens new window)在 jackson-annotations 模块,包含了 Jackson 中的注解。
Databind (opens new window)在 jackson-databind 模块, 在 Streaming 包的基础上实现了数据绑定,依赖于 Streaming 和 Annotations 包。
jackson-databind依赖 jackson-core 和 jackson-annotations,所以可以只显示地添加jackson-databind依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.4</version>
</dependency>
ObjectMapper是Jackson 库中最常用的一个类,使用它可以进行 Java 对象和JSON字符串之间快速转换
readValue() 方法:进行JSON 的反序列化操作,比如可以将字符串、文件流、字节流、字节数组等将常见的内容转换成 Java 对象。
writeValue() 方法:进行JSON 的序列化操作,可以将 Java 对象转换成 JSON 字符串。
ObjectMapper的工作原理是通过 Java Bean 对象的 Get/Set 方法进行转换时映射的,所以Java对象的 Get/Set方法尤为重要。
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("Jack", 20);
String json = objectMapper.writeValueAsString(user);
System.out.println(json);
}
{"username":"Jack","age":20}
@Data
class User {
private String username;
private Integer age;
public User() {
}
public User(String username, Integer age) {
this.username = username;
this.age = age;
}
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
String json = "{\"username\":\"Jack\", \"age\": \"20\"}";
User user = objectMapper.readValue(json, User.class);
System.out.println("user = " + user);
}
user = User(username=Jack, age=20)
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
String json = "[{\"username\":\"Jack\", \"age\": \"20\"},{\"username\":\"Tom\", \"age\": \"22\"}]";
List<User> userList = objectMapper.readValue(json, new TypeReference<List<User>>() {});
userList.forEach(System.out::print);
}
User(username=Jack, age=20)User(username=Tom, age=22)
JSON转Map适用于在没有一个明确的Java对象时十分实用
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
String json = "{\"username\":\"Jack\", \"age\": \"20\"}";
Map<String, Object> userNmp = objectMapper.readValue(json, new TypeReference<Map>() {});
for (Map.Entry<String, Object> entry : userNmp.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
如果在进行JSON 转 Java对象时,JSON中出现 Java 类中不存在的属性,那么在转换时会遇到com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException
异常。
使用objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
配置可以忽略不存在的属性。
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
String json = "{\"username\":\"Jack\", \"age\": \"20\",, \"test\": \"test\"}";
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
User user = objectMapper.readValue(json, User.class);
System.out.println("user = " + user);
}
开发中通常使用java.util.Date类或时间类java.time.LocalDateTime类(JDK8),两者在Jackson中的处理略有不同。
Date类型
@AllArgsConstructor
@NoArgsConstructor
@Data
class User {
private String username;
private Integer age;
private Date createTime;
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("Jack", 20, new Date());
String json = objectMapper.writeValueAsString(user);
System.out.println(json);
User u = objectMapper.readValue(json, User.class);
System.out.println(u.toString());
}
未使用@JsonFormat
注解,可以正常的进行JSON的序列化与反序列化,但是JSON 中的时间是一个时间戳格式
{"username":"Jack","age":20,"createTime":1669690748654}
User(username=Jack, age=20, createTime=Tue Nov 29 10:59:08 CST 2022)
使用 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
{"username":"Jack","age":20,"createTime":"2022-11-29 10:56:28"}
User(username=Jack, age=20, createTime=Tue Nov 29 10:56:28 CST 2022)
LocalDateTime类型
注意:默认情况下进行 LocalDateTime 类的 JSON 转换会遇到报错。异常信息:com.fasterxml.jackson.databind.exc.InvalidDefinitionException
需要添加相应的数据绑定支持包。
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.13.3</version>
</dependency>
定义 ObjectMapper 时通过 findAndRegisterModules() 方法来注册依赖。
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
User user = new User("Jack", 20, LocalDateTime.now());
String json = objectMapper.writeValueAsString(user);
System.out.println(json);
User u = objectMapper.readValue(json, User.class);
System.out.println(u.toString());
}
{"username":"Jack","age":20,"createTime":"2022-11-29 11:02:32"}
User(username=Jack, age=20, createTime=2022-11-29T11:02:32)
@JsonIgnore:使用@JsonIgnore 可以忽略某个 Java 对象中的属性,它将不参与 JSON 的序列化与反序列化。
@JsonIgnore
private String username;
@JsonGetter:使用 @JsonGetter 可以在对 Java 对象进行 JSON 序列化时自定义属性名称。
private String username;
@JsonGetter(value = "myName")
public String getUsername() {
return username;
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("Jack", 20);
String json = objectMapper.writeValueAsString(user);
System.out.println(json);
User u = objectMapper.readValue(json, User.class);
System.out.println(u.toString());
}
{"age":20,"myName":"Jack"}
User(username=Jack, age=20)
@JsonSetter:使用 @JsonSetter 可以在对 JSON 进行反序列化时设置 JSON 中的 key 与 Java 属性的映射关系。
@JsonSetter(value = "myName")
private String username;
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
String json="{\"age\":20,\"myName\":\"Jack\"}";
User u = objectMapper.readValue(json, User.class);
System.out.println(u.toString());
}
User(username=Jack, age=20)