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}

]

相关推荐
Hello-Brand3 分钟前
Java核心知识体系10-线程管理
java·高并发·多线程·并发·多线程模型·线程管理
乐悠小码9 分钟前
数据结构------队列(Java语言描述)
java·开发语言·数据结构·链表·队列
史努比.11 分钟前
Pod控制器
java·开发语言
2的n次方_13 分钟前
二维费用背包问题
java·算法·动态规划
皮皮林55114 分钟前
警惕!List.of() vs Arrays.asList():这些隐藏差异可能让你的代码崩溃!
java
莳光.14 分钟前
122、java的LambdaQueryWapper的条件拼接实现数据sql中and (column1 =1 or column1 is null)
java·mybatis
程序猿麦小七19 分钟前
基于springboot的景区网页设计与实现
java·spring boot·后端·旅游·景区
weisian15125 分钟前
认证鉴权框架SpringSecurity-2--重点组件和过滤器链篇
java·安全
蓝田~27 分钟前
SpringBoot-自定义注解,拦截器
java·spring boot·后端
.生产的驴29 分钟前
SpringCloud Gateway网关路由配置 接口统一 登录验证 权限校验 路由属性
java·spring boot·后端·spring·spring cloud·gateway·rabbitmq