JSON 学习
文章目录
1. Json数据格式
JSON官网:https://www.json.org/json-en.html
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。轻量级指的是跟xml作比较,数据交换指的是客户端和服务器之间业务数据的传输格式。
JSON 是一种完全独立于语言的文本格式,使用 C 系列语言(包括 C)所熟悉的约定,使之让开发者很容易阅读和编写,也让机器很容易解析和生成,并有效地提升网络传输效率。这些优点也使 JSON 成为一种理想的独立语言文本格式。很多语言都提供了对json的支持(包括C,C++,C#,Java,JavaScript、Perl、Python等)。
1.1 Json 数据格式
Json的数据本身是数组,中括号包裹,数组的元素之间逗号分开,数组元素的数据类型没有限制。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JsonArray_Json数组格式</title>
<script type="text/javascript">
/**
* 定义json数组格式
* 中括号包裹,数组的元素的数据类型没用限制
* 元素之间,逗号分开
*/
var jsonArray = ["k1","中文",100,9.9,true];
// 访问数组元素,通过索引访问
console.log("索引访问:");
console.log(jsonArray[1]);
//遍历数组,取出数组中的元素
console.log("遍历数组:");
for (var i = 0; i < jsonArray.length; i++) {
console.log(jsonArray[i]);
}
</script>
</head>
<body>
</body>
</html>
输出:鼠标放到页面上 右键 -> 选择检查> 或 直接按 F12>
1.2 Json 对象格式
json的数据本身是对象,大括号包裹,对象采用键值对形式存储,键固定为字符串类型,值是任意类型的数据,键和值使用冒号分开。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JsonObject_Json对象格式</title>
<script type="text/javascript">
/**
* 定义json的对象格式
* 大括号包裹,定义键值对,建必须是字符串类型,值的数据类型不限
* 键值对之间,是冒号分开
* 每个键值对之间,逗号分开
*/
var jsonObject = {"k1":"v1","k2":"中国","k3":100,"k4":9.9,"k5":true};
//取出键值对,键找值的方式
console.log("取出键值对:");
console.log(jsonObject.k1);
console.log(jsonObject.k2);
console.log(jsonObject.k3);
console.log(jsonObject.k4);
console.log(jsonObject.k5);
</script>
</head>
<body>
</body>
</html>
1.3 数组对象相互嵌套格式
1.3.1 数组中的元素是对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JsonArrayObject_Json数据的嵌套</title>
</head>
<body>
<script type="text/javascript">
/**
* json数组的元素是对象
* 数组定义了2个元素,每个元素是对象
* 对象是键值对形式
*/
var jsonArray =[
{"name":"张三","age":20},
{"name":"李四","age":22}
];
//取出需要的数据,李四 22
console.log("取出需要的数据:");
console.log(jsonArray[1].name + "=="+jsonArray[1].age);
//遍历数组,取出数组中的元素
console.log("遍历数组,取出需要的数据:");
for (var i = 0; i < jsonArray.length; i++) {
console.log(jsonArray[i].name + "===" + jsonArray[i].age);
}
</script>
</body>
</html>
1.3.2 对象中的值是数组
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JsonObjectArray</title>
</head>
<body>
<script type="text/javascript">
/**
* json数组是对象,对象值是数组
*/
var jsonObject = {
"k1":["北京","天津","上海"],
"k2":["中国","美国","英国"]
};
//取出上海
console.log("取出“上海“值:");
console.log(jsonObject.k1[2])
//分别取出k1和k2键的数组,遍历
console.log("分别取出k1和k2键的数组,遍历:");
for (var i = 0; i < jsonObject.k1.length; i++) {
console.log(jsonObject.k1[i]);
}
console.log("========");
for (var i = 0; i < jsonObject.k2.length; i++) {
console.log(jsonObject.k2[i]);
}
</script>
</body>
</html>
1.3.3 你中有我,我中有你
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Json数据的嵌套</title>
</head>
<body>
<script type="text/javascript">
/**
* json的数据嵌套,泥中有我,我中有你
* json的数据本质上是对象 {} {"属性":"属性值,"属性2”:“属性2”}
* 集合:【】
* 对象的键是字符串,对象的值是数组、数组的元素是对象
*/
var json = {
//键是k1,值是数组,数组元素是对象
"k1":[
//数组的元素是2个对象
{"name":"张三","age":20},
{"name":"李四","age":22}
],
"k2":[
{"name":"王五","age":24},
{"name":"赵六","age":26}
]
};
//取出数据 李四 22
console.log("取出数据————李四 22")
console.log(json.k1[1].name + "==" + json.k1[1].age);
//遍历k2键对应的数组
console.log("遍历k2键对应的数组")
for (var i = 0; i < json.k2.length; i++) {
console.log(json.k2[i].name + "==" + json.k2[i].age)
}
</script>
</body>
</html>
2. 使用场景
- 网络传输
- 序列化存储
描述同样的消息,json相比xml占用更少的空间,如:
xml格式
<?xml version="1.0" encoding="UTF-8" ?>
<user>
<id>1</id>
<name>张三</name>
<age>30</age>
</user>
json表示
{
"id": 1,
"name": "张三",
"age": 30
}
3. java里面操作json有哪些技术
所有的操作把java里面的bean、map、collection等转化为json字符串(序列化),或反向操作(反序列化)占用更少的空间,如:java里面作json的技术一览
json官网:https://www.json.org/json-en.html
4. Fastjson
FastJson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将JavaBean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。FastJson会出现漏洞和bug,注意一下!
4.1 FastJson的优点
- 速度快
Fastjson相对其他JSON库特点是快,从2011年fastjson发布1.1.版本之后,其性能从未被其他Java实现的JSON超越 - 使用广泛
Fastjson在阿里巴巴大规模使用,在数万台服务器上部署,fastjson在业界被广泛接受,在2012年被开源中国评选为最受欢迎的国产开源软件之一。 - 测试完备
Fastjson有非常多的testcase,在1.2.11版本中,testcase超过3321个,每次发布都会进行回归测试,保证质量稳定。 - 使用简单
Fastjson的API十分简洁 - 功能完备
支持泛型,支持流处理超大文本、支持枚举、支持序列化和反序列化扩展。
4.2 FastJson的使用
4.2.1 FastJson引入依赖
<!--https://mvnrepository.com/artifact/com.alibaba/fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
<scope>compile</scope>
</dependency>
4.2.2 创建实体类
package com.test.json.pojo;
import lombok.Data;
import java.util.Date;
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
private String email;
private Date birthday;
private Boolean flag;
}
4.2.3 序列化
序列化:是指将java对象转成json格式字符串的过程,JavaBean对象,List集合对象,Map集合,为应用最广泛的。
- JSON.toJSONString
- 序列化java对象
4.2.3.1 创建测试类
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.test.json.pojo.Student;
import org.junit.Test;
import java.util.*;
public class TestFastJson {
//用于获取日期
public Date getDate(){
Date date = new Date();
return date;
}
}
4.2.3.2 Java中的对象(Student对象),序列化为Json格式字符串
@Test
//Java中的对象,Student对象,序列化为Json格式字符串
public void testObjectToJson(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setEmail("zs@sina.com");
student.setBirthday(getDate()); //转化毫秒值
//student 对象,转到Json格式字符串
//调用静态方法,传递要转换的对象
String jsonString = JSON.toJSONString(student);
System.out.println(jsonString);
//student对象,转到Json格式字符串
//{"age":20,"birthday":1662539443005,"email":"zs@sina.com","id":1,"name":"张三"}
}
4.2.3.3 Java中的集合List,序列化为Json格式字符串
@Test
//Java中的集合List,序列化为Json格式字符串
public void testListToJson(){
//集合List,存储Student对象
List<Student> list = new ArrayList<>();
Student student1 = new Student();
student1.setId(1);
student1.setName("张三");
student1.setAge(20);
student1.setEmail("zs@sina.com");
student1.setBirthday(getDate()); //转化毫秒值
Student student2 = new Student();
student2.setId(2);
student2.setName("李四");
student2.setAge(22);
student2.setEmail("ls@126.com");
student2.setBirthday(getDate()); //转化毫秒值
//Student对象存储到List集合中
list.add(student1);
list.add(student2);
//List集合,序列化为Json格式字符串
String jsonString = JSON.toJSONString(list);
System.out.println(jsonString);
// 转后的结果是数组,数组的元素是对象
// [{"age":20,"birthday":1662539828574,"email":"zs@sina.com","id":1,"name":"张三"}, //数组是1对象:张三 2对象:李四
// {"age":22,"birthday":1662539828574,"email":"ls@126.com","id":2,"name":"李四"}]
}
4.2.3.4 Java中的集合Maps,序列化为Json格式字符串
@Test
//Java中的集合Maps,序列化为Json格式字符串
public void testMapToJson(){
//创建Map集合,键为字符串类型,值是Student对象
Map<String,Student> map = new HashMap<String,Student>();
//集合List,存储Student对象
List<Student> list = new ArrayList<>();
Student student1 = new Student();
student1.setId(1);
student1.setName("张三");
student1.setAge(20);
student1.setEmail("zs@sina.com");
student1.setBirthday(getDate()); //转化毫秒值
Student student2 = new Student();
student2.setId(2);
student2.setName("李四");
student2.setAge(22);
student2.setEmail("ls@126.com");
student2.setBirthday(getDate()); //转化毫秒值
map.put("Student1",student1);
map.put("Student2",student2);
String jsonString = JSON.toJSONString(map);
System.out.println(jsonString);
// json格式字符串是对象,对象中有两个键 student1 student2 每个键对应的值是Student对象 List转换是数组 map转换是对象
// {"Student1":{"age":20,"birthday":1662540245268,"email":"zs@sina.com","id":1,"name":"张三"},
// "Student2":{"age":22,"birthday":1662540245268,"email":"ls@126.com","id":2,"name":"李四"}}
}
4.2.4 反序列化
4.2.4.1 Json格式字符串,反序列化回到Java对象
@Test
//Json格式字符串,反序列化回到Java对象
public void testJsonToObject(){
String jsonString = "{\"age\":20,\"birthday\":1662539443005,\"email\":\"zs@sina.com\",\"id\":1,\"name\":\"张三\"}";
//JSON类的静态方法
//传递要反序列化的Json字符串,传递Java对象的class对象
Student student = JSON.parseObject(jsonString,Student.class);
System.out.println(student);
//Student(id=1, name=张三, age=20, email=zs@sina.com, birthday=Wed Sep 07 16:30:43 CST 2022)
}
4.2.4.2 Json格式字符串,反序列化回到List集合
@Test
//Json格式字符串,反序列化回到List集合
public void testJsonToList(){
String jsonString = "[{\"age\":20,\"birthday\":1662539828574,\"email\":\"zs@sina.com\",\"id\":1,\"name\":\"张三\"},{\"age\":22,\"birthday\":1662539828574,\"email\":\"ls@126.com\",\"id\":2,\"name\":\"李四\"}]";
//JSON类的静态方法,parseArray
//传递json格式字符串,传递转换后的集合的泛型的class对象
List<Student> list = JSON.parseArray(jsonString,Student.class);
for (Student student:list){
System.out.println(student);
}
// Student(id=1, name=张三, age=20, email=zs@sina.com, birthday=Wed Sep 07 16:37:08 CST 2022)
// Student(id=2, name=李四, age=22, email=ls@126.com, birthday=Wed Sep 07 16:37:08 CST 2022)
}
4.2.4.3 Json格式字符串,反字符串回到Map集合
@Test
//Json格式字符串,反字符串回到Map集合
public void testJsonToMap(){
String jsonString = " {\"Student1\":{\"age\":20,\"birthday\":1662540245268,\"email\":\"zs@sina.com\",\"id\":1,\"name\":\"张三\"},\"Student2\":{\"age\":22,\"birthday\":1662540245268,\"email\":\"ls@126.com\",\"id\":2,\"name\":\"李四\"}}";
//JSON类的静态方法 .parseObject()
//直接进行反序列化,Map集合没有泛型的,泛型没有是不安全的集合
//转换后的集合,必须有泛型
//调用parseObject,传递参数,类型引用 typeReferences类的泛型中,传递转后的map集合 protected 授权限保护的匿名方法 需要匿名内部类 是子类的匿名对象
Map<String,Student> map = JSON.parseObject(jsonString,new TypeReference<Map<String,Student>>(){});
for (String key: map.keySet()) {
System.out.println(key + "::" + map.get(key));
}
// Student1::Student(id=1, name=张三, age=20, email=zs@sina.com, birthday=Wed Sep 07 16:44:05 CST 2022)
//Student2::Student(id=2, name=李四, age=22, email=ls@126.com, birthday=Wed Sep 07 16:44:05 CST 2022)
}
4.2.5 SerializerFeature枚举
创建测试类:
import java.util.Date;
/**
* SerializerFeature 枚举:进行序列化时,可以自己定义特殊需求
* JSON静态方法 tJSONString()
* 方法的参数:第一个是要序列化的对象
* 方法的参数:第二个参数SerializerFeature枚举类型的可变参数
* SerializerFeature枚举常量,做序列化的个性需求
*/
public class TestFastJson2 {
public Date getDate(){
Date date = new Date();
return date;
}
}
SerializerFeature枚举常量,该枚举类型支持序列化的一些特性数据类型定义:
public static String toJSONString(Object object, SerializerFeature... features) {
return toJSONString(object, DEFAULT_GENERATE_FEATURE, features);
}
1. 枚举常量 WriteMapNullValue ,序列化null值的字段
@Test
//WriteMapNullValue 枚举中的常量,序列化null值的字段
public void testWriteMapNullValue(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setBirthday(getDate()); //转化毫秒值
//不赋值
//student.setEmail("zs@sina.com");
String jsonString1 = JSON.toJSONString(student);
System.out.println(jsonString1);
// {"age":20,"birthday":1662542783030,"id":1,"name":"张三"}
//方法参数上,添加枚举类型
String jsonString2 = JSON.toJSONString(student,SerializerFeature.WriteMapNullValue);
System.out.println(jsonString2);
// {"age":20,"birthday":1662542783030,"email":null,"id":1,"name":"张三"}
}
2. 枚举常量 WriteNullStringAsEmpty字段为null,序列化为""
@Test
//WriteNullAsEmpty 枚举的常量,序列化为null的字段,值序列化为“”
public void testWriteStringAsEmpty(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setBirthday(getDate()); //转化毫秒值
//不赋值
//student.setEmail("zs@sina.com");
//方法的参数上,添加枚举类型
String jsonString = JSON.toJSONString(student,SerializerFeature.WriteNullStringAsEmpty);
System.out.println(jsonString);
// {"age":20,"birthday":1662543749112,"email":"","id":1,"name":"张三"}
}
3. 枚举常量 WriteNullNumberAsZero 字段为null序列化为0
@Test
//WriteNullNumberAsZero 枚举的常量 序列化字段值为null 序列化为0
public void testWriteNullAsZero() {
Student student = new Student();
student.setId(1);
student.setName("张三");
//不赋值
// student.setAge(20);
student.setBirthday(getDate()); //转化毫秒值
//不赋值
//student.setEmail("zs@sina.com");
//方法的参数上,添加枚举类型
String jsonString = JSON.toJSONString(student,SerializerFeature.WriteNullNumberAsZero);
System.out.println(jsonString);
// {"age":0,"birthday":1662544065292,"id":1,"name":"张三"}
}
4. 枚举常量 WriteNullBooleanAsFalse 字段值为null 输出为false
@Test
//WriteNullBooleanAsFalse 枚举的常量 序列化布尔值为null 序列华为false
public void testWriteNullBooleanAsFalse() {
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setBirthday(getDate()); //转化毫秒值
//不赋值
//student.setEmail("zs@sina.com");
//不赋值
//student.setFlag(true);
String jsonString1 = JSON.toJSONString(student);
System.out.println(jsonString1);
// {"age":20,"birthday":1662544479657,"id":1,"name":"张三"}
//方法的参数上,添加枚举类型
String jsonString2 = JSON.toJSONString(student,SerializerFeature.WriteNullBooleanAsFalse);
System.out.println(jsonString2);
// {"age":20,"birthday":1662544479657,"flag":false,"id":1,"name":"张三"}
}
5. 枚举常量 WriteDateUseDateFormat ,日期格式化;枚举常量 PrettyFormat,格式化输出
@Test
// WriteDateUseDateFormat 枚举的常量,序列化 日期格式化
// PrettyFormat 枚举常量,序列化,格式化输出
public void testWriteDateUseDate_FormatPrettyFormat(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setBirthday(getDate()); //转化毫秒值
//不赋值
//student.setEmail("zs@sina.com");
//不赋值
//student.setFlag(true);
String jsonString1 = JSON.toJSONString(student);
System.out.println(jsonString1);
//{"age":20,"birthday":1662544849121,"id":1,"name":"张三"}
//方法的参数上,添加枚举类型
String jsonString2 = JSON.toJSONString(student,SerializerFeature.WriteDateUseDateFormat);
System.out.println(jsonString2);
//{"age":20,"birthday":"2022-09-07 18:00:49","id":1,"name":"张三"}
//方法的参数上,添加枚举类型 可以加俩
String jsonString3 = JSON.toJSONString(student,SerializerFeature.WriteDateUseDateFormat,SerializerFeature.PrettyFormat);
System.out.println(jsonString3);
/**
* {
* "age":20,
* "birthday":"2022-09-07 18:00:49",
* "id":1,
* "name":"张三"
* }
*/
}
4.2.6 @JSONField注解
1. JSONField 源码
@JSONField
注解,该注解作用于方法上字段上和参数上可在序列化和反序列化时进行特性功能定制,注解可以放在方法上、成员变量上、方法的参数上。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.alibaba.fastjson.annotation;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface JSONField {
int ordinal() default 0;
String name() default "";
String format() default "";
boolean serialize() default true;
boolean deserialize() default true;
SerializerFeature[] serialzeFeatures() default {};
Feature[] parseFeatures() default {};
String label() default "";
boolean jsonDirect() default false;
Class<?> serializeUsing() default Void.class;
Class<?> deserializeUsing() default Void.class;
String[] alternateNames() default {};
boolean unwrapped() default false;
String defaultValue() default "";
}
2. 创建实体类:
package com.test.json.pojo;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import java.util.Date;
@Data
public class Student_JsonField {
//@JSONField 注解属性: name 指定序列化后的名字
//@JSONField 注解属性:ordinal 序列化后的顺序,属性值越小,顺序靠前
//@JSONField 注解属性:format 序列化后的格式
//@JSONField 注解属性:serialize 是否序列化该字段
//@JSONField 注解属性:deserialize 是否反序列化该字段
//@JSONField 注解属性:serialzeFeatures 序列化时的特性定义,和常量一致
private Integer id;
@JSONField(name = "studentName",ordinal = 1)
private String name;
@JSONField(ordinal = 2)
private Integer age;
//@JSONField 注解属性:serialize 是否序列化该字段
@JSONField(serialize = false)
private String email;
//@JSONField 注解属性:format 指定序列化后的格式
@JSONField(format = "YYYY-MM-dd HH:mm:ss")
private Date birthday;
private Boolean flag;
}
3. 创建测试类:
import com.alibaba.fastjson.JSON;
import com.test.json.pojo.Student_JsonField;
import org.junit.Test;
import java.util.Date;
/**
* @JSonField 注解
* 该注解作用于方法上,字段上和方法的参数上。可在序列化和反序列化时进行特性功能定制
*/
public class TestFastJson3_JsonField {
public Date getDate(){
Date date = new Date();
return date;
}
@Test
public void testObjectToJson(){
/**
* @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
* public @interface JSONField {
* int ordinal() default 0;
* 注意看一下源代码
*/
Student_JsonField student = new Student_JsonField();
student.setId(1);
student.setName("张三");
student.setAge(20);
student.setBirthday(getDate()); //转化毫秒值
student.setEmail("zs@sina.com");
String jsonString = JSON.toJSONString(student);
System.out.println(jsonString);
// {"age":20,"birthday":1662565074308,"email":"zs@sina.com","id":1,"name":"张三"}
//加完注解后 name
// {"age":20,"birthday":1662565946059,"email":"zs@sina.com","id":1,"studentName":"张三"}
//加完注解 ordinal
//{"birthday":1662565915298,"email":"zs@sina.com","id":1,"studentName":"张三","age":20}
//加完注解 format
// {"birthday":"2022-09-07 23:54:03","email":"zs@sina.com","id":1,"studentName":"张三","age":20}
//加完注解 serialize = false
//{"birthday":"2022-09-07 23:55:21","id":1,"studentName":"张三","age":20}
}
}
4.2.7 @JSONType注解
1. @JSONType源码
@JSONType
该注解作用于类上对该类的字段进行序列化和反序列化的特性功能定制,该注解作用在类上。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.alibaba.fastjson.annotation;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface JSONType {
boolean asm() default true;
String[] orders() default {};
String[] includes() default {};
String[] ignores() default {};
SerializerFeature[] serialzeFeatures() default {};
Feature[] parseFeatures() default {};
boolean alphabetic() default true;
Class<?> mappingTo() default Void.class;
Class<?> builder() default Void.class;
String typeName() default "";
String typeKey() default "";
Class<?>[] seeAlso() default {};
Class<?> serializer() default Void.class;
Class<?> deserializer() default Void.class;
boolean serializeEnumAsJavaBean() default false;
PropertyNamingStrategy naming() default PropertyNamingStrategy.CamelCase;
Class<? extends SerializeFilter>[] serialzeFilters() default {};
}
2. 创建实体类:
package com.test.json.pojo;
import com.alibaba.fastjson.annotation.JSONType;
import lombok.Data;
@Data
// 注解属性 includes 要被序列化的字段
// 注解属性 orders 序列化后的顺序
// 注解属性:serialzeFeatures 序列化时的特性定义和常数一致
@JSONType(includes = {"id","name","age","address"},orders = {"name","age","id","address"})
public class Student_JsonType {
private int id;
private String name;
private int age;
private String address;
}
3. 创建测试类
import com.alibaba.fastjson.JSON;
import com.test.json.pojo.Student_JsonType;
import org.junit.Test;
/**
* @JSONType 注解
* 该注解作用于类上,对该类的字段进行序列化和反序列化时的特性功能定制
*/
public class TestFastJson4_JsonType {
@Test
public void test(){
Student_JsonType student = new Student_JsonType();
student.setId(1);
student.setAddress("北京市");
student.setName("张三");
student.setAge(22);
String jsonString = JSON.toJSONString(student);
System.out.println(jsonString);
//{"address":"北京市","age":22,"id":1,"name":"张三"}
//如果去掉一个 @JSONType(includes = {"id","name","address"})
// {"address":"北京市","id":1,"name":"张三"}
/**
* package com.test.json.fastjson.pojo;
*
* import com.alibaba.fastjson.annotation.JSONField;
* import com.alibaba.fastjson.annotation.JSONType;
* import lombok.Data;
*
* @Data
* // 注解的属性 includes 要被序列化的字段
* @JSONType(includes = {"id","name","address"})
* public class Person {
*
* private int id;
*
* private String name;
*
* @JSONField(serialize = true) 不管用
* private int age;
*
* private String address;
* }
*/
//{"address":"北京市","id":1,"name":"张三"}
//添加orders
// @JSONType(includes = {"id","name","age","address"},orders = {"name","age","id","address"})
//{"name":"张三","age":22,"id":1,"address":"北京市"}
}
}
5. Jackson
Jackson是用来序列化和反序列化 json 的 Java 的开源框架。Spring MVC 的默认 json 解析器便是 Jackson。与其他 Java 的 json 框架 Gson 等相比, Jackson 解析大的 json 文件速度比较快;Jackson 运行时占用内存比较低,性能比较好;Jackson 有灵活的 API,可以很容易进行扩展和定制。
5.1 添加依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.1</version>
</dependency>
<!--对localDateTime等jdk8时间日期api的转化文件-->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.10.1</version>
</dependency>
5.1 序列化
5.1.1 创建实体类:
1. UserS类
package com.test.json.fastjson;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.Date;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserS{
/**
* 用户id
*/
private Long id;
/**
* 用户姓名
*/
private String name;
/**
* 密码
*/
private String pwd;
/**
* 网站名1
*/
private String websiteUrl;
/**
* 注册日期
*/
private Date registerDate;
/**
* 生日
*/
private LocalDateTime birthday;
/**
* 地址
*/
private String addr;
}
2. ResultDTO类: 用于后续泛型
package com.test.json.jackson;
import lombok.Data;
@Data
public class ResultDTO<T> {
private Boolean success = Boolean.TRUE;
private T data;
private ResultDTO(){}
public static <T> ResultDTO<T> buildSuccess(T t){
ResultDTO<T> resultDTO = new ResultDTO<>();
resultDTO.setData(t);
return resultDTO;
}
}
5.1.2 只包含非null属性
1. 全局配置
//序列化
private static ObjectMapper objectMapper = new ObjectMapper();
static {
/**
* 序列化配置
*/
//全局配置: 配置序列化时只包含非空属性
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
/**
* 序列化
* 把bean转化成json字符串
*/
@Test
public void test1() throws JsonProcessingException {
UserS user = new UserS();
user.setId(1L);
user.setName("张三");
//user.setPwd("123");
user.setAddr("河南");
user.setWebsiteUrl("http://www.baidu.com");
user.setRegisterDate(new Date());
user.setBirthday(LocalDateTime.now());
String string = objectMapper.writeValueAsString(user);
System.out.println(string);
}
2. 单个bean配置
@Data
@JsonInclude(JsonInclude.Include.NON_NULL) //类加上标签
public class UserS{
...
}
结果:
{"id":1,"name":"张三","websiteUrl":"http://www.baidu.com","registerDate":1661844024802,"birthday":{"month":"AUGUST","year":2022,"dayOfMonth":30,"hour":15,"minute":20,"monthValue":8,"nano":857000000,"second":24,"dayOfWeek":"TUESDAY","dayOfYear":242,"chronology":{"id":"ISO","calendarType":"iso8601"}},"addr":"河南"}
5.1.3 日期时间格式化
1. 全局配置
static {
/**
* 全局的配置
*/
//自动通过spi发现jackson的module并注册
objectMapper.findAndRegisterModules();
}
2.单个属性配置
/**
* 注册日期
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date registerDate;
结果:
{"id":1,"name":"张三","websiteUrl":"http://www.baidu.com","registerDate":"2022-08-30 15:42:10","birthday":"2022-08-30 15:42:10","addr":"河南"}
5.1.4 美化输出
static {
//美化输出
objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
}
结果:
{
"id" : 1,
"name" : "张三",
"websiteUrl" : "http://www.baidu.com",
"registerDate" : "2022-08-30 16:13:48",
"birthday" : "2022-08-30 16:13:48",
"addr" : "河南"
}
5.2 反序列化
5.2.1 忽略不存在的key
FastJson对于json中多的key默认的处理就是忽略!!!
添加这行代码,当遇到与类多余的属性时会选择不输出
static {
/**
* 反序列化的配置
*/
//objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
//两种写法等价
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
/**
* 反序列化
*/
@Test
public void test2() throws Exception{
String str = "{\"id\":1,\"name\":\"张三\",\"websiteUrl\":\"http://www.baidu.com\",\"registerDate\":\"2022-08-30 15:42:10\",\"birthday\":\"2022-08-30 15:42:10\",\"addr\":\"河南\"}\n";
UserS user = objectMapper.readValue(str, UserS.class); //属性必须与类相同 多了少了 都会报错
System.out.println(user); //Ctrl + Alt +V
}
结果:
{
"success" : true,
"data" : {
"name" : "张三",
"websiteUrl" : "http://www.baidu.com"
}
}
5.2.2 泛型处理
/**
* 泛型的处理
*/
@Test
public void test3() throws Exception{
UserS user = new UserS();
user.setName("张三");
user.setWebsiteUrl("http://www.baidu.com");
ResultDTO<User> userResultDTO = ResultDTO.buildSuccess(user);
String dtoSerializationResult = objectMapper.writeValueAsString(userResultDTO);
System.out.println(dtoSerializationResult);
//反序列化为ResultDTO<User>
ResultDTO<User> dataResult = objectMapper.readValue(dtoSerializationResult, new TypeReference<ResultDTO<User>>() {
});
System.out.println("dataResult:"+dataResult);
System.out.println("data:"+dataResult.getData());
}
结果:
{
"success" : true,
"data" : {
"name" : "张三",
"websiteUrl" : "http://www.baidu.com"
}
}
dataResult:ResultDTO(success=true, data=User(id=null, name=张三, pwd=null, websiteUrl=http://www.baidu.com, registerDate=null, birthday=null, addr=null))
data:User(id=null, name=张三, pwd=null, websiteUrl=http://www.baidu.com, registerDate=null, birthday=null, addr=null)
5.3 通用配置
- 序列化:驼峰转下划线;
- 反序列化:下划线传驼峰
static {
//驼峰命名法 转下划线
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
}
- 指定属性名和json字符串key的对应关系
/**
* 地址
*/
@JsonProperty("address")
private String addr;
{
"id" : 1,
"name" : "张三",
"pwd" : "123",
"website_url" : "http://www.baidu.com",
"register_date" : "2022-08-30 16:53:56",
"birthday" : "2022-08-30 16:53:56",
"address" : "河南"
}
- 忽略指定属性
/**
* 密码
*/
@JsonIgnore
private String pwd;
{
"id" : 1,
"name" : "张三",
"website_url" : "http://www.baidu.com",
"register_date" : "2022-08-30 16:52:08",
"birthday" : "2022-08-30 16:52:08",
"address" : "河南"
}
5.4 其他应用
- 对象更新
/**
* 对象更新,对象合并,如果后者属性有值,则用后者,否则前者的值不变
*/
@Test
public void test4() throws Exception {
UserS orginalUser = new UserS();
orginalUser.setId(2L);
orginalUser.setName("张三");
orginalUser.setWebsiteUrl("www.baidu.com");
UserS newUser = new UserS();
newUser.setId(3L);
newUser.setWebsiteUrl("www.google.com");
//让我们省去了很多判断
UserS updateUser = objectMapper.updateValue(orginalUser, newUser);
//id:2 name:张三 java websiteUrl:http:google.com
System.out.println(updateUser);
}
结果:
UserS(id=3, name=张三, pwd=null, websiteUrl=www.google.com, registerDate=null, birthday=null, addr=null)
5.5 全部代码
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.test.json.jackson.ResultDTO;
import com.test.json.jackson.UserS;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
public class JacksonTest {
//序列化
private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
private static ObjectMapper objectMapper = new ObjectMapper();
static {
/**
* 序列化配置
*/
//全局配置: 配置序列化时只包含非空属性
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//美化输出
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
/**
* 反序列化的配置
*/
//objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
//两种写法等价
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
/**
* 通用的配置
*/
//对Date进行配置,SimpleDateFormat是线程不安全的
objectMapper.setDateFormat(new SimpleDateFormat(DATE_TIME_FORMAT));
//自动通过spi发现jackson的module并注册
//objectMapper.findAndRegisterModules(); //注释了 就可以用下面手动配置JavaModule
//手动配置JavaTimeModule并注册
JavaTimeModule javaTimeModule = new JavaTimeModule();
//序列化
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
//反序列化
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
//注册:
objectMapper.registerModule(javaTimeModule);
//驼峰命名法 转下划线
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
}
/**
* 序列化
* 把bean转化成json字符串
*/
@Test
public void test1() throws JsonProcessingException {
UserS user = new UserS();
user.setId(1L);
user.setName("张三");
user.setPwd("123");
user.setAddr("河南");
user.setWebsiteUrl("http://www.baidu.com");
user.setRegisterDate(new Date());
user.setBirthday(LocalDateTime.now());
String string = objectMapper.writeValueAsString(user);
System.out.println(string);
}
/**
* 反序列化
*/
@Test
public void test2() throws Exception {
String str = "{\"id\":1,\"name\":\"张三\",\"websiteUrl\":\"http://www.baidu.com\",\"registerDate\":\"2022-08-30 15:42:10\",\"birthday\":\"2022-08-30 15:42:10\",\"addr\":\"河南\"}\n";
UserS user = objectMapper.readValue(str, UserS.class); //属性必须与类相同 多了少了 都会报错
System.out.println(user); //Ctrl + Alt +V
}
/**
* 泛型的处理
*/
@Test
public void test3() throws Exception {
UserS user = new UserS();
user.setName("张三");
user.setWebsiteUrl("http://www.baidu.com");
ResultDTO<UserS> userResultDTO = ResultDTO.buildSuccess(user);
String dtoSerializationResult = objectMapper.writeValueAsString(userResultDTO);
System.out.println(dtoSerializationResult);
//反序列化为ResultDTO<User>
ResultDTO<UserS> dataResult = objectMapper.readValue(dtoSerializationResult, new TypeReference<ResultDTO<UserS>>() {
});
System.out.println("dataResult:" + dataResult);
System.out.println("data:" + dataResult.getData());
}
/**
* 对象更新,对象合并,如果后者属性有值,则用后者,否则前者的值不变
*/
@Test
public void test4() throws Exception {
UserS orginalUser = new UserS();
orginalUser.setId(2L);
orginalUser.setName("张三");
orginalUser.setWebsiteUrl("www.baidu.com");
UserS newUser = new UserS();
newUser.setId(3L);
newUser.setWebsiteUrl("www.google.com");
//让我们省去了很多判断
UserS updateUser = objectMapper.updateValue(orginalUser, newUser);
//id:2 name:张三 java websiteUrl:http:google.com
System.out.println(updateUser);
}
}