文章目录
- Fastjson 使用指南
- 0 简要说明
- 为什么要用JSON?用JSON的好处是什么?
- 为什么要用JSON?
- JSON好处
- 1 常用数据类型的JSON格式
- 值的范围
- 2 快速上手
- 2.1 依赖
- 2.2 实体类
- 2.3 测试类
- 3 常见用法
- 3.1 序列化操作
- 核心操作
- 对象转换为JSON串
- list转换JSON串
- map转换为JSON串
- 3.2 反序列化操作
- JSON串转换为对象
- JSON串转换为map
- JSON串转换为list
- 4 常见问题
- 4.1 如何处理日期毫秒值问题
- 4.2 定制化序列化字段
- 4.3 指定某些字段不序列化
- 4.4 自定义序列化器
- 4.5 使用ordinal指定字段的顺序
- 4.6 序列化起别名
- 4.7 空值序列化操作处理
w3school
JSON格式化
序列化操作
Fastjson 使用指南
0 简要说明
Fastjson是一个Java语言编写的高性能功能完善的SON库。它采用一种"假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前)ava语言中最快的)SON库。Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。
主要特点:
快速FAST(比其它任何基于Java的解析器和生成器更快,包括jackson)
强大(支持普通DK类包括任意Java Bean Class、Collection、Map、Date或enum)
零依赖(除了DK没有依赖其它任何类库)
为什么要用JSON?用JSON的好处是什么?
1.首先JSON是一种数据格式,我们HTTP请求交互/内容存储到JSON,我们可以替代的方案就是XML,或者直接文本,当然首先是是使用JSON或者XML,其次才是文本,因为您考虑到存储方便也要考虑解析方便。
2.JSON是一个轻量级的数据格式,轻量级是相比较XML等其他复杂的存储格式而言,各个语言都兼容,都有各自解析JSON的组件。
为什么要用JSON?
1.其实用JSON主要是因为它轻量,各个平台语言都支持JSON交互、JSON解析和存储。
2.JSON常用于我们接口交互,前后端交互中,有解析速度快,方便的特点。
3.JSON常用于我们一些配置文件也是因为解析方便,JSON存储数据体积小等特征,而不像XML、PList(也是xml的一种)等格式,定义各种Dom节点(当然复杂的格式还是建议XML)。
JSON好处
1.JSON是大家公认的传输格式,所以学习成本低,程序员之间交流经常会问,您接口返回什么格式?答曰:“JSON”,其实就没啥问题了。
2.各个语言、各个框架(第三方组件)都支持JSON,所以使用上来讲,复用率更高,不用格式转来转去。
3.上面也讲了,体积小、解析速度快。
1 常用数据类型的JSON格式
值的范围
- Number:数字(整数或浮点数)
- String:字符串(在双引号中),一定是英文双引号(“”),个别弱语言可以支持单引号。
- Boolean:逻辑值(true 或 false)
- Array:数组(在方括号中),一般是在Value位置上。
- Object:对象(在花括号中),一般是在Value位置上。
- null:没什么好说的。
{"key":"value"},最简单的JSON 格式。
{"key1":"value1","key2":"value2"},一个JSON中有多个键值对的表达方式。
{"key":["a","b","sojson.com"]},value是一个Array 的JSON格式。
{"sojson":["5年","JSON在线解析","sojson.com",true,1,null]},value是一个Array 的JSON格式,并且这个数组中有多重类型的元素,有String,Boolean,Number,null。
{"key":{"json":"json for javascript"}},value 是JSONObject的JSON格式。
2 快速上手
2.1 依赖
仓库地址
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.51</version>
</dependency>
https://www.sojson.com/
2.2 实体类
package com.geekmice.springbootselfexercise.domain;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelIgnore;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserDomain implements Serializable {
/**
* 用户名
*/
private String userName;
/**
* 生日
*/
private Date birthday;
/**
* 性别
*/
private String sex;
/**
* 地址
*/
private String address;
}
2.3 测试类
/**
* 处理fastjson
*/
@Test
public void validateFastJson() {
UserDomain user = UserDomain.builder()
.userName("胡汉三").sex("男")
.birthday(new Date()).address("123@163.com").build();
String userJsonString = JSON.toJSONString(user);
log.info("userJsonString : [\n{}\n]", userJsonString);
}
14:36:33.649 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - userJsonString : [
{“address”:“123@163.com”,“birthday”:1691562993337,“sex”:“男”,“userName”:“胡汉三”}
]
3 常见用法
3.1 序列化操作
序列化:将一个对象编码成一个字节流(I/O),序列化的目的是为了方便数据的传递以及存储到磁盘上(把一个Java对象写入到硬盘或者传输到网路上面的其它计算机,这时我们就需要将对象转换成字节流才能进行网络传输。对于这种通用的操作,就出现了序列化来统一这些格式)。
核心操作
/**
* This method serializes the specified object into its equivalent Json representation. Note that this method works fine if the any of the object fields are of generic type,
* just the object itself should not be of a generic type. If you want to write out the object to a
* {@link Writer}, use {@link #writeJSONString(Writer, Object, SerializerFeature[])} instead.
*
* @param object the object for which json representation is to be created setting for fastjson
* @return Json representation of {@code object}.
*/
String jsonString = JSON.toJSONString(obj);
对象转换为JSON串
/**
* 处理fastjson
*/
@Test
public void validateFastJson() {
log.info("序列化操作开始,对象转换JSON串");
UserDomain user = UserDomain.builder()
.userName("胡汉三").sex("男")
.birthday(new Date()).address("123@163.com").build();
String userJsonString = JSON.toJSONString(user);
log.info("userJsonString : [\n\n{}\n\n]", userJsonString);
}
14:59:16.377 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - userJsonString : [
{“address”:“123@163.com”,“birthday”:1691564356144,“sex”:“男”,“userName”:“胡汉三”}
]
list转换JSON串
/**
* 处理fastjson
*/
@Test
public void validateFastJson() {
log.info("序列化操作开始,list转换JSON串");
List<UserDomain> result = Arrays.asList(
UserDomain.builder()
.userName("胡汉三").sex("男")
.birthday(new Date()).address("123@163.com").build(),
UserDomain.builder()
.userName("笑笑").sex("女")
.birthday(new Date()).address("345@163.com").build()
);
String listStr = JSON.toJSONString(result);
log.info("listStr : [\n\n{}\n\n]" , listStr);
}
14:59:16.381 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - listStr : [
[{“address”:“123@163.com”,“birthday”:1691564356380,“sex”:“男”,“userName”:“胡汉三”},{“address”:“345@163.com”,“birthday”:1691564356380,“sex”:“女”,“userName”:“笑笑”}]
]
map转换为JSON串
/**
* 处理fastjson
*/
@Test
public void validateFastJson() {
log.info("序列化操作开始,map转换JSON串");
HashMap<Object, Object> map = Maps.newHashMap();
map.put("name","小三子");
map.put("age",10);
final String mapStr = JSON.toJSONString(map);
log.info("mapStr : [\n\n{}\n\n]" , mapStr);
}
14:59:16.398 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - mapStr : [
{“name”:“小三子”,“age”:10}
]
3.2 反序列化操作
JSON串转换为对象
String userJsonString="{\"address\":\"123@163.com\",\"birthday\":1691564927544,\"sex\":\"男\",\"userName\":\"胡汉三\"}";
log.info("反序列化开始,JSON串转换对象");
UserDomain nonUser = JSON.parseObject(userJsonString, UserDomain.class);
log.info("nonUser : [{}]" , nonUser);
15:08:47.859 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - 反序列化开始,JSON串转换对象
15:08:47.903 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - nonUser : [UserDomain(id=null, userName=胡汉三, birthday=Wed Aug 09 15:08:47 CST 2023, sex=男, address=123@163.com)]
JSON串转换为map
String mapStr="{\"name\":\"小三子\",\"age\":10}";
log.info("反序列化开始,JSON串转换map");
Map<Object, Object> nonMap = JSON.parseObject(mapStr, new TypeReference<Map<Object, Object>>() {
});
log.info("nonMap : [{}]" , nonMap);
15:08:47.903 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - 反序列化开始,JSON串转换map
15:08:47.906 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - nonMap : [{name=小三子, age=10}]
JSON串转换为list
String listStr ="{\"address\":\"123@163.com\",\"birthday\":1691564927840,\"sex\":\"男\",\"userName\":\"胡汉三\"},{\"address\":\"345@163.com\",\"birthday\":1691564927840,\"sex\":\"女\",\"userName\":\"笑笑\"}"
log.info("反序列化开始:JSON串转换为list");
List<UserDomain> nonUserList = JSON.parseArray(listStr, UserDomain.class);
log.info("nonUserList : [{}]" , nonUserList);
15:08:47.906 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - 反序列化开始:JSON串转换为list
15:08:47.906 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - nonUserList : [[UserDomain(id=null, userName=胡汉三, birthday=Wed Aug 09 15:08:47 CST 2023, sex=男, address=123@163.com), UserDomain(id=null, userName=笑笑, birthday=Wed Aug 09 15:08:47 CST 2023, sex=女, address=345@163.com)]]
4 常见问题
4.1 如何处理日期毫秒值问题
方案一:使用 @JSONField(format = DateUtils.DATE_FORMAT_10)
format属性指定时间日期格式,只是针对于某几个字段,使用了这个注解有效
方案二:通过代码实现,这种形式所有date类型都是指定时间格式 yyyy-MM-dd
String result = JSON.toJSONStringWithDateFormat(user, com.alibaba.excel.util.DateUtils.DATE_FORMAT_10);
4.2 定制化序列化字段
4.3 指定某些字段不序列化
@JSONField(serialize= false)
4.4 自定义序列化器
1 定义
package com.geekmice.springbootselfexercise.serializer;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.ObjectSerializer;
import com.alibaba.fastjson.serializer.SerializeWriter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import java.io.IOException;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.util.Date;
import java.util.Objects;
/**
* @BelongsProject: spring-boot-self-exercise
* @BelongsPackage: com.geekmice.springbootselfexercise.serializer
* @Author: pingmingbo
* @CreateTime: 2023-08-09 15:59
* @Description: TODO
* @Version: 1.0
*/
@Slf4j
public class MyDateSerializer implements ObjectSerializer, ObjectDeserializer {
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
// 序列化,
// log.info("serializer : [{}]" , serializer); // 数据源
// log.info("object : [{}]" , object); // 字段值
// log.info("fieldName : [{}]" , fieldName); // 字段名称
// log.info("fieldType : [{}]" , fieldType);// 类型
if (Objects.isNull(object)) {
return;
}
String dateStr = object.toString();
Date date = null;
if (StringUtils.isNotBlank(dateStr)) {
try {
date = DateUtils.parseDate(dateStr, com.alibaba.excel.util.DateUtils.DATE_FORMAT_19);
} catch (ParseException e) {
log.error("error msg:【{}】", e);
throw new IllegalArgumentException(e);
}
}
long time = date.getTime();
SerializeWriter writer = serializer.getWriter();
writer.writeLong(time);
}
@Override
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
return null;
}
@Override
public int getFastMatchToken() {
return 0;
}
}
2.实体类添加
// @JSONField(ordinal = 7,format = DateUtils.DATE_FORMAT_10)
@JSONField(ordinal = 7,serializeUsing = MyDateSerializer.class)
private String testStrDate;
3.测试类使用
log.info("序列化操作开始,对象转换JSON串");
TempData user = TempData.builder()
.userName(null).sex("男")
.birthday(new Date()).address("123@163.com")
.logTime(new Date())
.registerTime(new Date())
.testStrDate("2023-08-09 23:22:21")
.score(new BigDecimal("2384.23"))
.build();
// 字符串类型字段为null,不进行序列化
String userJsonString = JSON.toJSONString(user, SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullNumberAsZero,
SerializerFeature.WriteNullBooleanAsFalse
);
log.info("userJsonString : [\n\n{}\n\n]", userJsonString);
21:18:42.724 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - userJsonString : [
{“id”:0,“username”:“”,“sex”:“男”,“address”:“123@163.com”,“logTime”:“2023-08-09 21:18:42”,“registerTime”:1691587122488,“testStrDate”:1691594541000,“score”:2384.23}
]
4.5 使用ordinal指定字段的顺序
package com.geekmice.springbootselfexercise.domain;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* @BelongsProject: spring-boot-self-exercise
* @BelongsPackage: com.geekmice.springbootselfexercise.domain
* @Author: pingmingbo
* @CreateTime: 2023-08-07 09:53
* @Description: Easy Excel 导入导出对应的实体类
* @Version: 1.0
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TempData implements Serializable {
private static final long serialVersionUID = 611155229642304781L;
/**
* 忽略这个字段
*/
private Long id;
/**
* 用户名
*/
@JSONField(name = "username",ordinal = 1)
private String userName;
/**
* 生日
*/
@JSONField(format = DateUtils.DATE_FORMAT_10,serialize = false,ordinal = 2)
private Date birthday;
/**
* 性别
*/
@JSONField(ordinal = 3)
private String sex;
/**
* 地址
*/
@JSONField(ordinal = 4)
private String address;
@JSONField(ordinal = 5)
private Date registerTime;
}
4.6 序列化起别名
@JSONField(name = "username", ordinal = 3)
@ExcelProperty(value = {"父级", "用户名"}, index = 0)
@JSONField(name = "username")
private String userName;
16:04:28.708 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - result : [{“address”:“123@163.com”,“logTime”:“2023-08-09”,“registerTime”:“2023-08-09”,“sex”:“男”,“username”:“胡汉三”}]
4.7 空值序列化操作处理
SerializerFeature | 描述 |
---|---|
WriteNullListAsEmpty | 将Collection类型字段的字段空值输出为[] |
WriteNullStringAsEmpty | 将字符串类型字段的空值输出为空字符串 “” |
WriteNullNumberAsZero | 将数值类型字段的空值输出为0 |
WriteNullNumberAsZero | 将Boolean类型字段的空值输出为false |
log.info("序列化操作开始,对象转换JSON串");
TempData user = TempData.builder()
.userName(null).sex("男")
.birthday(new Date()).address("123@163.com")
.logTime(new Date())
.registerTime(new Date())
.testStrDate("2023-07-18 23:22:21")
.build();
// 字符串类型字段为null,不进行序列化
String userJsonString = JSON.toJSONString(user, SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullNumberAsZero,
SerializerFeature.WriteNullBooleanAsFalse
);
20:42:40.253 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - 序列化操作开始,对象转换JSON串
20:42:40.664 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - userJsonString : [{“id”:0,“username”:“”,“sex”:“男”,“address”:“123@163.com”,“logTime”:“2023-08-09 20:42:40”,“registerTime”:1691584960267,“testStrDate”:1689693741000,“score”:0}
]