fastjson

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

1|0一、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实现的一些优化算法

2|0二、使用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|12.1 JSON对象

JSON这个类主要用于转换

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

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

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

2|22.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|32.3 JSONArray

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

最常用的方法:

  • getJSONObject(int index)

3|0三、序列化和反序列化

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

  • 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);

3|1反序列化

一般来说,我们从数据库拿到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字符串里边的字段改掉。

1|0parse、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字符串

3|2序列化

实体类:

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) */ } }

1|0序列化特征数组

方法

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" * } */ } }

4|0四、注解

4|1JSONField配置方式

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

1|0配置在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;} }

1|0配置在field上

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

4|2使用name指定字段名称

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

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

1|0使用format配置日期格式化

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

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

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

1|0使用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; }

1|0使用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"} */ } }

4|3JSONType

@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} } }

__EOF__

本文作者😎
本文链接https://www.cnblogs.com/dongye95/p/16152071.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   dongye95  阅读(164)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示