fastjson使用
fastjson使用
https://github.com/alibaba/fastjson/wiki
1、基本API和配置
准备POJO测试数据
@Before
public void initObjectAndList(){
//设置user对象的值
user = new User();
user.setId(1);
user.setUsername("小鲁");
Calendar calendar = Calendar.getInstance();
calendar.set(1990,11,20);
Date birthday = calendar.getTime();
IdCard idCard = new IdCard("1999-05-10","1",birthday);
user.getIdCards().add(idCard);
calendar.set(1995,0,1);
Date birthday2 = calendar.getTime();
IdCard idCard2 = new IdCard("2000-10-10","0",birthday2);
user.getIdCards().add(idCard2);
//设置users集合的值
users.add(user);
}
@Before
public void initString(){
userStr = "{\"ids\":1,\"id\":1,\"idCards\":[{\"birthday\":\"1995-01-01\",\"cardNo\":\"2000134102030010\",\"sex\":\"1\"},{\"birthday\":788929283273,\"cardNo\":\"2000134102030020\",\"sex\":\"0\"}],\"username\":\"小鲁\"}";
usersStr = "[{\"id\":1,\"idCards\":[{\"birthday\":\"1990-01-01\",\"cardNo\":\"2000134102030010\",\"sex\":\"1\"},{\"birthday\":\"2002-11-11\",\"cardNo\":\"2000134102030020\",\"sex\":\"0\"}],\"username\":\"小鲁\"}]";
}
1.1 序列化
-
对象/Map -- 字符串
@Test public void toJsonString(){ String userString = JSON.toJSONString(user); System.out.println(userString); String usersString = JSON.toJSONString(users); System.out.println(usersString); }
{ "id":1, "idCards":[ { "birthday":661654769839, "cardNo":"2020001", "sex":"1" }, { "birthday":788921969839, "cardNo":"2020002", "sex":"0" } ], "username":"小y" } [ { "id":1, "idCards":[ { "birthday":661654769839, "cardNo":"2020001", "sex":"1" }, { "birthday":788921969839, "cardNo":"2020002", "sex":"0" } ], "username":"小y" } ]
-
序列化到OutputStream
/** * 和OutputStream/Writer对接 * 应用场景:直接和web项目的response对接 */ @Test public void toJsonOS() throws Exception { File file = new File("E:/test.json"); FileOutputStream fileOutputStream = new FileOutputStream(file); JSON.writeJSONString(fileOutputStream,user); }
-
BeanToArray
@Test public void bean2Array() throws Exception { System.out.println(JSON.toJSONString(user,SerializerFeature.BeanToArray)); }
[1,[[100.0101,661676334969,"2020001","1"],[200.056,788943534969,"2020002","0"]],"小y"]
1.2 反序列化
-
字符串转对象/Map/集合
@Test public void parseObjectOrArray(){ User user = JSON.parseObject(userStr, User.class); System.out.println(user); List<User> users = JSON.parseArray(usersStr, User.class); System.out.println(users); List<Map> maps = JSON.parseArray(usersStr, Map.class); System.out.println(maps); }
-
InputStream转对象/Map/集合
/** * 和inputstream对接 * 应用场景:web项目中,请求过来的payload数据可以通过该API解析数据 */ @Test public void testIsToObject() throws IOException { InputStream is = new ByteArrayInputStream(userStr.getBytes()); User user = JSON.parseObject(is, User.class); System.out.println(user); }
-
传入的是对象(数组同理),但是对象中的属性值是一个复杂对象
{"user":{ "id":1, "username":"小A", idCards:[ {cardNo:2000134102030010, "sex":1, "birthday":"1995-01-01"}, {cardNo:2000134102030020, "sex":0, "birthday":"1992-02-02"} ] } }
@Test public void testComObject() throws IOException { String a = "{\"user\":{\n" + " \"id\":1,\n" + " \"username\":\"小A\",\n" + " idCards:[\n" + " {cardNo:2000134102030010, \"sex\":1, \"birthday\":\"1995-01-01\"}, \n" + " {cardNo:2000134102030020, \"sex\":0, \"birthday\":\"1992-02-02\"}\n" + " ]\n" + "\t}\n" + "}"; Map<String,User> user = JSON.parseObject(a, new TypeReference<Map<String, User>>(){}); System.out.println(user); User user1 = user.get("user"); IdCard idCard = user1.getIdCards().get(0); System.out.println(idCard.getBirthday()); }
1.3 定制序列化
以最常用的Date类型举例说明。
-
@JSONField
@JSONField(format = "yyyy-MM-dd") private Date birthday;
@Test public void dateFormat1(){ String string = JSON.toJSONString(user); System.out.println(string); }
-
使用SerializerFeature的WriteDateUseDateFormat
@Test public void dateFormat(){ JSON.DEFFAULT_DATE_FORMAT = "yyyy/MM/dd HH:mm:ss"; String string = JSON.toJSONString(user,SerializerFeature.WriteDateUseDateFormat); System.out.println(string); }
{"id":1,"idCards":[{"balance":100.015,"birthday":"1990-11-10","cardNo":"1001"},{"balance":300.0123,"birthday":"2000-10-09","cardNo":"1002"}],"username":"查克拉"}
-
配置SerializeConfig
@Test public void dateFormat3(){ SerializeConfig config = new SerializeConfig(); config.put(Date.class,new SimpleDateFormatSerializer("yyyy/MM/dd HH:mm:ss")); String str = JSON.toJSONString(user,config); System.out.println(JSON.toJSONString(str); }
-
使用SerializeFilter
@Test public void dateFormat4(){ // 类似全局配置,@JSONField会失效 ValueFilter valueFilter = new ValueFilter() { public Object process(Object object, String name, Object value) { if(value instanceof Date){ value = new SimpleDateFormat("yyyy/MM/dd").format(value); } return value; } }; System.out.println(JSON.toJSONString(user,valueFilter)); }
SerializeFilter
下有多个子接口或抽象类简单说明:
PropertyPreFilter
根据PropertyName判断是否序列化
PropertyFilter
在序列化,设定那些字段是否被序列化
NameFilter
序列化时修改Key的名称。比如属性名为name,可以修改为Name。
ValueFilter
序列化时修改Value
BeforeFilter
在序列化对象的所有属性之前执行某些操作AfterFilter
在序列化对象的所有属性之后执行某些操作
他们有执行顺序:PropertyPreFilter --> PropertyFilter --> NameFilter --> ValueFilter --> BeforeFilter --> AfterFilter -
使用
JSONField
注解的serializeUsing
属性public class DateSer implements ObjectSerializer { public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { if (object == null) { serializer.out.writeNull(); return; } Date date = (Date)object; String dateStr = new SimpleDateFormat("yyyy-MM/dd HH:mm:ss").format(date); serializer.write(dateStr); } }
@JSONField(serializeUsing = DateSer.class) private Date birthday;
注解属性说明:
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; }
2、springboot+fastjson
2.1 配置fastjson
-
依赖 (我们此处暂不使用fastjson的起步依赖方式)
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.68</version> </dependency>
-
配置类
springmvc 4.2+ 、fastjson使用最新的
@Configuration public class HttpMessageConfig { @Bean public HttpMessageConverters fastJsonHttpMessageConverter(){ FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter(); // fastJsonHttpMessageConverter通过封装FastjsonConfig配置全局 return new HttpMessageConverters(fastJsonHttpMessageConverter); } }
2.2 FastJsonConfig
public void setCharset(Charset charset);
public void setSerializerFeatures(SerializerFeature... serializerFeatures); 序列化特性
public void setSerializeConfig(SerializeConfig serializeConfig); 序列化配置-个性化
public void setParserConfig(ParserConfig parserConfig); 反序列化配置
public void setSerializeFilters(SerializeFilter... serializeFilters); 序列化过滤器
2.3 SerializerFeature
名称 | 描述 |
---|---|
QuoteFieldNames | 输出key时是否使用双引号,默认为true |
UseSingleQuotes | 使用单引号而不是双引号,默认为false |
WriteMapNullValue | 是否输出值为null的字段,默认为false |
WriteEnumUsingToString | Enum输出name()或者original,默认为false |
WriteEnumUsingName | 用枚举name()输出 |
UseISO8601DateFormat | Date使用ISO8601格式输出,默认为false |
WriteNullListAsEmpty | List字段如果为null,输出为[],而非null |
WriteNullStringAsEmpty | 字符类型字段如果为null,输出为”“,而非null |
WriteNullNumberAsZero | 数值字段如果为null,输出为0,而非null |
WriteNullBooleanAsFalse | Boolean字段如果为null,输出为false,而非null |
SkipTransientField | 如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true |
SortField | 按字段名称排序后输出。默认为false |
(过期)WriteTabAsSpecial | 把\t做转义输出,默认为false |
PrettyFormat | 结果是否格式化,默认为false |
WriteClassName | 序列化时写入类型信息,默认为false。反序列化时需用到 |
DisableCircularReferenceDetect | 消除对同一对象循环引用的问题,默认为false |
WriteSlashAsSpecial | 对斜杠’/’进行转义 |
BrowserCompatible | 将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6,默认为false |
WriteDateUseDateFormat | 全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat); |
(过期)DisableCheckSpecialChar | 一个对象的字符串属性中如果有特殊字符如双引号,将会在转成json时带有反斜杠转移符。如果不需要转义,可以使用这个属性。默认为false |
2.4 SerializeConfig
// API
public boolean put(Type type, ObjectSerializer value)
serializeConfig.propertyNamingStrategy =
PropertyNamingStrategy.CamelCase/PascalCase/...;
CamelCase策略,Java对象属性:personId,序列化后属性:persionId
PascalCase策略,Java对象属性:personId,序列化后属性:PersonId
SnakeCase策略,Java对象属性:personId,序列化后属性:person_id
KebabCase策略,Java对象属性:personId,序列化后属性:person-id
3.解决方案
3.1 重复引用
使用 SerializerFeature.DisableCircularReferenceDetect 来去除重复引用
@PostMapping("/users")
public @ResponseBody List<User> users(@RequestBody User user){
//封装用户信息
...
//封装信用卡信息
List<IdCard> idCards = new ArrayList<>();
idCards.add(idCard1);
idCards.add(idCard2);
user.setIdCards(idCards);
user2.setIdCards(idCards);//两个user对象共用一个idCards集合
List<User> userList = new ArrayList<>();
userList.add(user);
userList.add(user2);
return userList;
}
[
{
"createTime": "2020/05/24 17:12:15",
"id": 4,
"idCards": [
{ "balance": 20000.011,
"birthday": "2020-05-24 17:12:15",
"cardNo": "2002110" },
{ "balance": 200.1271,
"birthday": "2020-05-24 17:12:15",
"cardNo": "2002120" }
],
"username": ""
},
{
"createTime": "2020/02/02 00:00:00",
"id": 10,
"idCards": [
{ "$ref": "$[0].idCards[0]" },
{ "$ref": "$[0].idCards[1]" }
],
"username": "lisi"
}
]
语法 | 描述 |
---|---|
引用根对象 | |
引用自己 | |
引用父对象 | |
引用父对象的父对象 | |
基于路径的引用 |
fastJsonConfig.setSerializerFeatures(
//去除重复引用
SerializerFeature.DisableCircularReferenceDetect
)
如果能直接控制到序列化方法的话,可以
JSON.toJSONString(user,SerializerFeature.DisableCircularReferenceDetect);
3.2 BigDecimal类型设置
-
public class BigDecimalSerializer implements ObjectSerializer { private final String pattern; public BigDecimalSerializer(String pattern){ this.pattern = pattern; } @Override public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { DecimalFormat decimalFormat = new DecimalFormat(pattern); SerializeWriter out = serializer.out; if (object == null) { out.write("0.00"); return; } BigDecimal decimal = (BigDecimal) object; // String formatDecimal = decimalFormat.format(decimal); out.write(formatDecimal); } }
serializeConfig.put(BigDecimal.class,new BigDecimalSerializer("#0.00"));
发现并不可行。
但是如果在IdCard中任意加一个@JSONField注解,并且有format属性,就可用了! -
使用SerializeFilter处理
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter(); SerializeConfig serializeConfig = new SerializeConfig();
fastJsonConfig.setSerializeConfig(serializeConfig);
PropertyFilter propertyFilter = new PropertyFilter() {
@Override
public boolean apply(Object object, String name, Object value) {
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);
value = ((BigDecimal) value).setScale(2,BigDecimal.ROUND_DOWN);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
writeKeyValue(field.getName(), value );
}
}
}
};fastJsonConfig.setSerializeFilters(propertyFilter,afterFilter);
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig); -
使用SerializeFilter处理
ValueFilter valueFilter = new ValueFilter() { @Override public Object process(Object object, String name, Object value) { if(value instanceof BigDecimal){ value = ((BigDecimal)value).setScale(3,BigDecimal.ROUND_DOWN); } return value; } }; fastJsonConfig.setSerializeFilters(valueFilter);
3.3 日期类型格式化
SerializeConfig serializeConfig = new SerializeConfig();
serializeConfig.put(Date.class,new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));
如果采用下面的全局配置方式,则会导致@JSONField失效
//配置全局日期处理,配置后@JSONField不再生效
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm");
//设置全局ValueFilter,配置后@JSONField不再生效
ValueFilter valueFilter = (Object object, String name, Object value) -> {
if(value == null){
value = "";
}
if(value instanceof LocalDateTime){
value = ((LocalDateTime)value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
if(value instanceof Date){
value = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date)value);
}
return value;
};
fastJsonConfig.setSerializeFilters(valueFilter,...);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义