Fastjson 使用指南

文章目录

  • [Fastjson 使用指南](#Fastjson 使用指南)

w3school
JSON格式化
序列化操作

Fastjson 使用指南

0 简要说明

Fastjson是一个Java语言编写的高性能功能完善的SON库。它采用一种"假定有序快速匹配"的算法,把JSON Parse的性能提升到极致,是目前)ava语言中最快的)SON库。Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。

主要特点:

快速FAST(比其它任何基于Java的解析器和生成器更快,包括jackson)

强大(支持普通DK类包括任意Java Bean Class、Collection、Map、Date或enum)

零依赖(除了DK没有依赖其它任何类库)

为什么要用JSON?用JSON的好处是什么?

1.首先JSON是一种数据格式,我们HTTP请求交互/内容存储到JSON,我们可以替代的方案就是XML,或者直接文本,当然首先是是使用JSON或者XML,其次才是文本,因为您考虑到存储方便也要考虑解析方便。

2.JSON是一个轻量级的数据格式,轻量级是相比较XML等其他复杂的存储格式而言,各个语言都兼容,都有各自解析JSON的组件。

为什么要用JSON?

1.其实用JSON主要是因为它轻量,各个平台语言都支持JSON交互、JSON解析和存储。

2.JSON常用于我们接口交互,前后端交互中,有解析速度快,方便的特点。

3.JSON常用于我们一些配置文件也是因为解析方便,JSON存储数据体积小等特征,而不像XML、PList(也是xml的一种)等格式,定义各种Dom节点(当然复杂的格式还是建议XML)。

JSON好处

1.JSON是大家公认的传输格式,所以学习成本低,程序员之间交流经常会问,您接口返回什么格式?答曰:"JSON",其实就没啥问题了。

2.各个语言、各个框架(第三方组件)都支持JSON,所以使用上来讲,复用率更高,不用格式转来转去。

3.上面也讲了,体积小、解析速度快。

1 常用数据类型的JSON格式

值的范围

  • Number:数字(整数或浮点数)
  • String:字符串(在双引号中),一定是英文双引号(""),个别弱语言可以支持单引号。
  • Boolean:逻辑值(true 或 false)
  • Array:数组(在方括号中),一般是在Value位置上。
  • Object:对象(在花括号中),一般是在Value位置上。
  • null:没什么好说的。
json 复制代码
{"key":"value"},最简单的JSON 格式。
{"key1":"value1","key2":"value2"},一个JSON中有多个键值对的表达方式。
{"key":["a","b","sojson.com"]},value是一个Array 的JSON格式。
{"sojson":["5年","JSON在线解析","sojson.com",true,1,null]},value是一个Array 的JSON格式,并且这个数组中有多重类型的元素,有String,Boolean,Number,null。
{"key":{"json":"json for javascript"}},value 是JSONObject的JSON格式。

2 快速上手

2.1 依赖

仓库地址

xml 复制代码
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.51</version>
        </dependency>

https://www.sojson.com/

2.2 实体类

java 复制代码
package com.geekmice.springbootselfexercise.domain;

import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelIgnore;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Date;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserDomain implements Serializable {

    /**
     * 用户名
     */
    private String userName;
    /**
     * 生日
     */
    private Date birthday;
    /**
     * 性别
     */
    private String sex;
    /**
     * 地址
     */
    private String address;

}

2.3 测试类

java 复制代码
    /**
     * 处理fastjson
     */
    @Test
    public void validateFastJson() {
        UserDomain user = UserDomain.builder()
                .userName("胡汉三").sex("男")
                .birthday(new Date()).address("123@163.com").build();
        String userJsonString = JSON.toJSONString(user);
        log.info("userJsonString : [\n{}\n]", userJsonString);
    }

14:36:33.649 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - userJsonString : [

{"address":"123@163.com","birthday":1691562993337,"sex":"男","userName":"胡汉三"}

]

3 常见用法

3.1 序列化操作

序列化:将一个对象编码成一个字节流(I/O),序列化的目的是为了方便数据的传递以及存储到磁盘上(把一个Java对象写入到硬盘或者传输到网路上面的其它计算机,这时我们就需要将对象转换成字节流才能进行网络传输。对于这种通用的操作,就出现了序列化来统一这些格式)。

核心操作

java 复制代码
    /**
     * This method serializes the specified object into its equivalent Json representation. Note that this method works fine if the any of the object fields are of generic type,
     * just the object itself should not be of a generic type. If you want to write out the object to a
     * {@link Writer}, use {@link #writeJSONString(Writer, Object, SerializerFeature[])} instead.
     *
     * @param object the object for which json representation is to be created setting for fastjson
     * @return Json representation of {@code object}.
     */
String jsonString = JSON.toJSONString(obj);

对象转换为JSON串

java 复制代码
    /**
     * 处理fastjson
     */
    @Test
    public void validateFastJson() {
        log.info("序列化操作开始,对象转换JSON串");
        UserDomain user = UserDomain.builder()
                .userName("胡汉三").sex("男")
                .birthday(new Date()).address("123@163.com").build();
        String userJsonString = JSON.toJSONString(user);
        log.info("userJsonString : [\n\n{}\n\n]", userJsonString);

    }

14:59:16.377 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - userJsonString : [
{"address":"123@163.com","birthday":1691564356144,"sex":"男","userName":"胡汉三"}
]

list转换JSON串

java 复制代码
    /**
     * 处理fastjson
     */
    @Test
    public void validateFastJson() {
    
        log.info("序列化操作开始,list转换JSON串");
         List<UserDomain> result = Arrays.asList(
                UserDomain.builder()
                        .userName("胡汉三").sex("男")
                        .birthday(new Date()).address("123@163.com").build(),
                UserDomain.builder()
                        .userName("笑笑").sex("女")
                        .birthday(new Date()).address("345@163.com").build()
        );
        String listStr = JSON.toJSONString(result);
        log.info("listStr : [\n\n{}\n\n]" , listStr);

     

    }

14:59:16.381 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - listStr : [

{"address":"123@163.com","birthday":1691564356380,"sex":"男","userName":"胡汉三"},{"address":"345@163.com","birthday":1691564356380,"sex":"女","userName":"笑笑"}

]

map转换为JSON串

java 复制代码
    /**
     * 处理fastjson
     */
    @Test
    public void validateFastJson() {

        log.info("序列化操作开始,map转换JSON串");
        HashMap<Object, Object> map = Maps.newHashMap();
        map.put("name","小三子");
        map.put("age",10);
        final String mapStr = JSON.toJSONString(map);
        log.info("mapStr : [\n\n{}\n\n]" , mapStr);

    }

14:59:16.398 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - mapStr : [

{"name":"小三子","age":10}

]

3.2 反序列化操作

JSON串转换为对象

java 复制代码
        String userJsonString="{\"address\":\"123@163.com\",\"birthday\":1691564927544,\"sex\":\"男\",\"userName\":\"胡汉三\"}";
        log.info("反序列化开始,JSON串转换对象");
        UserDomain nonUser = JSON.parseObject(userJsonString, UserDomain.class);
        log.info("nonUser : [{}]" , nonUser);

15:08:47.859 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - 反序列化开始,JSON串转换对象

15:08:47.903 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - nonUser : [UserDomain(id=null, userName=胡汉三, birthday=Wed Aug 09 15:08:47 CST 2023, sex=男, address=123@163.com)]

JSON串转换为map

java 复制代码
        String mapStr="{\"name\":\"小三子\",\"age\":10}";
        log.info("反序列化开始,JSON串转换map");
        Map<Object, Object> nonMap = JSON.parseObject(mapStr, new TypeReference<Map<Object, Object>>() {
        });
        log.info("nonMap : [{}]" , nonMap);

15:08:47.903 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - 反序列化开始,JSON串转换map

15:08:47.906 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - nonMap : [{name=小三子, age=10}]

JSON串转换为list

java 复制代码
                String listStr ="{\"address\":\"123@163.com\",\"birthday\":1691564927840,\"sex\":\"男\",\"userName\":\"胡汉三\"},{\"address\":\"345@163.com\",\"birthday\":1691564927840,\"sex\":\"女\",\"userName\":\"笑笑\"}"
        log.info("反序列化开始:JSON串转换为list");
        List<UserDomain> nonUserList = JSON.parseArray(listStr, UserDomain.class);
        log.info("nonUserList : [{}]" , nonUserList);

15:08:47.906 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - 反序列化开始:JSON串转换为list

15:08:47.906 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - nonUserList : [[UserDomain(id=null, userName=胡汉三, birthday=Wed Aug 09 15:08:47 CST 2023, sex=男, address=123@163.com), UserDomain(id=null, userName=笑笑, birthday=Wed Aug 09 15:08:47 CST 2023, sex=女, address=345@163.com)]]

4 常见问题

4.1 如何处理日期毫秒值问题

方案一:使用 @JSONField(format = DateUtils.DATE_FORMAT_10)

format属性指定时间日期格式,只是针对于某几个字段,使用了这个注解有效

方案二:通过代码实现,这种形式所有date类型都是指定时间格式 yyyy-MM-dd

java 复制代码
String result = JSON.toJSONStringWithDateFormat(user, com.alibaba.excel.util.DateUtils.DATE_FORMAT_10);

4.2 定制化序列化字段

4.3 指定某些字段不序列化

@JSONField(serialize= false)

4.4 自定义序列化器

1 定义

java 复制代码
package com.geekmice.springbootselfexercise.serializer;


import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.ObjectSerializer;
import com.alibaba.fastjson.serializer.SerializeWriter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.io.IOException;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.util.Date;
import java.util.Objects;

/**
 * @BelongsProject: spring-boot-self-exercise
 * @BelongsPackage: com.geekmice.springbootselfexercise.serializer
 * @Author: pingmingbo
 * @CreateTime: 2023-08-09  15:59
 * @Description: TODO
 * @Version: 1.0
 */
@Slf4j
public class MyDateSerializer implements ObjectSerializer, ObjectDeserializer {

    @Override
    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
        // 序列化,
        // log.info("serializer : [{}]" , serializer); // 数据源
        // log.info("object : [{}]" , object); // 字段值
        // log.info("fieldName : [{}]" , fieldName); // 字段名称
        // log.info("fieldType : [{}]" , fieldType);// 类型
        if (Objects.isNull(object)) {
            return;
        }
        String dateStr = object.toString();
        Date date = null;
        if (StringUtils.isNotBlank(dateStr)) {
            try {
                date = DateUtils.parseDate(dateStr, com.alibaba.excel.util.DateUtils.DATE_FORMAT_19);
            } catch (ParseException e) {
                log.error("error msg:【{}】", e);
                throw new IllegalArgumentException(e);
            }
        }
        long time = date.getTime();
        SerializeWriter writer = serializer.getWriter();
        writer.writeLong(time);
    }

    @Override
    public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
        return null;
    }

    @Override
    public int getFastMatchToken() {
        return 0;
    }
}

2.实体类添加

java 复制代码
    // @JSONField(ordinal = 7,format = DateUtils.DATE_FORMAT_10)
    @JSONField(ordinal = 7,serializeUsing = MyDateSerializer.class)
    private String testStrDate;

3.测试类使用

java 复制代码
        log.info("序列化操作开始,对象转换JSON串");
        TempData user = TempData.builder()
                .userName(null).sex("男")
                .birthday(new Date()).address("123@163.com")
                .logTime(new Date())
                .registerTime(new Date())
                .testStrDate("2023-08-09 23:22:21")
                .score(new BigDecimal("2384.23"))
                .build();
        // 字符串类型字段为null,不进行序列化
        String userJsonString = JSON.toJSONString(user, SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteNullStringAsEmpty,
                SerializerFeature.WriteNullNumberAsZero,
                SerializerFeature.WriteNullBooleanAsFalse
                );
        log.info("userJsonString : [\n\n{}\n\n]", userJsonString);

21:18:42.724 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - userJsonString : [
{"id":0,"username":"","sex":"男","address":"123@163.com","logTime":"2023-08-09 21:18:42","registerTime":1691587122488,"testStrDate":1691594541000,"score":2384.23}

]

4.5 使用ordinal指定字段的顺序

java 复制代码
package com.geekmice.springbootselfexercise.domain;

import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Date;

/**
 * @BelongsProject: spring-boot-self-exercise
 * @BelongsPackage: com.geekmice.springbootselfexercise.domain
 * @Author: pingmingbo
 * @CreateTime: 2023-08-07  09:53
 * @Description: Easy Excel 导入导出对应的实体类
 * @Version: 1.0
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TempData implements Serializable {

    private static final long serialVersionUID = 611155229642304781L;
    /**
     * 忽略这个字段
     */
    private Long id;

    /**
     * 用户名
     */
    @JSONField(name = "username",ordinal = 1)
    private String userName;
    /**
     * 生日
     */
    @JSONField(format = DateUtils.DATE_FORMAT_10,serialize = false,ordinal = 2)
    private Date birthday;
    /**
     * 性别
     */
    @JSONField(ordinal = 3)
    private String sex;
    /**
     * 地址
     */
    @JSONField(ordinal = 4)
    private String address;

    @JSONField(ordinal = 5)
    private Date registerTime;
}

4.6 序列化起别名

复制代码
@JSONField(name = "username", ordinal = 3)
@ExcelProperty(value = {"父级", "用户名"}, index = 0)
@JSONField(name = "username")
private String userName;

16:04:28.708 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - result : [{"address":"123@163.com","logTime":"2023-08-09","registerTime":"2023-08-09","sex":"男","username":"胡汉三"}]

4.7 空值序列化操作处理

SerializerFeature 描述
WriteNullListAsEmpty 将Collection类型字段的字段空值输出为[]
WriteNullStringAsEmpty 将字符串类型字段的空值输出为空字符串 ""
WriteNullNumberAsZero 将数值类型字段的空值输出为0
WriteNullNumberAsZero 将Boolean类型字段的空值输出为false
java 复制代码
        log.info("序列化操作开始,对象转换JSON串");
        TempData user = TempData.builder()
                .userName(null).sex("男")
                .birthday(new Date()).address("123@163.com")
                .logTime(new Date())
                .registerTime(new Date())
                .testStrDate("2023-07-18 23:22:21")
                .build();
        // 字符串类型字段为null,不进行序列化
        String userJsonString = JSON.toJSONString(user, SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteNullStringAsEmpty,
                SerializerFeature.WriteNullNumberAsZero,
                SerializerFeature.WriteNullBooleanAsFalse
                );

20:42:40.253 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - 序列化操作开始,对象转换JSON串

20:42:40.664 [main] INFO com.geekmice.springbootselfexercise.NoDaoTest - userJsonString : [

{"id":0,"username":"","sex":"男","address":"123@163.com","logTime":"2023-08-09 20:42:40","registerTime":1691584960267,"testStrDate":1689693741000,"score":0}

]

相关推荐
程序员小假28 分钟前
我们来说一下 MySQL 的慢查询日志
java·后端
独自破碎E1 小时前
Java是怎么实现跨平台的?
java·开发语言
To Be Clean Coder1 小时前
【Spring源码】从源码倒看Spring用法(二)
java·后端·spring
xdpcxq10291 小时前
风控场景下超高并发频次计算服务
java·服务器·网络
想用offer打牌1 小时前
你真的懂Thread.currentThread().interrupt()吗?
java·后端·架构
橘色的狸花猫1 小时前
简历与岗位要求相似度分析系统
java·nlp
独自破碎E2 小时前
Leetcode1438绝对值不超过限制的最长连续子数组
java·开发语言·算法
用户91743965392 小时前
Elasticsearch Percolate Query使用优化案例-从2000到500ms
java·大数据·elasticsearch
yaoxin5211232 小时前
279. Java Stream API - Stream 拼接的两种方式:concat() vs flatMap()
java·开发语言
坚持学习前端日记2 小时前
2025年的个人和学习年度总结以及未来期望
java·学习·程序人生·职场和发展·创业创新