JSON
JSON介绍
JSON:JavaScript Object Notation,JavaScript 对象表示法,一种轻量级的文本数据交换格式,采用一种“key:value
”的文本格式来存储和交换文本信息的语法,类似 XML
JSON 通常用于前端与后端交换数据
JSON 文件:
- JSON 文件的文件类型是
.json
- JSON 文本的 MIME 类型是
application/json
特点:
- JSON 比 XML 更小、更快,更易解析
JSON在线视图查看器:JSON在线视图查看器
JSON和XML区别
JSON与XML相同:纯文本;层级结构(值中存在值);通过JavaScript解析;数据可使用AJAX进行传输
JSON与XML不同:没有结束标签;更短,数据读写的速度更快;可以使用数组最大的不同是:XML 需要使用 XML 解析器来解析,JSON 可以使用标准的 JavaScript 函数来解析
- JSON.parse(): 将一个 JSON 字符串转换为 JavaScript 对象
- JSON.stringify(): 于将 JavaScript 值转换为 JSON 字符串
# JSON实例
{
"sites": [
{ "name":"hefery" , "age":23 },
{ "name":"lalala" , "age":24 },
{ "name":"hahaha" , "age":25 }
]
}
# XML实例
<sites>
<site>
<name>hefery</name> <age>23</age>
</site>
<site>
<name>lalala</name> <age>24</age>
</site>
<site>
<name>hahaha</name> <age>25</age>
</site>
</sites>
为什么使用 JSON?
对于 AJAX 应用程序来说,JSON 比 XML 更快更易使用:
- 使用 XML
读取 XML 文档
使用 XML DOM 来循环遍历文档
读取值并存储在变量中- 使用 JSON
读取 JSON 字符串
用 eval() 处理 JSON 字符串
JSON语法
数据格式:key:value
,"name" : "Hefery"
语法规则:
- key 必须是字符串,value 可以是合法的 JSON 数据类型(字符串, 数字, 对象, 数组, 布尔值或 null)
- key 和 value 中使用冒号“:”分隔
- 每个 key/value 对使用逗号“,”分隔
- 大括号 {} 保存对象
- 中括号 [] 保存数组,数组可以包含多个对象
Json 值:
- 数字(整数或浮点数):{ "age":30 }
- 字符串(在双引号中)
- 逻辑值(true 或 false):{ "flag":true }
- 数组(中括号中)
[ { key1 : value1-1 , key2:value1-2 }, { key1 : value2-1 , key2:value2-2 }, { key1 : value3-1 , key2:value3-2 }, ... { key1 : valueN-1 , key2:valueN-2 }, ] // 对象 sites 是包含三个对象的数组 { "sites": [ { "name":"hefery" , "age":23 }, { "name":"lalala" , "age":24 }, { "name":"hahaha" , "age":25 } ] }
- 对象(大括号中):
{key1:value1, key2:value2, ... keyN:valueN }
site={ "name":"hefery" , "age":23 }
访问或修改值:site["name"]; 或 site.name - null:{ "runoob":null }
嵌套 JSON 对象或对象数组
# JSON对象
cart= {
"name":"旺仔",
"price":10000,
"items": {
"item1":"旺仔牛奶糖",
"item2":"旺仔QQ糖",
"item3":"旺仔小馒头"
}
}
# 访问或修改元素
cart.items[1] # 旺仔牛奶糖
# JSON对象数组
cart= {
"name":"旺仔",
"num":3,
"items": [
{ "name":"旺仔牛奶糖", "info":[ "旺仔", "牛奶糖" ] },
{ "name":"旺仔QQ糖", "info":[ "旺仔", "QQ糖" ] },
{ "name":"旺仔小馒头", "info":[ "旺仔", "小馒头" ] }
]
}
# 访问或修改元素
cart.items[1].name # 旺仔牛奶糖
JSON应用
前端
JSON 使用 JavaScript 语法,所以无需额外的软件就能处理 JavaScript 中的 JSON
# 创建一个 JSON 对象sites
var sites = [
{ "name":"hefery" , "age":23 },
{ "name":"lalala" , "age":24 },
{ "name":"hahaha" , "age":25 }
];
# 访问数组对象sites的元素(索引从 0 开始)
sites[0].name; # hefery,通过索引下标访问
# 修改数组对象sites的元素(索引从 0 开始)
sites[0].name="hebin";
# 创建一个 JSON 对象数组cart
var cart = {
"name":"旺仔",
"num":3,
"items": [
{ "name":"旺仔牛奶糖", "info":[ "旺仔", "牛奶糖" ] },
{ "name":"旺仔QQ糖", "info":[ "旺仔", "QQ糖" ] },
{ "name":"旺仔小馒头", "info":[ "旺仔", "小馒头" ] }
]
};
# 访问或修改元素
cart.items[1].name # 旺仔牛奶糖
JSON文本转JavaScript对象
JSON.parse(): var obj = JSON.parse('{ "name":"hefery", "age":23, "site":"www.hefery.icu" }');
JSON.parse(text[, reviver])
text:必输, 一个有效的 JSON 字符串
reviver:可选,一个转换结果的函数, 将为对象的每个成员调用此函数
在线检测 JSON 格式工具:在线检测 JSON 格式工具
JSON格式化校验:JSON格式化校验
注意:JSON 不能存储 Date 对象,需要将其转换为字符串
var text = { "name":"hefery", "age":23, "initDate":new Date(), "site":"www.hefery.icu" };
var obj = JSON.parse(text, function(key, value) {
if (key == "initDate") {
return new Date(value);
} else {
return value;
}
});
JavaScript对象转JSON文本
JSON.stringify():
JSON.stringify(value[, replacer[, space]])
- value:必输, 要转换的 JavaScript 值(通常为对象或数组)
- replacer:可选。用于转换结果的函数或数组。
- 如果 replacer 为函数,则 JSON.stringify 将调用该函数,并传入每个成员的键和值。使用返回值而不是原始值。如果此函数返回 undefined,则排除成员。根对象的键是一个空字符串:""
- 如果 replacer 为数组,则仅转换该数组中具有键值的成员。成员的转换顺序与键在数组中的顺序一样。当 value 参数也为数组时,将忽略 replacer 数组
- space::可选,文本添加缩进、空格和换行符
- 如果 space 是一个数字,则返回值文本在每个级别缩进指定数目的空格,如果 space 大于 10,则文本缩进 10 个空格
- space 也可以使用非数字,如:\t
var text = { "name":"hefery", "age":23, "initDate":"2022-01-14", "site":"www.hefery.icu" };
var obj = JSON.stringify(text);
注意:JSON 不能存储 Date 对象,需要将其转换为字符串
var text = { "name":"hefery", "age":23, "initDate":new Date(), "site":"www.hefery.icu" };
# 在执行 JSON.stringify() 函数前将函数转换为字符串
text.initDate = text.initDate.toString();
var obj = JSON.stringify(text);
后端
FastJson
数据准备:
-
POJO
- User:用户
Integer id; String uaername; List<IdCard> idCards = new ArrayList<IdCard>();
- IdCard:银行卡
String cardNo; String sex; Date birthday; BigDecimal balance;
- User:用户
-
Test
public class FastJsonTest { /** JSON对象 */ private User user; /** JSON对象数组 */ private List<User> userList = new ArrayList<User>(); /** 序列化后的JSON对象字符串 */ private String userStr; /** 序列化后的JSON对象数组字符串 */ private String userListStr; /** 为序列化做准备 */ @Before public void initObjectAndList() { // 银行卡List1 List<IdCard> idCardList1 = new ArrayList<IdCard>(); IdCard idCard1 = new IdCard("10001", "男", new Date(), new BigDecimal("666.666")); IdCard idCard2 = new IdCard("10002", "男", new Date(), new BigDecimal("777.777")); idCardList1.add(idCard1); idCardList1.add(idCard2); // user用户有两张银行卡 idCard1 + idCard2 user = new User(1, "Hefery", idCardList1); // 银行卡List2 List<IdCard> idCardList2 = new ArrayList<IdCard>(); IdCard idCard3 = new IdCard("10003", "男", new Date(), new BigDecimal("888.888")); IdCard idCard4 = new IdCard("10004", "男", new Date(), new BigDecimal("999.999")); idCardList2.add(idCard3); idCardList2.add(idCard4); // hahaha用户有两张银行卡 idCard3 + idCard4 User hahaha = new User(2, "hahaha", idCardList2); userList.add(user); userList.add(hahaha); } /** 为反序列化做准备 */ @Before public void initString() { userStr = "{\"id\":1,\"idCards\":[{\"balance\":666.666,\"birthday\":1646565945957,\"cardNo\":\"10001\",\"sex\":\"男\"},{\"balance\":777.777,\"birthday\":1646565945958,\"cardNo\":\"10002\",\"sex\":\"男\"}],\"uaername\":\"Hefery\"}"; userListStr = "[{\"id\":1,\"idCards\":[{\"balance\":666.666,\"birthday\":1646565945957,\"cardNo\":\"10001\",\"sex\":\"男\"},{\"balance\":777.777,\"birthday\":1646565945958,\"cardNo\":\"10002\",\"sex\":\"男\"}],\"uaername\":\"Hefery\"},{\"id\":2,\"idCards\":[{\"balance\":888.888,\"birthday\":1646565945958,\"cardNo\":\"10003\",\"sex\":\"男\"},{\"balance\":999.999,\"birthday\":1646565945958,\"cardNo\":\"10004\",\"sex\":\"男\"}],\"uaername\":\"hahaha\"}]"; } }
FastJson使用
引入依赖
<!-- Fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
FastJson序列化
JSON序列化:JSON对象 --> 字符串
String userString = JSON.toJSONString(user);
String userListString = JSON.toJSONString(userList);
public class FastJsonTest {
/**
* 序列化JSON:JSON文本 --> 字符串
*/
@Test
public void test01() {
String userString = JSON.toJSONString(user);
String userListString = JSON.toJSONString(userList);
// 打印 JSON 对象
System.out.println(userString);
// 打印 JSON 对象数组
System.out.println(userListString);
}
/**
* 序列化JSON:JSON文本 --> OutputStream
*/
@Test
public void test09() throws IOException {
File file = new File("D:\\data\\test.json");
FileOutputStream fileOutputStream = new FileOutputStream(file);
JSON.writeJSONString(fileOutputStream, user);
}
}
// JSON 对象
{
"id": 1,
"idCards": [
{
"balance": 666.666,
"birthday": 1646565945957,
"cardNo": "10001",
"sex": "男"
},
{
"balance": 777.777,
"birthday": 1646565945958,
"cardNo": "10002",
"sex": "男"
}
],
"uaername": "Hefery"
}
// JSON 对象数组
[
{
"id": 1,
"idCards": [
{
"balance": 666.666,
"birthday": 1646565945957,
"cardNo": "10001",
"sex": "男"
},
{
"balance": 777.777,
"birthday": 1646565945958,
"cardNo": "10002",
"sex": "男"
}
],
"uaername": "Hefery"
},
{
"id": 2,
"idCards": [
{
"balance": 888.888,
"birthday": 1646565945958,
"cardNo": "10003",
"sex": "男"
},
{
"balance": 999.999,
"birthday": 1646565945958,
"cardNo": "10004",
"sex": "男"
}
],
"uaername": "hahaha"
}
]
注意:日期格式是毫秒值
FastJson反序列化
反序列化JSON:字符串 --> JSON文本
User user = JSON.parseObject(userStr, User.class);
List<User> userList = JSON.parseArray(userListStr, User.class);
public class FastJsonTest {
/**
* 反序列化JSON:字符串 --> JSON文本
*/
@Test
public void test02() {
User user = JSON.parseObject(userStr, User.class);
List<User> userList = JSON.parseArray(userListStr, User.class);
System.out.println(user);
System.out.println(userList);
}
/**
* 反序列化JSON:request对象的InputStream流的数据 --> JSON文本
*/
@Test
public void test03() throws IOException {
InputStream inputStream1 = new ByteArrayInputStream(userStr.getBytes());
Map<String, User> mapObject = JSON.parseObject(inputStream1, Map.class);
System.out.println(mapObject);
}
}
// user
User(id=1, uaername=Hefery, idCards=[IdCard(cardNo=10001, sex=男, birthday=Sun Mar 06 19:25:45 GMT+08:00 2022, balance=666.666), IdCard(cardNo=10002, sex=男, birthday=Sun Mar 06 19:25:45 GMT+08:00 2022, balance=777.777)])
// userList
[User(id=1, uaername=Hefery, idCards=[IdCard(cardNo=10001, sex=男, birthday=Sun Mar 06 19:25:45 GMT+08:00 2022, balance=666.666), IdCard(cardNo=10002, sex=男, birthday=Sun Mar 06 19:25:45 GMT+08:00 2022, balance=777.777)]), User(id=2, uaername=hahaha, idCards=[IdCard(cardNo=10003, sex=男, birthday=Sun Mar 06 19:25:45 GMT+08:00 2022, balance=888.888), IdCard(cardNo=10004, sex=男, birthday=Sun Mar 06 19:25:45 GMT+08:00 2022, balance=999.999)])]
FastJson需求
所有响应给前端的数据都只保留两位小数
坑:配置 SerializeConfig 全局实现 BigDecimal 类型保留两位小数,如果 POJO 类的 BigDecimal 类型字段没有添加 @JSONField(format = "")
注解并且没有(只要有一个,无论加在哪个字段),SerializeConfig 配置不会生效。
- 序列化配置时,设置转换规则
// 序列化配置:能够制定具体类型使用的序列转换器 SerializeConfig serializeConfig = new SerializeConfig(); serializeConfig.put(BigDecimal.class, new ObjectSerializer() { public final Integer newScale = 2; @Override public void write(JSONSerializer jsonSerializer, Object o, Object o1, Type type, int i) throws IOException { if (o == null) { jsonSerializer.out.write("0.00"); return; } jsonSerializer.out.write(((BigDecimal) o).setScale(newScale, RoundingMode.DOWN).toString()); } }); // BigDecimal 类型保留两位小数*/ serializeConfig.put(BigDecimal.class, new DIYBigDecimalSerializer(2)); //BigDecimal保留两位小数 fastJsonConfig.setSerializeConfig(serializeConfig);
- 通过过滤器,PropertyFilter不序列化 BigDecimal 类型,BeforeFilter/AfterFilter 手动填充
PropertyFilter propertyFilter = new PropertyFilter() { @Override public boolean apply(Object object, String name, Object value) { // PropertyFilter不序列化 BigDecimal 类型,BeforeFilter/AfterFilter 手动填充 if (value instanceof BigDecimal) { return false; } return true; } }; AfterFilter afterFilter = new AfterFilter() { @Override public void writeAfter(Object object) { Field[] fields = object.getClass().getDeclaredFields(); for (Field field : fields) { if (field.getType() == BigDecimal.class) { field.setAccessible(true); Object value = null; try { value = ((BigDecimal)field.get(object)).setScale(2, RoundingMode.DOWN); } catch (IllegalAccessException e) { e.printStackTrace(); } writeKeyValue(field.getName(), value); } } } }; fastJsonConfig.setSerializeFilters(propertyFilter, afterFilter);
- 通过过滤器,ValueFilter 设置 BigDecimal 类型序列化时将值保留两位小数
ValueFilter valueFilter = new ValueFilter() { @Override public Object process(Object object, String name, Object value) { if (value instanceof BigDecimal) { value = ((BigDecimal)value).setScale(1, RoundingMode.DOWN); } return value; } }; fastJsonConfig.setSerializeFilters(valueFilter);
所有日期格式转换为“yyy-MM-dd HH🇲🇲ss”格式
-
在POJO类的日期字段添加注解
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
@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 */ 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 ""; }
-
SerializerFeature.WriteDateUseDateFormat:
@Test public void test04() { // 指定日期格式 JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; String userString = JSON.toJSONString(user, SerializerFeature.WriteDateUseDateFormat); String userListString = JSON.toJSONString(userList, SerializerFeature.WriteDateUseDateFormat); System.out.println(userString); System.out.println(userListString); }
-
SerializeConfig:
@Test public void test04() { SerializeConfig config = new SerializeConfig(); config.put(Date.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss")); String userString = JSON.toJSONString(user, config); String userListString = JSON.toJSONString(userList, config); System.out.println(userString); System.out.println(userListString); }
-
ValueFilter
public void test04() { // @JSONField注解会失效 ValueFilter valueFilter = new ValueFilter() { @Override public Object process(Object object, String name, Object value) { if (value instanceof Date) { value = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value); } return value; } }; String userString = JSON.toJSONString(user, valueFilter); String userListString = JSON.toJSONString(userList, valueFilter); System.out.println(userString); System.out.println(userListString); }
消除对同一对象重复引用问题—$ref
fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
FastJson转换器配置
@Configuration
public class FastJsonConverConfig {
@Bean
public HttpMessageConverters httpMessageConverters() {
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
/** 设置支持的 MediaType */
List<MediaType> typeList = new ArrayList<MediaType>();
typeList.add(MediaType.APPLICATION_JSON_UTF8); // public static final MediaType APPLICATION_JSON = new MediaType("application", "json");
fastJsonHttpMessageConverter.setSupportedMediaTypes(typeList);
/** 设置 FastJson 全局配置(注意:注解失效) */
FastJsonConfig fastJsonConfig = new FastJsonConfig();
// 编码格式
fastJsonConfig.setCharset(StandardCharsets.UTF_8);
// 序列化格式处理
fastJsonConfig.setSerializerFeatures(
SerializerFeature.QuoteFieldNames, // 输出 key 时是否使用双引号,默认为 true
//SerializerFeature.UseSingleQuotes, // 使用单引号而不使用双引号,默认为 false
SerializerFeature.WriteMapNullValue, // 是否输出为null的字段,默认为 false
//SerializerFeature.WriteEnumUsingToString, // Enum枚举输出 name() 或 original,默认为 false
//SerializerFeature.WriteEnumUsingName, // 用 Enum枚举 nmae() 输出
//SerializerFeature.UseISO8601DateFormat, // Date 使用 ISO8601 格式输出,默认为 false
SerializerFeature.WriteNullListAsEmpty, // List 字段如果为 null,输出 []
SerializerFeature.WriteNullStringAsEmpty, // 字符类型字段如果为 null,输出 ""
SerializerFeature.WriteNullNumberAsZero, // 数值类型字段如果为 null,输出 []
SerializerFeature.WriteNullBooleanAsFalse, // 布尔类型字段如果为 null,输出 false
//SerializerFeature.SkipTransientField, // 如果为 true,类中的 getter 方法对应的 Field 是 Transient,序列化时会被忽略,默认为 true
//SerializerFeature.SortField, // 按字段名称排序后输出,默认为 false
//SerializerFeature.PrettyFormat, // 结果是否格式化,默认为 false
//SerializerFeature.WriteClassName, // 序列化时写入类型信息,默认为 false
SerializerFeature.DisableCircularReferenceDetect // 消除对同一对线循环引用的问题
//SerializerFeature.WriteSlashAsSpecial, // 对斜杠“/”进行转义
//SerializerFeature.WriteDateUseDateFormat // 全局修改日期格式,默认为 false
);
// 序列化配置:能够制定具体类型使用的序列转换器
SerializeConfig serializeConfig = new SerializeConfig();
serializeConfig.put(Date.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss")); // 日期的转换格式
//serializeConfig.put(String.class, PropertyNamingStrategy.CamelCase); // 设置字段的命名规则:驼峰 userid --> userId
/*serializeConfig.put(BigDecimal.class, new ObjectSerializer() { // BigDecimal 类型保留两位小数
public final Integer newScale = 2;
@Override
public void write(JSONSerializer jsonSerializer, Object o, Object o1, Type type, int i) throws IOException {
if (o == null) {
jsonSerializer.out.write("0.00");
return;
}
jsonSerializer.out.write(((BigDecimal) o).setScale(newScale, RoundingMode.DOWN).toString());
}
});*/
//serializeConfig.put(BigDecimal.class, new DIYBigDecimalSerializer(2)); // BigDecimal 类型保留两位小数
fastJsonConfig.setSerializeConfig(serializeConfig);
// 反序列化配置:不常用
//fastJsonConfig.setParserConfig();
/**
* 序列化过滤器:
* 执行顺序:PropertyPreFilter -> PropertyFilter -> NameFilter -> ValueFiter -> BeforeFilter -> AfterFilter
* PropertyPreFilter:根据PropertyName判断是否序列化
* PropertyFilter:在序列化,设定那些字段是否被序列化
* NameFilter:序列化时修改Key的名称,比如属性名为name,可以修改为Name
* ValueFilter:序列化时修改Value
* BeforeFilter:在序列化对象的所有属性之前执行某些操作
* AfterFilter:在序列化对象的所有属性之后执行某些操作
*/
fastJsonConfig.setSerializeFilters();
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
return new HttpMessageConverters(fastJsonHttpMessageConverter);
}
}