fastjson

转自:https://github.com/ZhongFuCheng3y/athena

一、fastjson入门

以下内容来源:https://github.com/alibaba/fastjson/wiki/Quick-Start-CN

它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean

fastjson优点:速度快、使用广泛、使用简单、功能完备、测试完备(之前爆了很多漏洞,现在我司走发布流程都强制我们升级fastjson版本了),现在使用fastjson至少升级到1.2.60版本

速度快的原因:

1、自行编写类似StringBuilder的工具类SerializeWriter。
2、使用ThreadLocal来缓存buf。
3、使用asm避免反射
4、集成jdk实现的一些优化算法

二、使用fastjson

首先我们在pom文件中引入fastjson的依赖就好了:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>x.x.x</version>
</dependency>

fastjson的使用主要是三个对象:

  • JSON
  • JSONObject
  • JSONArray

JSONArray和JSONObject继承JSON:

2.1 JSON对象

JSON这个类主要用于转换

  • 将Java对象序列化为JSON字符串
  • 将JSON字符串反序列化为Java对象

所以,有三个方法我们用得特别多:

  • parseObject(String text, Class<T> clazz)
  • parseArray(String text, Class<T> clazz)
  • toJSONString(Object object)

2.2 JSONObject

JSON对象( JSONObject )中的数据都是以 key-value 形式出现,所以它实现了 Map 接口:

使用起来也很简单,跟使用 Map 就没多大的区别(因为它底层实际上就是操作 Map ),常用的方法:

  • getString(String key)
  • remove(Object key)
  • put(String key, Object value)
  • clear()
  • getJSONObject(String key)
  • getJSONArray(String key)

2.3 JSONArray

JSONArray则是JSON数组,JSON数组对象中存储的是一个个JSON对象,所以类中的方法主要用于直接操作JSON对象

最常用的方法:

  • getJSONObject(int index)

三、序列化和反序列化

从上面的简单介绍我们已经可以知道了:

  • JSON用于将字符串反序列化为JavaBean和JavaBean序列化为JSON
  • JSONObject代表的是JSON对象,底层通过Map来操作,常用getString等方法来获取对应的值
  • JSONArray代表的是JSON对象数组,底层实际上是List,它用作于操作JSON对象

常用api

// 把JSON文本parse为JSONObject或者JSONArray 
public static final Object parse(String text); 
// 把JSON文本parse成JSONObject 
public static final JSONObject parseObject(String text); 
// 把JSON文本parse为JavaBean 
public static final <T> T parseObject(String text, Class<T> clazz); 
// 把JSON文本parse成JSONArray 
public static final JSONArray parseArray(String text); 
//把JSON文本parse成JavaBean集合 
public static final <T> List<T> parseArray(String text, Class<T> clazz); 
 // 将JavaBean序列化为JSON文本 
public static final String toJSONString(Object object);
// 将JavaBean根据字段特征序列化
public static final String toJSONString(Object object,SerializerFeature... features); 
//将JavaBean转换为JSONObject或者JSONArray。
public static final Object toJSON(Object javaObject); 

反序列化

一般来说,我们从数据库拿到JSON数据以后,然后要对JSON进行修改。比如JSON串如下:

{
    "formId": "{$formId}",
    "link": "www.java3y.com",
    "text": [{
        "name": "java3y",
        "label": "3y",
        "value": {
            "value": "{$tureName}",
            "color": "",
            "emphasis": ""
        }
    }, {
        "name": "java4y",
        "label": "3y",
        "value": {
            "value": "{$title}",
            "color": "",
            "emphasis": ""
        }
    }, {
        "name": "java5y",
        "label": "5y",
        "value": {
            "value": "关注我的公众号,更多干货",
            "color": "#ff0040",
            "emphasis": ""
        }
    }],
    "yyyImg": "",
    "yyyAge": "",
    "pagepath": ""
}

我们是不会直接操作JSON的,我们会将JSON转成我们自己的JavaBean,再操作JavaBean,最后序列化为JSONString

从上面的JSON结构上来看还是相对复杂的,思路:

  • 我们可以根据JSON的结构构建对应的JavaBean
  • 使用JSON类将JSON字符串反序列化为JavaBean
  • 修改JavaBean的值
  • 最后将JavaBean序列化为JSON字符串

从上面的JSON结构,首先我们针对text这层抽象为一个JavaBean。(实际上最里层的结构是value,但我这边不需要处理value,所以就不抽象了)

/**
 * "name": "java3y",
 *  "label": "3y",
 *  "value": {
 *      "value": "{$tureName}",
 *      "color": "",
 *      "emphasis": ""
 *    }
 *
 *  对Text进行抽象
 */
public class TextInfo {

    private String name;
    private String label;

    // 因为value我这边不需要操作,所以就不抽象了,如果每层都要处理,那就得抽象
    private Object value;


    // set get ... 省略

}

然后对外层进行抽象:

public class ContentValue {
    private String formId;
    private String link;
    // 这里是一个数组,我们就抽象为List,属性名为text
    private List<TextInfo> text;

    private String yyyImg;
    private String yyyAge;
    private String pagepath;

    // set get ... 省略

}

我们反序列化看一下:

public static void main(String[] args) {

    // JSON 字符串
    String s = "{\"formId\":\"{$formId}\",\"link\":\"www.java3y.com\",\"text\":[{\"name\":\"java3y\",\"label\":\"3y\",\"value\":{\"value\":\"{$tureName}\",\"color\":\"\",\"emphasis\":\"\"}},{\"name\":\"java4y\",\"label\":\"3y\",\"value\":{\"value\":\"{$title}\",\"color\":\"\",\"emphasis\":\"\"}},{\"name\":\"java5y\",\"label\":\"5y\",\"value\":{\"value\":\"关注我的公众号,更多干货\",\"color\":\"#ff0040\",\"emphasis\":\"\"}}],\"yyyImg\":\"\",\"yyyAge\":\"\",\"pagepath\":\"\"}";

    // 使用JSON对象 将JSON字符串反序列化为JavaBean
    ContentValue contentValue = JSON.parseObject(s, ContentValue.class);
    System.out.println(contentValue);


    }

反序列化结果:

我们要改text里边的值,只需要操作JavaBean就好了:

public static void main(String[] args) {

    // JSON 字符串
    String s = "{\"formId\":\"{$formId}\",\"link\":\"www.java3y.com\",\"text\":[{\"name\":\"java3y\",\"label\":\"3y\",\"value\":{\"value\":\"{$tureName}\",\"color\":\"\",\"emphasis\":\"\"}},{\"name\":\"java4y\",\"label\":\"3y\",\"value\":{\"value\":\"{$title}\",\"color\":\"\",\"emphasis\":\"\"}},{\"name\":\"java5y\",\"label\":\"5y\",\"value\":{\"value\":\"关注我的公众号,更多干货\",\"color\":\"#ff0040\",\"emphasis\":\"\"}}],\"yyyImg\":\"\",\"yyyAge\":\"\",\"pagepath\":\"\"}";

    // 使用JSON对象 将JSON字符串反序列化为JavaBean
    ContentValue contentValue = JSON.parse(s, ContentValue.class);
    List<TextInfo> text = contentValue.getText();
    for (TextInfo textInfo : text) {
        textInfo.setName("Java3y");
        textInfo.setLabel("关注我的公众号呗");
    }


    // 修改后,反序列化回去
    String content = JSON.toJSONString(contentValue);
}

序列化结果:

轻松将JSON字符串里边的字段改掉。

parse、parseObejct、parseArray区别

JSON.parseArray() 和 JSON.parseObject 都是讲 json 字符串转为实体类的方法

  1. JSON.parseArray 用于 json 是 [] 包裹的
  2. JSON.parseObject 用于 json 是 {} 包裹的
  3. 用JSON.toJSONString() 来解析对象

JSON.parse() 与 JSON.parseObject() 的区别

两者转化的结果都是一个json对象,没有区别。但是JSON.parseObject生成的对象有许多可以操作的方法,所以后端一般都是JSON.parseObject来解析json字符串

序列化

实体类:

package com.qr;

import lombok.Data;

import java.util.Date;

/**
 * FastJson
 */
@Data
public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private Date bitrthday;
}

测试

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import org.junit.Test;

import java.util.*;

public class FastJsonTest {

    /**
     * java对象转为json格式的字符串
     */
    @Test
    public void testObjectToJson(){
        Student student = new Student();
        student.setId(1);
        student.setName("list");
        student.setAge(11);
        student.setBitrthday(new Date());

        //转化
        String jsongString = JSON.toJSONString(student);
        System.out.println(jsongString);
        //{"age":11,"bitrthday":1620137932283,"id":1,"name":"list"}
    }

    /**
     * java中的集合转换为json
     */
    @Test
    public void testListToJson() {
        List<Student> list = new ArrayList<Student>();
        Student student1 = new Student();
        student1.setId(1);
        student1.setName("list");
        student1.setAge(11);
        student1.setBitrthday(new Date());

        Student student2 = new Student();
        student2.setId(2);
        student2.setName("lisa");
        student2.setAge(12);
        student2.setBitrthday(new Date());

        list.add(student1);
        list.add(student2);

        //list集合序列华为json格式的字符串
        String s = JSON.toJSONString(list);
        System.out.println(s);
        //[{"age":11,"bitrthday":1620138289599,"id":1,"name":"list"},{"age":12,"bitrthday":1620138289599,"id":2,"name":"lisa"}]
    }

    /**
     * map集合
     */
    @Test
    public void testMapToJson(){
        Map<String,Student> map = new HashMap<String, Student>();
        Student student1 = new Student();
        student1.setId(1);
        student1.setName("list");
        student1.setAge(11);
        student1.setBitrthday(new Date());

        Student student2 = new Student();
        student2.setId(2);
        student2.setName("lisa");
        student2.setAge(12);
        student2.setBitrthday(new Date());

        //map集合存储对象
        map.put("stu1",student1);
        map.put("stu2",student2);

        String s = JSON.toJSONString(map);
        System.out.println(s);
        //    {"stu2":{"age":12,"bitrthday":1620138549606,"id":2,"name":"lisa"},
        //    "stu1":{"age":11,"bitrthday":1620138549606,"id":1,"name":"list"}}
    }


    /**
     * 反序列化
     */

    /**
     * json 反序列化为 java对象
     */
    @Test
    public void testJsonToObject(){
        String json = "{\"age\":11,\"bitrthday\":1620137932283,\"id\":1,\"name\":\"list\"}";
        Student student = JSON.parseObject(json, Student.class);
        System.out.println(student);
        //Student(id=1, name=list, age=11, bitrthday=Tue May 04 22:18:52 CST 2021)
    }

    /**
     * json 反序列化为 list集合
     */
    @Test
    public void testJsonToList(){
        String json = "[{\"age\":11,\"bitrthday\":1620138289599,\"id\":1,\"name\":\"list\"},{\"age\":12,\"bitrthday\":1620138289599,\"id\":2,\"name\":\"lisa\"}]";
        List<Student> list = JSON.parseArray(json, Student.class);
        list.forEach(System.out::println);
        /**
         * Student(id=1, name=list, age=11, bitrthday=Tue May 04 22:24:49 CST 2021)
         * Student(id=2, name=lisa, age=12, bitrthday=Tue May 04 22:24:49 CST 2021)
         */
    }

    @Test
    public void testJsonToMap(){
        String json = "{\"stu2\":{\"age\":12,\"bitrthday\":1620138549606,\"id\":2,\"name\":\"lisa\"},\"stu1\":{\"age\":11,\"bitrthday\":1620138549606,\"id\":1,\"name\":\"list\"}}";
        //直接反序列化是没有泛型的,转不过去,没有泛型的集合是不安全的
//        Map jsonObject = JSON.parseObject(json);

        //传入转后的map集合,最后部分需要添加一个括号{}
        Map<String, Student> map = JSON.parseObject(json, new TypeReference<Map<String, Student>>(){});
        for (String key:map.keySet()){
            System.out.println(key+":"+map.get(key));
        }
        /**
         * stu2:Student(id=2, name=lisa, age=12, bitrthday=Tue May 04 22:29:09 CST 2021)
         * stu1:Student(id=1, name=list, age=11, bitrthday=Tue May 04 22:29:09 CST 2021)
         */
    }

}

序列化特征数组

方法

SerializerFeature[] features = {
SerializerFeature.WriteMapNullValue, // 输出空置字段
SerializerFeature.WriteNullListAsEmpty, // list字段如果为null,输出为[],而不是null
SerializerFeature.WriteNullNumberAsZero, // 数值字段如果为null,输出为0,而不是null
SerializerFeature.WriteNullBooleanAsFalse, // Boolean字段如果为null,输出为false,而不是null
SerializerFeature.WriteNullStringAsEmpty, // 字符类型字段如果为null,输出为"",而不是null
};

JSON.toJSONString(object, features);
@Data
public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private Date bitrthday;

    //添加一个布尔值
    private Boolean flag;
}
package com.qr;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.junit.Test;

import java.util.Date;

/**
 * SerializerFeature枚举:
 *      进行序列化的时候,可以自定义特殊需求
 *
 */
public class FastJsonTest2 {

    /**
     * 序列化为null值的字段
     *      WriteMapNullValue
     */
    @Test
    public void testWriteMapNullValue(){
        Student student = new Student();
        student.setId(1);
        student.setName("zhangsan");
        student.setAge(20);
//        String s = JSON.toJSONString(student);
//        System.out.println(s);
        //{"age":20,"id":1,"name":"zhangsan"},空值是没有被序列化的

        //SerializerFeature.WriteMapNullValue
        String s = JSON.toJSONString(student, SerializerFeature.WriteMapNullValue);
        System.out.println(s);
        //{"age":20,"bitrthday":null,"id":1,"name":"zhangsan"}

    }


    /**
     * 序列化为null的字段,序列化为""
     */
    @Test
    public void testWriteNullStringEnpty(){
        Student student = new Student();
        student.setId(1);
        student.setAge(20);
        String s = JSON.toJSONString(student,SerializerFeature.WriteNullStringAsEmpty);
        System.out.println(s);
        //{"age":20,"bitrthday":null,"id":1,"name":""}
    }


    /**
     * 序列化为null的number为0
     */
    @Test
    public void testWriteNullNumberAsZero(){
        Student student = new Student();
        student.setId(1);
        student.setName("zhangsan");
//        student.setAge(20);
        student.setBitrthday(new Date());
        String s = JSON.toJSONString(student,SerializerFeature.WriteNullNumberAsZero);
        System.out.println(s);
        //{"age":0,"bitrthday":1620141333809,"id":1,"name":"zhangsan"}
    }

    /**
     *  WriteNullBooleanAsFalse枚举常量,boolean值为null,序列化为false
     */
    @Test
    public void testWriteNullBooleanAsFalse(){
        Student student = new Student();
        student.setId(1);
        student.setName("zhangsan");
        student.setAge(20);
        student.setBitrthday(new Date());
        student.setFlag(true);
        String s = JSON.toJSONString(student,SerializerFeature.WriteNullBooleanAsFalse);
        System.out.println(s);
        //{"age":20,"bitrthday":1620141727099,"flag":true,"id":1,"name":"zhangsan"}
    }

    /**
     *  序列化日期格式化
     *
     */
    @Test
    public void testWriteDateUseDateFormatPrettyFormat(){
        Student student = new Student();
        student.setId(1);
        student.setName("zhangsan");
        student.setAge(20);
        student.setBitrthday(new Date());
        student.setFlag(true);
        String s = JSON.toJSONString(student,SerializerFeature.WriteDateUseDateFormat);
        System.out.println(s);
        //{"age":20,"bitrthday":"2021-05-04 23:25:57","flag":true,"id":1,"name":"zhangsan"}

        String s2 = JSON.toJSONString(student,SerializerFeature.WriteDateUseDateFormat,
                SerializerFeature.PrettyFormat);
        System.out.println(s2);
        /**
         * {
         * 	"age":20,
         * 	"bitrthday":"2021-05-04 23:27:20",
         * 	"flag":true,
         * 	"id":1,
         * 	"name":"zhangsan"
         * }
         */
    }
}

四、注解

JSONField配置方式

FieldInfo可以配置在getter/setter方法或者字段上。例如:

配置在getter/setter上

public class A {
      private int id;
 
      @JSONField(name="ID")
      public int getId() {return id;}
      @JSONField(name="ID")
      public void setId(int value) {this.id = id;}
 }

配置在field上

public class A {
      @JSONField(name="ID")
      private int id;
 
      public int getId() {return id;}
      public void setId(int value) {this.id = id;}
 }

使用name指定字段名称

当前端传过来的字段名不一样的时候,我们可以在字段名上加上这个注解

public class A {
      @JSONField(name="ID")
      private int id;
 
      public int getId() {return id;}
      public void setId(int value) {this.id = id;}
 }

使用format配置日期格式化

public class A {
      // 配置date序列化和反序列使用yyyyMMdd日期格式
      @JSONField(format="yyyyMMdd")
      public Date date;
 }

使用serialize/deserialize指定字段不序列化

public class A {
      @JSONField(serialize=false)
      public Date date;
 }
public class A {
      @JSONField(deserialize=false)
      public Date date;
 }

使用ordinal指定字段的顺序

​ 缺省fastjson序列化一个java bean,是根据fieldName的字母序进行序列化的,你可以通过ordinal指定字段的顺序。这个特性需要1.1.42以上版本。

public static class VO {
    @JSONField(ordinal = 3)
    private int f0;
    @JSONField(ordinal = 2)
    private int f1;
    @JSONField(ordinal = 1)
    private int f2;
}

使用serializeUsing制定属性的序列化类

​ 在fastjson 1.2.16版本之后,JSONField支持新的定制化配置serializeUsing,可以单独对某一个类的某个属性定制序列化,比如:

public static class Model {
    @JSONField(serializeUsing = ModelValueSerializer.class)
    public int value;
}
public static class ModelValueSerializer implements ObjectSerializer {
    @Override
    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
                      int features) throws IOException {
        Integer value = (Integer) object;
        String text = value + "元";
        serializer.write(text);
    }
}

演示

package com.qr;

import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;

import java.util.Date;

/**
 * FastJson
 */
@Data
public class Student {
    private Integer id;
    //注解属性
    @JSONField(name = "studentName",ordinal = 1)
    private String name;
    @JSONField(ordinal = 2,serialize = false)
    private Integer age;


    @JSONField(format = "yyyy-MM-dd")
    private Date bitrthday;

    //添加一个布尔值
    private Boolean flag;
}
package com.qr;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.junit.Test;

import java.util.Date;

/**
 * JSONFeild注解:
 *      该注解作用于方法上,字段和参数上,可在序列化和反序列时进行特定功能定制
 */
public class FastJsonTest3 {

    /**
     * 序列化的时候可以做到修改属性名
     */
    @Test
    public void testObjectToJson(){
        Student student = new Student();
        student.setId(1);
        student.setName("list");
        student.setAge(11);
        student.setBitrthday(new Date());
        student.setFlag(true);
        String jsongString = JSON.toJSONString(student);
        System.out.println(jsongString);
        /**
         *     //注解属性
         *     @JSONField(name = "studentName")
         *     private String name;
         *
         *     {"age":11,"bitrthday":1620142567227,"flag":true,"id":1,"studentName":"list"}
         */

        /**
         *     可以改变出现的位置
         *     @JSONField(name = "studentName",ordinal = 1)
         *     private String name;
         *     @JSONField(ordinal = 2)
         *     private Integer age;
         *     注解的顺序可以进行调整
         *     {"bitrthday":1620142775049,"flag":true,"id":1,"studentName":"list","age":11}
         */


        /**
         *     @JSONField(format = "yyyy-MM-dd")
         *     private Date bitrthday;
         *     {"bitrthday":"2021-05-04","flag":true,"id":1,"studentName":"list","age":11}
         */


        /**
         *     @JSONField(ordinal = 2,serialize = false)指定false就不会进行序列化
         *     private Integer age;
         *    {"bitrthday":"2021-05-04","flag":true,"id":1,"studentName":"list"}
         */

    }
}

JSONType

@Data
//includes指的是要被序列化的字段
@JSONType(includes = {"id","age","address"})
public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private String address;
}


/**
 * JSONType注解:
 *      该注解作用于方法上,字段和参数上,可在序列化和反序列时进行特定功能定制
 */
public class FastJsonTest4 {

    @Test
    public void test(){
        Person person = new Person();
        person.setId(1);
        person.setName("aa");
        person.setAge(11);
        person.setAddress("浙江杭州");
        String s = JSON.toJSONString(person);
        System.out.println(s);
        //{"address":"浙江杭州","age":11,"id":1}name没有被序列化
    }
}
@Data
//includes指的是要被序列化的字段
//orders明确序列化后的顺序
@JSONType(includes = {"id","name","age","address"},orders = {"name","address","age","id"})
public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private String address;
}

public class FastJsonTest4 {

    @Test
    public void test(){
        Person person = new Person();
        person.setId(1);
        person.setName("aa");
        person.setAge(11);
        person.setAddress("浙江杭州");
        String s = JSON.toJSONString(person);
        System.out.println(s);
        //{"name":"aa","address":"浙江杭州","age":11,"id":1}
    }
}
posted @ 2022-04-16 10:15  dongye95  阅读(183)  评论(0)    收藏  举报