使用 Fastjson 操作 JSON 数据

Fastjson详解:使用、注解、序列化与反序列化
本文详细介绍了阿里巴巴的Fastjson库,包括其核心类`JSON`的使用,如字符串转JSON、JavaBean序列化与反序列化;`@JSONField`注解的属性及其在序列化和反序列化中的作用;JSONPath对象的API、语法及示例;并展示了如何处理空值和自定义序列化规则。Fastjson是一个高性能的JSON库,适用于服务器端和Android客户端。


1. 工具简介

Fastjson 项目 GitHub 主页

Fastjson 是一个 Java 库,可以用来将 Java 对象转换为它们的 JSON 表示。它还可以用于将 JSON 字符串转换为等价的 Java 对象。fastjson 可以处理任意 Java 对象,包括没有源代码的已存在对象。
在这里插入图片描述
Fastjson 目标:

  • 在服务器端和 android 客户端上提供最佳性能。
  • 提供简单的toJSONString()parseObject()方法将 Java 对象转换为 JSON,反之亦然。
  • 允许预先存在的不可修改对象与 JSON 之间的转换。
  • 广泛支持 Java 泛型。
  • 允许对象的自定义表示。
  • 支持任意复杂的对象(具有深度继承层次结构和广泛使用泛型类型)。
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.73</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.1.72.android</version>
</dependency>

Fastjson 是阿里巴巴开源的 JSON 解析库,它可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean。fastjson 已经被广泛使用在各种场景,包括 cache 存储、RPC 通讯、MQ 通讯、网络协议通讯、Android 客户端、Ajax 服务器处理程序等等。

Fastjson 的 API 十分简洁:

String text = JSON.toJSONString(obj); //序列化
VO vo = JSON.parseObject("{...}", VO.class); //反序列化

2. JSON 对象使用

com.alibaba.fastjson.JSON这个类是 fastjson API 的入口,主要的功能都通过这个类提供。

2.1. String 转 JSON

对于字符串的处理,主要是看这个字符串(jsonStr)是 JSON 对象格式还是 JSON 数组格式,然后选择对应的方法处理就行。

JSON 对象字符串转为 JSON 对象:

JSONObject jsonObj = JSON.parseObject(jsonStr);

JSON 数组字符串转为 JSON 数组对象:

JSONArray jsonArr = JSON.parseArray(jsonStr);

2.2. String 转 JavaBean

Model model = JSON.parseObject(jsonStr, Model.class);

2.3. Object 转 String

包括 JSONObject、JSONArray、JavaBean、数组、List、Set、Map 都可以通过这种方式转 String。

String jsonStr = JSON.toJSONString(object);

3. @JSONField 注解使用

这是一个注解,用于配置在 JavaBean,可以配置在 getter/setter 方法或者字段上,也可以直接配置在属性上。

注意:若属性是私有的,必须有 set* 方法。否则无法反序列化。

部分属性示例:

//配置序列化的字段顺序(1.1.42版本之后才支持)
@JSONField(ordinal=1)
//是否参与序列化:该字段不输出,但是如果加了final,这个字段就无法被过滤
@JSONField(serialize=false)
//是否参与反序列化:该字段不输出,但是如果加了final,这个字段就无法被过滤
@JSONField(derialize=false)  
//日期按照指定格式序列化
@JSONField(format="yyyy-MM-dd HH:mm:ss")
//使用字段别名
@JSONField(name="别名")
//序列化规则
@JSONField(serialzeFeatures={SerialzeFeatures属性})
//反序列化规则
@JSONField(parseFeatures={Features属性});

3.1. 序列化 SerializerFeature 属性

public enum SerializerFeature {
    /**
     * 输出key时是否使用双引号,默认为true
     */
    QuoteFieldNames,
    /**
     * 使用单引号而不是双引号,默认为false
     */
    UseSingleQuotes,
    /**
     * 是否输出值为null的字段,默认为false
     */
    WriteMapNullValue,
    /**
     * 用枚举toString()值输出
     */
    WriteEnumUsingToString,
    /**
     * 用枚举name()输出
     */
    WriteEnumUsingName,
    /**
     * Date使用ISO8601格式输出,默认为false
     */
    UseISO8601DateFormat,
    /**
     * @since 1.1
     * List字段如果为null,输出为[],而非null
     */
    WriteNullListAsEmpty,
    /**
     * @since 1.1
     * 字符类型字段如果为null,输出为"",而非null
     */
    WriteNullStringAsEmpty,
    /**
     * @since 1.1
     * 数值字段如果为null,输出为0,而非null
     */
    WriteNullNumberAsZero,
    /**
     * @since 1.1
     * Boolean字段如果为null,输出为false,而非null
     */
    WriteNullBooleanAsFalse,
    /**
     * @since 1.1
     * 如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true
     */
    SkipTransientField,
    /**
     * @since 1.1
     * 按字段名称排序后输出。默认为false
     */
    SortField,
    /**
     * @since 1.1.1
     * 把\t做转义输出,默认为false(不推荐,已删除)
     */
    @Deprecated
    WriteTabAsSpecial,
    /**
     * @since 1.1.2
     * 结果是否格式化,默认为false
     */
    PrettyFormat,
    /**
     * @since 1.1.2
     * 序列化时写入类型信息,默认为false。反序列化时需用到
     */
    WriteClassName,
    /**
     * @since 1.1.6
     * 消除对同一对象循环引用的问题,默认为false
     */
    DisableCircularReferenceDetect,
    /**
     * @since 1.1.9
     * 对斜杠"/"进行转义
     */
    WriteSlashAsSpecial,
    /**
     * @since 1.1.10
     * 将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6,默认为false
     */
    BrowserCompatible,
    /**
     * @since 1.1.14
     * 全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);
     */
    WriteDateUseDateFormat,
    /**
     * @since 1.1.15
     */
    NotWriteRootClassName,
    /**
     * @since 1.1.19
     * 一个对象的字符串属性中如果有特殊字符如双引号,将会在转成json时带有反斜杠转移符。如果不需要转义,可以使用这个属性。默认为false
     */
    DisableCheckSpecialChar,
    /**
     * @since 1.1.35
     * 将对象转为array输出
     */
    BeanToArray,
    /**
     * @since 1.1.37
     */
    WriteNonStringKeyAsString,   
    /**
     * @since 1.1.42
     */
    NotWriteDefaultValue,    
    /**
     * @since 1.2.6
     */
    BrowserSecure,    
    /**
     * @since 1.2.7
     */
    IgnoreNonFieldGetter,   
    /**
     * @since 1.2.9
     */
    WriteNonStringValueAsString,    
    /**
     * @since 1.2.11
     */
    IgnoreErrorGetter;

}

3.2. 反序列化 Feature 属性

public enum Feature {
    /**
     * 这个特性,决定了解析器是否将自动关闭那些不属于parser自己的输入源。 
     * 如果禁止,则调用应用不得不分别去关闭那些被用来创建parser的基础输入流InputStream和reader;
     * 如果允许,parser只要自己需要获取closed方法(当遇到输入流结束,或者parser自己调用 JsonParder#close方法),就会处理流关闭。
     * 注意:这个属性默认是true,即允许自动关闭流
     */
    AutoCloseSource,
    /**
     * 该特性决定parser将是否允许解析使用Java/C++ 样式的注释(包括'/'+'*' 和'//' 变量)。 
     * 由于JSON标准说明书上面没有提到注释是否是合法的组成,所以这是一个非标准的特性;尽管如此,这个特性还是被广泛地使用。
     * 注意:该属性默认是false,因此必须显式允许,即通过JsonParser.Feature.ALLOW_COMMENTS 配置为true。
     */
    AllowComment,
    /**
     * 这个特性决定parser是否将允许使用非双引号属性名字, (这种形式在Javascript中被允许,但是JSON标准说明书中没有)。
     * 注意:由于JSON标准上需要为属性名称使用双引号,所以这也是一个非标准特性,默认是false的。
     * 同样,需要设置JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES为true,打开该特性。
     */
    AllowUnQuotedFieldNames,
    /**
     * 该特性决定parser是否允许单引号来包住属性名称和字符串值。
     * 注意:默认下,该属性也是关闭的。需要设置JsonParser.Feature.ALLOW_SINGLE_QUOTES为true
     */
    AllowSingleQuotes,
    /**
     * 该特性决定JSON对象属性名称是否可以被String#intern 规范化表示。如果允许,则JSON所有的属性名将会 intern() ;
     * 如果不设置,则不会规范化,默认下,该属性是开放的。此外,必须设置CANONICALIZE_FIELD_NAMES为true
     * 关于intern方法作用:当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串 (该对象由 equals(Object) 方法确定),则返回池中的字符串。
     * 否则,将此 String 对象添加到池中, 并且返回此 String 对象的引用。
     */
    InternFieldNames,
    /**
     * 这个设置为true则遇到字符串符合ISO8601格式的日期时,会直接转换成日期类。
     */
    AllowISO8601DateFormat,
    /**
     * 允许多重逗号,如果设为true,则遇到多个逗号会直接跳过。
     * {"a":1,,,"b":2}
     */
    AllowArbitraryCommas,
    /**
     * 这个设置为true则用BigDecimal类来装载数字,否则用的是double;
     */
    UseBigDecimal,  
    /**
     * @since 1.1.2 
     * 忽略不匹配
     */
    IgnoreNotMatch,
    /**
     * @since 1.1.3
     * 如果你用fastjson序列化的文本,输出的结果是按照fieldName排序输出的,parser时也能利用这个顺序进行优化读取。这种情况下,parser能够获得非常好的性能
     */
    SortFeidFastMatch,  
    /**
     * @since 1.1.3
     * 禁用ASM
     */
    DisableASM, 
    /**
     * @since 1.1.7
     * 禁用循环引用检测
     */
    DisableCircularReferenceDetect,    
    /**
     * @since 1.1.10
     * 对于没有值的字符串属性设置为空串
     */
    InitStringFieldAsEmpty,   
    /**
     * @since 1.1.35
     * 支持数组to对象
     */
    SupportArrayToBean,   
    /**
     * @since 1.2.3
     * 属性保持原来的顺序
     */
    OrderedField,  
    /**
     * @since 1.2.5
     * 禁用特殊字符检查
     */
    DisableSpecialKeyDetect,
    
    /**
     * @since 1.2.9
     * 使用对象数组
     */
    UseObjectArray;

}

3.3. 测试代码

JavaBean:

class User {
    
    //指定序列化字段顺序,字段名称
    @JSONField(ordinal=4,name="ID")
    private Integer id;
    
    //指定序列化字段顺序,不参加序列化
    @JSONField(ordinal=3,serialize=false)
    private String name; 
    
    //指定序列化字段顺序,不参加反序列化
    @JSONField(ordinal=2,deserialize=false)
    private Integer age;
    
    //指定序列化字段顺序,日期格式
    @JSONField(ordinal=1,format="yyyy-MM-dd")
    private Date creattime;
    
    //指定序列化规则,字段为null的时候依然参加序列化
    @JSONField(serialzeFeatures=SerializerFeature.WriteMapNullValue)
    private String phone;
  
    public Integer getId() {return id;}
    public Date getCreattime() {return creattime;}
    public void setId(Integer id) {this.id = id;}
    public void setCreattime(Date creattime) {this.creattime = creattime;}
    public String getName() {return name;}  
    public void setName(String name) {this.name = name;}  
    public Integer getAge() {return age;}  
    public void setAge(Integer age) {this.age = age;}
    public String getPhone() {return phone;}
    public void setPhone(String phone) {this.phone = phone;}

    @Override
    public String toString() {
        return "id="+id+"; name="+name+"; age="+age+"; createtime="+creattime;
    }
    
};

测试代码:

User user = new User();
user.setId(123456);
user.setName("wangbo");
user.setAge(28);
user.setCreattime(new Date());
        
String userStr = JSON.toJSONString(user);
System.out.println(userStr);
        
User user2 = JSON.parseObject(userStr, User.class);
System.out.println(user2);

执行结果:
userStr

{"phone":null,"creattime":"2018-12-04","age":28,"ID":123456}

user2

id=123456; name=null; age=null; createtime=Tue Dec 04 00:00:00 CST 2018

可以看出:

第一步序列化的结果:按照指定字段顺序序列化的,id 字段序列化为 ID,name 没有参加序列化,createtime 按照指定格式序列化,phone 为 null,但是参与了序列化。

FastJson 默认的序列化规则是字段的值为 null 的时候,不参与序列化,serialzeFeatures=SerializerFeature.WriteMapNullValue可以在 value 的值为null 的时候,依然会把它的值序列化出来。

第二部反序列化结果:age 没有参与反序列化。

4. JSONPath 对象使用

FastJson 1.2.0 之后的版本支持 JSONPath。这是一个很强大的功能,可以在Java 框架中当作对象查询语言(OQL)来使用。

4.1. API 方法

public class JSONPath {
    
    //求值,静态方法
    public static Object eval(Object rootObject, String path);

    //计算size,Map非空元素个数,对象非空元素个数,Collection的Size,数组的长度。其他无法求值返回-1
    public static int size(Object rootObject, String path);

    //是否包含,path中是否存在对象
    public static boolean contains(Object rootObject, String path);

    //是否包含,path中是否存在指定值,如果是集合或者数组,在集合中查找value是否存在
    public static boolean containsValue(Object rootObject, String path, Object value);

    //在数组或者集合中添加元素
    public static void arrayAdd(Object rootObject, String path, Object... values);

    //修改制定路径的值,如果修改成功,返回true,否则返回false
    public static boolean set(Object rootObject, String path, Object value);

}

4.2. 语法

JSONPATH描述
$根对象,例如$.name
[num]数组访问,其中num是数字,可以是负数。例如$[0].leader.departments[-1].name
[num0,num1,num2…]数组多个元素访问,其中num是数字,可以是负数,返回数组中的多个元素。例如$[0,3,-2,5]
[start:end]数组范围访问,其中start和end是开始小表和结束下标,可以是负数,返回数组中的多个元素。例如$[0:5]
[start:end :step]数组范围访问,其中start和end是开始小表和结束下标,可以是负数;step是步长,返回数组中的多个元素。例如$[0:5:2]
[?(key)]对象属性非空过滤,例如$.departs[?(name)]
[key > 123]数值类型对象属性比较过滤,例如$.departs[id >= 123],比较操作符支持=,!=,>,>=,<,<=
[key = ‘123’]字符串类型对象属性比较过滤,例如$.departs[name = ‘123’],比较操作符支持=,!=,>,>=,<,<=
[key like ‘aa%’]字符串类型like过滤,例如$.departs[name like ‘sz*’],通配符只支持%,支持not like
[key rlike ‘regexpr’]字符串类型正则匹配过滤,例如departs[name like ‘aa(.)*’],正则语法为jdk的正则语法,支持not rlike
[key in (‘v0’, ‘v1’)]IN过滤, 支持字符串和数值类型。例如:
$.departs[name in ('wenshao','Yako')]
$.departs[id not in (101,102)]
[key between 234 and 456]BETWEEN过滤, 支持数值类型,支持not between。例如:
$.departs[id between 101 and 201]
$.departs[id not between 101 and 201]
length() 或者 size()数组长度。例如$.values.size()。支持类型java.util.Map、java.util.Collection和数组
.属性访问,例如$.name
..deepScan属性访问,例如$..name
*对象的所有属性,例如$.leader.*
[‘key’]属性访问。例如$[‘name’]
[‘key0’,‘key1’]多个属性访问。例如$[‘id’,‘name’]

注意:以下两种写法的语义是相同的:

$.store.book[0].title
$['store']['book'][0]['title']

语法示例

JSONPath语义
$根对象
$[-1]最后元素
$[:-2]第1个至倒数第2个
$[1:]第2个之后所有元素
$[1,2,3]集合中1,2,3个元素

4.3. 代码示例

package com.wangbo.fastjson;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;

public class Test {
    
    public static void main(String[] args) {
        String jsonStr = "{\n" +
                "    \"store\": {\n" +
                "        \"bicycle\": {\n" +
                "            \"color\": \"red\",\n" +
                "            \"price\": 19.95\n" +
                "        },\n" +
                "        \"book\": [\n" +
                "            {\n" +
                "                \"author\": \"刘慈欣\",\n" +
                "                \"price\": 8.95,\n" +
                "                \"category\": \"科幻\",\n" +
                "                \"title\": \"三体\"\n" +
                "            },\n" +
                "            {\n" +
                "                \"author\": \"itguang\",\n" +
                "                \"price\": 12.99,\n" +
                "                \"category\": \"编程语言\",\n" +
                "                \"title\": \"go语言实战\"\n" +
                "            }\n" +
                "        ]\n" +
                "    }\n" +
                "}";

        JSONObject jsonObject = JSON.parseObject(jsonStr);

        System.out.println(jsonObject.toString());

        //得到所有的书
        List<Book> books = (List<Book>) JSONPath.eval(jsonObject, "$.store.book");
        System.out.println("books=" + books);

        //得到所有的书名
        List<String> titles = (List<String>) JSONPath.eval(jsonObject, "$.store.book.title");
        System.out.println("titles=" + titles);

        //第一本书title
        String title = (String) JSONPath.read(jsonStr, "$.store.book[0].title");
        System.out.println("title=" + title);

        //price大于10元的book
        List<Book> list = (List<Book>) JSONPath.read(jsonStr, "$.store.book[price > 10]");
        System.out.println("price大于10元的book="+ list);

        //price大于10元的title
        List<String> list2 =(List<String>) JSONPath.read(jsonStr, "$.store.book[price > 10].title");
        System.out.println("price大于10元的title=" + list2);

        //category(类别)为科幻的book
        List<Book> list3 = (List<Book>) JSONPath.read(jsonStr,"$.store.book[category = '科幻']");
        System.out.println("category(类别)为科幻的book=" + list3);

        //bicycle的所有属性值
        Collection<String> values = (Collection<String>) JSONPath.eval(jsonObject, "$.store.bicycle.*");
        System.out.println("bicycle的所有属性值={}" + values);

        //bicycle的color和price属性值
        List<String> read =(List<String>) JSONPath.read(jsonStr, "$.store.bicycle['color','price']");
        System.out.println("bicycle的color和price属性值=" + read);

    }

}

运行结果

{"store":{"bicycle":{"color":"red","price":19.95},"book":[{"author":"刘慈欣","price":8.95,"category":"科幻","title":"三体"},{"author":"itguang","price":12.99,"category":"编程语言","title":"go语言实战"}]}}
books=[{"author":"刘慈欣","price":8.95,"category":"科幻","title":"三体"},{"author":"itguang","price":12.99,"category":"编程语言","title":"go语言实战"}]
titles=["三体","go语言实战"]
title=三体
price大于10元的book=[{"author":"itguang","price":12.99,"category":"编程语言","title":"go语言实战"}]
price大于10元的title=["go语言实战"]
category(类别)为科幻的book=[{"author":"刘慈欣","price":8.95,"category":"科幻","title":"三体"}]
bicycle的所有属性值={}[red, 19.95]
bicycle的color和price属性值=[red, 19.95]

5. 遇到问题

遇到一个问题,方法参数传过来是一个Object,其实是个JSON格式的字符串,我在使用JSON.toJSONString(object)方法转化为String,然后通过JSON.parseObject(string)方法转化为JSONObject的时候报错了,提示can not cast to JSONObject.错误。

测试代码:

package com.gtcom.governance.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * @author wangbo
 * @date 2021/6/23
 */
public class TestJson {
    public static void main(String[] args) {
        Object string = "{\"name\":\"zhangsan\"}";

        System.out.println(string);
        System.out.println("========");

        JSONObject jsonObject1 = JSON.parseObject(string.toString());
        System.out.println(jsonObject1);
        System.out.println("========");

        String jsonStr = JSON.toJSONString(string);
        System.out.println(jsonStr);
        System.out.println("========");

        JSONObject jsonObject2 = JSON.parseObject(jsonStr);
        System.out.println(jsonObject2);
    }
}

控制台输出:

{"name":"zhangsan"}
========
{"name":"zhangsan"}
========
"{\"name\":\"zhangsan\"}"
========
Exception in thread "main" com.alibaba.fastjson.JSONException: can not cast to JSONObject.
	at com.alibaba.fastjson.JSON.parseObject(JSON.java:262)
	at com.gtcom.governance.utils.TestJson.main(TestJson.java:25)
Caused by: java.lang.ClassCastException: class java.lang.String cannot be cast to class com.alibaba.fastjson.JSONObject (java.lang.String is in module java.base of loader 'bootstrap'; com.alibaba.fastjson.JSONObject is in unnamed module of loader 'app')
	at com.alibaba.fastjson.JSON.parseObject(JSON.java:260)
	... 1 more

结论:

JSON.toJSONString(object)方法将转义符也写入字符串了,再进行JSONObject转化就会报异常。所以对于String类型的Object直接使用toString方法就行。

6. 序列化规则

6.1. 自定义序列化规则

package com.gtcom.web.json;

import com.alibaba.fastjson.serializer.ValueFilter;
import org.apache.commons.lang3.ObjectUtils;

/**
 * 空列表序列化
 *
 * @author wangbo
 * @date 2021/11/9
 */
public class EmptyListFilter implements ValueFilter {

    @Override
    public Object process(Object object, String name, Object value) {
        if (ObjectUtils.isEmpty(value)) {
            return null;
        }
        return value;
    }
}

空 List 不会被序列化:

private final static ValueFilter VALUE_FILTER = new EmptyListFilter();

User user = new User();
JSON.toJSONString(user, VALUE_FILTER);

如果 User 对象中有一个 List 字段,则:

  • 未使用该自定义序列化规则:List 字段为 null,序列化结果不包含该字段;List 字段为空,序列化结果包含该字段。
  • 使用了该自定义序列化规则:List 字段为 null,序列化结果不包含该字段;List 字段为空,序列化结果不包含该字段。
<think>好的,用户现在想了解如何使用Fastjson返回JSON数据。首先,我需要回顾一下之前用户的提问历史。之前他们遇到了关于dataService类未注册的问题,可能是在Spring项目中遇到的问题,现在转向了JSON数据的处理,可能是同一个项目中的需求。 用户的问题比较直接,但需要详细解答。首先,我需要确定他们是否在使用Spring框架,因为不同的框架(如Spring MVC或Spring Boot)返回JSON的方式可能不同,而Fastjson作为阿里巴巴的库,通常用来替代默认的Jackson。 接下来,我需要考虑用户可能的场景。他们可能在开发一个Web应用,需要将Java对象转换为JSON返回给前端。可能遇到的问题包括依赖配置错误、注解使用不当或日期格式处理等。用户可能已经尝试过默认的Jackson,但希望切换为Fastjson,或者需要更高性能的JSON库。 然后,我需要整理回答的结构。首先介绍基本用法,比如如何将对象转换为JSON字符串。然后,结合Spring框架,说明如何配置Fastjson作为消息转换器。同时,要提醒用户注意依赖冲突,确保正确引入Fastjson的包,并排除默认的Jackson,如果存在的话。 还要提到常见问题,比如循环引用、日期格式化、字段过滤等,这些是实际开发中经常遇到的。给出示例代码和配置步骤,确保用户能够一步步操作。此外,可能需要对比Fastjson和其他库的优缺点,但用户主要关注使用方法,所以重点放在配置和示例上。 需要注意用户可能对Spring的配置不熟悉,尤其是如何替换默认的转换器。需要详细说明在Spring Boot中如何通过继承WebMvcConfigurer来添加自定义的HttpMessageConverter。同时,强调注解的使用,比如@JSONField,用于自定义字段名称和格式。 最后,要检查是否有遗漏的部分,比如版本兼容性问题,或者常见的错误配置,比如忘记排除Jackson导致转换器冲突。确保提供的代码示例准确,特别是包导入和配置类的正确写法。可能还需要提醒用户查看官方文档,以获取最新的配置方法,因为库的更新可能会导致配置方式的变化。</think>--- ### FastJSON返回JSON数据完整指南 使用阿里巴巴开源的FastJSON进行JSON数据处理时,主要涉及 **序列化**(Java对象转JSON)和 **反序列化**(JSON转Java对象)两个核心操作。以下是具体实现方案: --- #### 一、基础环境配置 1. **添加Maven依赖** ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>2.0.39</version> <!-- 使用最新稳定版本 --> </dependency> ``` 2. **Spring Boot中排除默认JSON库**(可选) 若需要完全替换Jackson,在`pom.xml`添加: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-json</artifactId> </exclusion> </exclusions> </dependency> ``` --- #### 二、基础序列化操作 ```java // 创建Java对象 public class User { private String username; private int age; // 必须提供getter/setter方法 } // 序列化操作 User user = new User(); user.setUsername("John"); user.setAge(25); // 转换为JSON字符串(标准模式) String jsonString = JSON.toJSONString(user); // 输出结果:{"age":25,"username":"John"} // 美化输出(带缩进) String prettyJson = JSON.toJSONString(user, SerializerFeature.PrettyFormat); ``` --- #### 三、与Spring框架集成 ##### 1. 配置FastJSON消息转换器(Spring MVC) ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { // 创建FastJSON转换器 FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); // 配置序列化规则 FastJsonConfig config = new FastJsonConfig(); config.setSerializerFeatures( SerializerFeature.WriteMapNullValue, // 保留null字段 SerializerFeature.WriteDateUseDateFormat, // 日期格式化 SerializerFeature.PrettyFormat // 美化输出 ); config.setDateFormat("yyyy-MM-dd HH:mm:ss"); // 日期格式 converter.setFastJsonConfig(config); converters.add(0, converter); // 优先使用FastJSON } } ``` ##### 2. Controller层使用示例 ```java @RestController public class UserController { // 直接返回对象即可自动转换 @GetMapping("/user") public User getUser() { return new User("Alice", 28); } // 返回复杂结构 @GetMapping("/users") public Map<String, Object> getUsers() { Map<String, Object> result = new HashMap<>(); result.put("code", 200); result.put("data", Arrays.asList( new User("Bob", 30), new User("Charlie", 22) )); return result; } } ``` --- #### 四、高级特性配置 ##### 1. 自定义字段名称与忽略字段 ```java public class Product { @JSONField(name = "product_name") // 自定义JSON字段名 private String productName; @JSONField(serialize = false) // 忽略该字段 private String secretKey; // 其他字段... } ``` ##### 2. 日期格式化处理 ```java public class Order { @JSONField(format = "yyyy/MM/dd") private Date createTime; // 若未指定格式,使用全局配置的日期格式 private Date updateTime; } ``` ##### 3. 处理循环引用 ```java // 在序列化时配置 String json = JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect // 关闭循环引用检测 ); ``` --- #### 五、常见问题排查 | 问题现象 | 解决方案 | |------------------------------|--------------------------------------------------------------------------| | 返回HTML而不是JSON | 检查`@RestController`注解是否正确,或方法是否误用`@Controller` | | 日期字段显示为时间戳 | 确认是否配置`SerializerFeature.WriteDateUseDateFormat`及日期格式 | | 字段值为null时未显示 | 启用`SerializerFeature.WriteMapNullValue` | | 中文乱码 | 在消息转换器中设置`SupportedMediaType.APPLICATION_JSON_UTF8` | | 复杂对象转换失败 | 检查是否所有嵌套对象都实现序列化接口,或使用`@JSONType`注解配置 | --- #### 六、性能优化建议 1. **重用JSON实例** ```java // 创建全局配置实例 private static final FastJsonConfig config = new FastJsonConfig(); // 复用Parser和Serializer JSON.parseObject(jsonString, User.class, config.getParserConfig()); ``` 2. **关闭冗余特性** ```java config.setSerializerFeatures( SerializerFeature.WriteNullListAsEmpty, // 仅开启必要特性 SerializerFeature.WriteNullStringAsEmpty ); ``` 3. **使用`JSONPath`进行高效查询** ```java String jsonStr = "{'store':{'book':[{'price':35.6}]}}"; Object price = JSONPath.eval(jsonStr, "$.store.book[0].price"); // 35.6 ``` --- 通过合理配置FastJSON,可以实现比原生Jackson **快2-3倍** 的序列化速度(根据官方基准测试)。建议根据实际业务需求选择合适的序列化策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值