FastJson使用

发布于 2023-07-15  2.55k 次阅读


1. Json数据格式

   JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它基于ECMAScript(欧洲计算机协会制定的js规范)的一个子集,采用完全独立与编程语言的文本格式来存储和表示数据。

JSON的优势:

  • 简洁和清晰的层次结构
  • 易于人阅读和编写
  • 易于机器解析和生成,解析和生成
  • JSON文本解析效率高,网络传输速率高
  • ………

1.1 Json的两种基本格式

两种基本格式:

  • 数组格式:Json数据本身是数组,
    • 中括号包裹
    • 数据的元素之间逗号分开
    • 数组元素的数据类型没有限制
  • 对象格式:Json数据本身是对象,对象采用键值对形式存储
    • 大括号包裹
    • 键固定为字符串类型,值可以是任意类型
    • 键和值之间使用冒号分开
    • 每个键值对之间,逗号分开

数组格式:[值1,值2,……]

["空想家",100,45.54,true]

对象格式:['键1':值1,'键2':值2,"键…":值3]

["a":100,"b":45.54,"c":true]

在读取方面数组通过下标取值,对象通过键取值

1.2 Json数组对象嵌套格式

在复杂数据传输过程中Json数据格式都是相互嵌套的

1)数组中包含对象元素:[{"键":值,"键":值,…},{"键":值,"键":值,…},……]

[{"name":"空想家","age":18,"sex":0},{"name":"空想家","age":18,"sex":0}]

2)对象中包含数组元素:{"键":['元素1','元素2'],"键":['元素1','元素2']}

{"k1":['拉','喇'],"k2":['蜡','辣']}

3)多重相互嵌套:多重嵌套可以很复杂没有固定格式

{"k1":[{"kxj":"空想家",maw:"兮夜"},{"kxj":"空想家",maw:"兮夜"}],"k2":['蜡','辣']}

2. Json解析库介绍

json序列化库:

  1. Json-lib:首个稳定版本(1.0) 发布于2002
  2. Gson:首个稳定版本(1.0) 发布于2008
  3. Jackson:首个稳定版本(1.0) 发布于2009
  4. FastJson:首个稳定版本(1.0) 发布于2012

1)Json-lib

  1. 是最早期的Java JSON库,提供了简单的API进行序列化和反序列化操作
  2. 它支持较早期的java版本,适用于特定场景和旧有系统
  3. 功能较弱json转bean有明显缺陷,性能效率低

2)Gson

  1. Gson是Google开发的Json序列化和反序列库,使用简单
  2. Gson是目前功能最全面的Json解析工具,它提供了丰富的AP和灵活的配置选型
  3. 它具有良好的性能和较低的内存消耗,在处理中等大小的Json数据是最快的
  4. 具有良好的社区支持

3)Jackson

  1. Jackson是功能强大的JSON库,被广泛应用于Java生态系统,从Github统计数据看,Jackson是最流行的json解析器之一,SpringMVC默认的Json解析器便是jackson
  2. Jackson所依赖jar包少,简单易用
  3. 它相比较于Gson,Jackson解析处理大的json文件速度更快,占内存比较低,性能较好
  4. Jackson支持多种数据格式,如JSON、XML、YAML等
  5. Jackson有完善的文档和活跃的社区,得到了广泛的应用和支持

4)FastJson

  1. FastJson是阿里巴巴开发的高性能JSON库,被称为Java中最快的JSON序列化库
  2. 它具有出色的性能和较低的内存消耗,适用于处理大型JSON数据。
  3. FastJson支持几乎所有的Java对象类型,并提供了灵活的配置选项。
  4. 可以通过注解或者代码配置来实现自定义序列化和反序列化。
  5. FastJson文档较少,但在社区中有广泛的使用和支持。

FastJson的优点:

1)速度快

    fastjson相对于其他Json的特点是快,从2011年fastjson发布1.1x版本之后,其性能从未被其他java实现的JSON库超越

2)使用广泛

    fastjson在阿里巴巴大规模使用,在数万台服务器上部署,fastjson在业界被广泛接收。在2012年被开源中国评选为最受欢迎的国产开源软件之一

3)测试完备

    fastjson有非常多的testcase,在1.2.11版本中,testcase超过3321个,每次发布都会进行回归测试,保证质量稳定

4)使用简单

    fastjson的API十分简洁

5)功能完备

    支持泛化,支持流处理超大文本,支持枚举,支持序列化和反序列化拓展

3. Java对象转化为Json

3.1 基本使用

序列化:是指将对象转成json格式字符串的过程(对象包括:JavaBean对象、List集合对象、Map集合对象)

JSON.toJSONString(Object object):序列化java对象的方法

  1. object:要转换为 JSON 字符串的对象。可以是 Java 对象、集合(如 List、Set)或数组等。
  2. config:一个 SerializeConfig 对象,用于指定序列化的配置选项。可以通过该对象来自定义序列化行为,例如指定日期格式、禁止循环引用等。如果不需要自定义配置,可以传递 null。
  3. filters:一个 SerializeFilter 对象数组,用于指定序列化时的过滤规则。可以通过该参数来排除某些字段或进行字段重命名等操作。可以传递多个过滤器,以数组形式提供。如果不需要过滤规则,可以传递 null。
  4. serializerFeatures:一个 SerializerFeature 枚举值或枚举值数组,用于指定序列化的特性。可以通过该参数来启用或禁用不同的序列化选项,如格式化输出、输出空字段等。可以传递多个特性,以数组形式提供。如果不需要特性设置,可以传递 null。
  5. globalFilters:一个 SerializeFilter 对象数组,用于指定全局的序列化过滤规则。与 filters 参数不同,全局过滤规则会应用于所有被序列化的对象。可以传递多个全局过滤器,以数组形式提供。如果不需要全局过滤规则,可以传递 null。
  6. dateFormat:一个日期格式化字符串,用于指定日期类型字段的序列化格式。例如,"yyyy-MM-dd HH:mm:ss" 表示使用年-月-日 时:分:秒的格式。如果不需要自定义日期格式,可以传递 null。
  7. features:一个 Feature 枚举值或枚举值数组,用于指定序列化的特性。该参数与 serializerFeatures 类似,但 features 参数用于全局设置,会影响所有被序列化的对象。可以传递多个特性,以数组形式提供。如果不需要特性设置,可以传递 null。

    对象转化为Json字符串都是使用JSON.toJSONString方法,基本使用中只传入object即可,配置、过滤、格式化不是必选项,根据具体业务逻辑而定

3.1.1 JavaBean转Json字符串

普通java类:

@ToString
@Data
@AllArgsConstructor
@NoArgsConstructor
public class fastbean {

    String name;

    String sex;

    Integer age;

    String  amie;
}

例:将bean转化为Json字符串

@Test
void beantoString(){
    fastbean fastbean = new fastbean();
    fastbean.setName("空想家");
    fastbean.setAmie("晴天");
    fastbean.setAge(190);
    fastbean.setSex("男");

    String string = JSON.toJSONString(fastbean);
    System.out.println(string);
}

输出:

{"age":190,"amie":"晴天","name":"空想家","sex":"男"}

3.1.2 List集合转Json字符串

例:

@Test
void listtoString(){
    ArrayList<fastbean> fastbeanArrayList = new ArrayList<>();
    fastbeanArrayList.add(new fastbean("空想家","男",20,"晴天"));
    fastbeanArrayList.add(new fastbean("疾风剑豪","男",40,"妖姬"));
    fastbeanArrayList.add(new fastbean("德玛西亚皇子","男",34,"光辉女郎"));
    fastbeanArrayList.add(new fastbean("盖伦","男",34,"寒冰"));
    String string = JSON.toJSONString(fastbeanArrayList);
    System.out.println(string);
}

输出:

[{"age":20,"amie":"晴天","name":"空想家","sex":"男"},{"age":40,"amie":"妖姬","name":"疾风剑豪","sex":"男"},
{"age":34,"amie":"光辉女郎","name":"德玛西亚皇子","sex":"男"},{"age":34,"amie":"寒冰","name":"盖伦","sex":"男"}]

3.1.3 Map集合转Json字符串

例:

@Test
void maptoString(){
    Map<Integer,fastbean> map = new HashMap<>();
    map.put(1,new fastbean("空想家","男",20,"晴天"));
    map.put(2,new fastbean("疾风剑豪","男",40,"妖姬"));
    map.put(3,new fastbean("德玛西亚皇子","男",34,"光辉女郎"));
    map.put(4,new fastbean("盖伦","男",34,"寒冰"));
    String string = JSON.toJSONString(map);
    System.out.println(string);
}

输出:

{1:{"age":20,"amie":"晴天","name":"空想家","sex":"男"},2:{"age":40,"amie":"妖姬","name":"疾风剑豪","sex":"男"},
3:{"age":34,"amie":"光辉女郎","name":"德玛西亚皇子","sex":"男"},4:{"age":34,"amie":"寒冰","name":"盖伦","sex":"男"}}

3.2 高级用法

普通java类:

@ToString
@Data
@AllArgsConstructor
@NoArgsConstructor
public class fastbean {


    String name;


    String sex;


    Integer age;


    String  amie;
}

演示的集合数据(List和Map是过滤是一样,主要以list举例):

ArrayList<fastbean> fastbeanArrayList = new ArrayList<>();
fastbeanArrayList.add(new fastbean("空想家","男",20,"晴天"));
fastbeanArrayList.add(new fastbean("疾风剑豪","男",40,"妖姬"));
fastbeanArrayList.add(new fastbean("德玛西亚皇子","男",34,"光辉女郎"));
fastbeanArrayList.add(new fastbean("盖伦","男",34,"寒冰"));

3.2.1 SerializeFilter过滤器

SerializeFilter是FastJson的顶级接口:子接口

  1. PropertyPreFilter:在序列化之前过滤属性的接口。通过实现该接口并实现 apply 方法,可以根据属性的名称和所属对象来决定是否将其包含在序列化结果中。例如,可以根据条件判断决定只序列化某些属性,或者根据属性值的特征进行过滤。
  2. PropertyFilter:在序列化过程中过滤属性的接口。通过实现该接口并实现 apply 方法,可以根据属性的名称、所属对象和属性值来决定是否将其包含在序列化结果中。相对于 PropertyPreFilter,PropertyFilter 提供了更多的信息,以便更灵活地过滤属性。
  3. NameFilter:用于重命名属性名称的接口。通过实现该接口并实现 process 方法,可以将属性名称转换为其他名称,并在序列化过程中使用新的属性名称。这对于需要修改属性名称的情况很有用,例如将驼峰命名转换为下划线命名。

注:PropertyFilter主要对集合中的对象做过滤,是否包含该对象。PropertyPreFilter是对对象中的某属性字段做过滤,该对象是否包含某属性

例1:将List集合转Json字符串中的对象中name属性值为"空想家"的对象过滤掉

① PropertyFilter接口实现(过滤对象)

public class kxjSerializeFilter implements PropertyFilter {
    @Override
    public boolean apply(Object o, String s, Object o1) { //o为对象 s为属性名 o1属性值
                //是否为fastbean类
        if (o instanceof fastbean) {
            fastbean fastBean = (fastbean) o;
            return !fastBean.getName().equals("空想家");
        }
        return true;
    }
}

② 测试

@Test
void fastjsonPreFile2() {
        //将过滤对象添加到过滤数组
    SerializeFilter[] filters = {new kxjSerializeFilter()};
        //集合对象过滤
    String string = JSON.toJSONString(fastbeanArrayList,filters);
    System.out.println(string);
}

结果:

[{},{"age":40,"amie":"妖姬","name":"疾风剑豪","sex":"男"},{"age":34,"amie":"光辉女郎","name":"德玛西亚皇子","sex":"男"},
{"age":34,"amie":"寒冰","name":"盖伦","sex":"男"}]

例2:将Json字符串中的对象中name属性值为"空想家"的字段过滤掉

① PropertyPreFilter接口实现(过滤对象中的字段)

public class PreSerializeFilter implements PropertyPreFilter {
    @Override
    public boolean apply(JSONSerializer serializer, Object object, String name) {
        // 返回 true 表示包含该属性,返回 false 表示过滤掉该属性

        // 例如,只保留 name 字段值为 "空想家" 的对象
        if (object instanceof fastbean && name.equals("name")) {
            fastbean fastBean = (fastbean) object;
            return !fastBean.getName().equals("空想家");
        }

        // 默认情况下包含所有属性
        return true;
    }
}

② 测试

@Test
void fastjsonPreFile() {
    //将过滤对象添加到过滤数组
    SerializeFilter[] filters = {new PreSerializeFilter()};
    String string = JSON.toJSONString(fastbeanArrayList,filters);
    System.out.println(string);
}

结果:

[{"age":20,"amie":"晴天","sex":"男"},{"age":40,"amie":"妖姬","name":"疾风剑豪","sex":"男"},
{"age":34,"amie":"光辉女郎","name":"德玛西亚皇子","sex":"男"},{"age":34,"amie":"寒冰","name":"盖伦","sex":"男"}]

实现过滤器可以使用匿名类如:参考

PropertyFilter propertyFilter = (object, name, value) -> !(name.equals("name") && value.equals("空想家"));
SerializeFilter[] filters = {propertyFilter};

例3:重命名name字段名为nickname

① NameFilter接口实现(属性重命名)

public class renameFilter implements NameFilter {
    @Override
    public String process(Object o, String s, Object o1) {//o对象 s属性名 o1为属性值
        if (s.equals("name")) {
            //返回新命名
            return "nicename";
        }
        return s;
    }
}

② 测试

@Test
void fastjsonPreFile3() {
    //重命名过滤器
    SerializeFilter[] filters = {new renameFilter()};
    String string = JSON.toJSONString(fastbeanArrayList,filters);
    System.out.println(string);
}

结果:

[{"age":20,"amie":"晴天","nicename":"空想家","sex":"男"},{"age":40,"amie":"妖姬","nicename":"疾风剑豪","sex":"男"},
{"age":34,"amie":"光辉女郎","nicename":"德玛西亚皇子","sex":"男"},{"age":34,"amie":"寒冰","nicename":"盖伦","sex":"男"}]

3.2.2 serializerFeatures特征

    serializerFeatures 参数用于指定序列化过程中的特性。它是一个 SerializerFeature 枚举值或枚举值数组,可以通过该参数启用或禁用不同的序列化选项。

以下是一些常见的 SerializerFeature 枚举值及其说明:

  • WriteNullListAsEmpty:当序列化空的集合(List、Set 等)时,将其序列化为 [],而不是 null。
  • WriteNullStringAsEmpty:当序列化空的字符串时,将其序列化为 "",而不是 null。
  • WriteNullNumberAsZero:当序列化空的数值类型(如 Integer、Double)时,将其序列化为 0,而不是 null。
  • WriteNullBooleanAsFalse:当序列化空的布尔类型时,将其序列化为 false,而不是 null。
  • WriteMapNullValue:序列化 Map 时,是否输出值为 null 的键值对。
  • WriteDateUseDateFormat:序列化 Date 对象时,使用指定的日期格式。
  • DisableCircularReferenceDetect:禁止循环引用的检测和处理,用于避免无限递归序列化。
  • PrettyFormat:输出格式化的 JSON 字符串,以提高可读性。

例:

// 使用 WriteNullStringAsEmpty 特性,将空的字符串序列化为 "" 
String jsonString1 = JSON.toJSONString(fastbean, SerializerFeature.WriteNullStringAsEmpty); System.out.println(jsonString1); 
// 使用 WriteNullNumberAsZero 特性,将空的数值类型序列化为 0 
String jsonString2 = JSON.toJSONString(fastbean, SerializerFeature.WriteNullNumberAsZero); System.out.println(jsonString2); 
// 同时使用 WriteMapNullValue 和 PrettyFormat 特性 
String jsonString3 = JSON.toJSONString(fastbean, SerializerFeature.WriteMapNullValue, SerializerFeature.PrettyFormat); 
System.out.println(jsonString3);

3.2.3 SerializeConfig序列化配置

序列化可配置项:

  • 日期格式化器:您可以设置不同类型的对象的日期格式化器,以定义它们在 JSON 中的表示形式。
  • 属性过滤器:您可以设置属性过滤器来选择要序列化的属性。这样,您可以控制哪些属性包含在生成的 JSON 中。
  • 自定义序列化器:您可以为特定的类型注册自定义的序列化器,以控制该类型对象在 JSON 中的表示形式。

方法:

  • getObjectWriter():getObjectWriter() 方法返回一个 ObjectSerializer 对象,用于获取当前配置的对象序列化器。您可以使用该序列化器来执行自定义的序列化操作。
  • getTypeKey():getTypeKey() 方法返回一个 String,表示当前配置的类型键(Type Key)。类型键用于在序列化和反序列化过程中标识对象的类型信息。默认情况下,fastjson 使用 @type 作为类型键。
  • clearSerializers():clearSerializers() 方法用于清除已注册的自定义序列化器。通过调用此方法,您可以清除配置中的所有自定义序列化器,使其恢复为默认状态。
  • createJavaBeanSerializer():createJavaBeanSerializer() 方法用于创建JavaBeanSerializer 对象,用于序列化 Java 对象。该方法可用于创建自定义的 JavaBean 序列化器,并进行进一步的定制。

例:

@Test
void fastjsonPreFile4() {
    //创建序列化配置对象
    SerializeConfig config = new SerializeConfig();
    //设置数据格式化
    config.put(Date.class, new SimpleDateFormatSerializer("yyyy-MM-dd"));
    //设置过滤器(间接设置 <->也可以直接设置)
    PropertyPreFilter filter = (source, name, value) -> !"空想家".equals(name);
    config.addFilter(fastbean.class, filter);
    //自定义序列化器
    config.put(fastbean.class, new MyCustomSerializer());
    //启用了 ASM
    config.setAsmEnable(true);
    String string = JSON.toJSONString(fastbeanArrayList,filters);
    System.out.println(string);
}

4. Json字符串转java对象

Json字符串转java对象,一般转三种格式普通javaBean对象、List集合、Map集合。

4.1 Json转JavaBean对象

序列化Josn字符串转JavaBean对象方法:JSON.parseObject(String text, Class<T> clazz)

  • String text:Json字符串
  • Class<T> clazz:需要转化的Java Class类对象

例:

@Test
void wq(){
    String json = "{\"age\":40,\"amie\":\"妖姬\",\"nicename\":\"疾风剑豪\",\"sex\":\"男\"}";
    fastbean fastjsontest = JSON.parseObject(json, fastbean.class);
    System.out.println(fastjsontest);
}

输出:

fastbean(name=null, sex=男, age=40, amie=妖姬)

4.2 Json转List对象集合

序列化Josn字符串转List对象集合方法:JSON.parseArray(String text, Class<T> clazz)

  • String text:Json字符串
  • Class<T> clazz:集合内部的对象类型

例:

@Test
void wq1(){
    String json ="[{\"age\":20,\"amie\":\"晴天\",\"nicename\":\"空想家\",\"sex\":\"男\"},{\"age\":40,\"amie\":\"妖姬\",\"nicename\":\"疾风剑豪\",\"sex\":\"男\"},{\"age\":34,\"amie\":\"光辉女郎\",\"nicename\":\"德玛西亚皇子\",\"sex\":\"男\"},{\"age\":34,\"amie\":\"寒冰\",\"nicename\":\"盖伦\",\"sex\":\"男\"}]";
    List<fastbean> fastbeans = JSON.parseArray(json, fastbean.class);
    System.out.println(fastbeans);
}

输出:

[fastbean(name=null, sex=男, age=20, amie=晴天), fastbean(name=null, sex=男, age=40, amie=妖姬), 
fastbean(name=null, sex=男, age=34, amie=光辉女郎), fastbean(name=null, sex=男, age=34, amie=寒冰)]

4.3 Json转Map对象集合

序列化Josn字符串转Map对象集合方法:JSON.parseObject(String text, Class<T> clazz)

使用和转JavaBean没有本质区别,类型指定时需要使用 TypeReference<Map<String, FastBean>> 来指定将 JSON 字符串转换为 Map<String, FastBean> 类型的对象

例:

@Test
void wq2(){
    String json ="{1:{\"age\":20,\"amie\":\"晴天\",\"name\":\"空想家\",\"sex\":\"男\"},2:{\"age\":40,\"amie\":\"妖姬\",\"name\":\"疾风剑豪\",\"sex\":\"男\"},3:{\"age\":34,\"amie\":\"光辉女郎\",\"name\":\"德玛西亚皇子\",\"sex\":\"男\"},4:{\"age\":34,\"amie\":\"寒冰\",\"name\":\"盖伦\",\"sex\":\"男\"}}";
    Map<Integer, fastbean> resultMap = JSON.parseObject(json, new TypeReference<Map<Integer, fastbean>>() {});

    for (Map.Entry<Integer, fastbean> entry : resultMap.entrySet()) {
        Integer key = entry.getKey();
        fastbean value = entry.getValue();
        System.out.println("Key: " + key);
        System.out.println("Value: " + value);
    }
}

输出:

Key: 1
Value: fastbean(name=空想家, sex=男, age=20, amie=晴天)
Key: 2
Value: fastbean(name=疾风剑豪, sex=男, age=40, amie=妖姬)
Key: 3
Value: fastbean(name=德玛西亚皇子, sex=男, age=34, amie=光辉女郎)
Key: 4
Value: fastbean(name=盖伦, sex=男, age=34, amie=寒冰)

5. @JSONField注解使用

@JSONField注解可作用于方法上、字段上和参数上。可对序列化和反序列进行特性功能定制

参数:

  • name:字段序列化之后的名称
  • ordinal:序列化后的顺序
  • format:字段值序列化后的格式
  • serialize:是否序列化该字段
  • deseriallize:是否反序列化该字段
  • serialzeFeatures:序列化的特性定义

注:@JSONField比编程式的写serializerFeatures、SerializeConfig更方便,当定制性较低

例:

public class fastbean {

    @JSONField(name = "namenice",ordinal = 1,serialzeFeatures = SerializerFeature.WriteNullStringAsEmpty)
    String name;

    @JSONField(ordinal = 4)
    String sex;

    @JSONField(ordinal = 3)
    Integer age;

    @JSONField(serialize=false,ordinal = 2)
    String  amie;
}

测试:

@Test
void maptoString(){
    Map<Integer,fastbean> map = new HashMap<>();
    map.put(1,new fastbean("空想家","男",20,"晴天"));
    map.put(2,new fastbean("疾风剑豪","男",40,"妖姬"));
    map.put(3,new fastbean("德玛西亚皇子","男",34,"光辉女郎"));
    map.put(4,new fastbean("盖伦","男",34,"寒冰"));
    String string = JSON.toJSONString(map);
    System.out.println(string);
}

输出:

 {1:{"namenice":"空想家","age":20,"sex":"男"},2:{"namenice":"疾风剑豪","age":40,"sex":"男"},
3:{"namenice":"德玛西亚皇子","age":34,"sex":"男"},4:{"namenice":"盖伦","age":34,"sex":"男"}}

6. @JSONType注解使用

@JSONType该注解作用于类上,对该类的字段进行序列化和反序列化时的特征功能定制

  • includes:要被序列化的字段
  • orders:序列化的顺序
  • serialzeFeatures:序列化时的特征定义

例:

@JSONType(includes = {"name","sex","age"},orders = {"name","age","sex"},serialzeFeatures = SerializerFeature.WriteNullStringAsEmpty)
public class fastbean {
    String name;
    String sex;
    Integer age;
    String  amie;
}

测试:

@Test
void maptoString(){
    Map<Integer,fastbean> map = new HashMap<>();
    map.put(1,new fastbean("空想家","男",20,"晴天"));
    map.put(2,new fastbean("疾风剑豪","男",40,"妖姬"));
    map.put(3,new fastbean("德玛西亚皇子","男",34,"光辉女郎"));
    map.put(4,new fastbean("盖伦","男",34,"寒冰"));
    String string = JSON.toJSONString(map);
    System.out.println(string);
}

输出:

{1:{"name":"空想家","age":20,"sex":"男"},2:{"name":"疾风剑豪","age":40,"sex":"男"},
3:{"name":"德玛西亚皇子","age":34,"sex":"男"},4:{"name":"盖伦","age":34,"sex":"男"}}

 


路漫漫其修远兮,吾将上下而求索