重学springboot系列之JSON处理工具类:FastJSON、Gson和Jackson对比,Json常用注解,手动数据转换,全局配置:使用配置文件和代码,hutool工具解析json

重学springboot系列之JSON处理工具类

  • https://www.hicxy.com/24774.html

  • FastJSON、Gson和Jackson对比

  • 在Spring中注解方法使用Jackson

    • 常用注解
    • 手动数据转换
    • Bug
  • Jackson全局配置


FastJSON、Gson和Jackson对比

  • 开源的Jackson:SpringBoot默认是使用Jackson作为JSON数据格式处理的类库,Jackson在各方面都比较优秀,所以不建议将Jackson替换为Gson或fastjson。
  • Google的Gson:Gson是Google为满足内部需求开发的JSON数据处理类库,其核心结构非常简单,toJson与fromJson两个转换函数实现对象与JSON数据的转换,
  • 阿里巴巴的FastJson:Fastjson是阿里巴巴开源的JSON数据处理类库,其主要特点是序列化速度快。当并发数据量越大的时候,越能体现出fastjson的优势。但是笔者觉得选择JSON处理类库,快并不是唯一需要考虑的因素,与数据库或磁盘IO相比,JSON数据序列化与反序列化的这点时间还不足以对软件性能产生比较大的影响。

性能比较:笔者看多很多的关于这三个类库的性能测试,总结如下:

  • 序列化过程性能:fastjson >= jackson > Gson,Gson在数据并发量较大时会与其他二者有较明显差距。
  • 反序列化性能:三者几乎不相上下,Gson略好一点

fastjson为人诟病的问题:虽然fastjson速度上有一定的优势,但是其为了追求速度,很大程度放弃了JSON的规范性。因此还时不时的在有些版本中暴露安全问题。大家如果有机会去看一下fastjson的github代码,其代码质量不是很高。所以用不用fastjson在国内软件界还是有争议的,在国外基本没人用。

在Spring中注解方法使用Jackson

jackson主要的作用是:

什么叫序列化与反序列化?

  • 反序列化:在客户端将请求数据上传到服务端的时候,自动的处理JSON数据对象中的字符串、数字,将其转换为包含Date类型、Integer等类型的对象。
  • 序列化:按照指定的格式、顺序等将实体类对象转换为JSON字符串
  • 说白了就是把对象转成可传输、可存储的格式(json、xml、二进制、甚至自定义格式)叫做序列化。

所以我们下面就给大家介绍一下jackson的常用注解的使用方法,帮助我们进行序列化和反序列化工作。


常用注解 JsonFormat JsonInclude

这些注解通常用于标注java实体类或实体类的属性。

  • @JsonPropertyOrder(value={“pname1”,“pname2”}) 改变子属性在JSON序列化中的默认定义的顺序。如:param1在先,param2在后。
  • 改变属性的顺序
  • @JsonIgnore 加在属性上面,排除某个属性不做序列化与反序列化
  • 排除某个属性(加属性上)
  • @JsonIgnoreProperties(ignoreUnknown =true),将这个注解写在类上之后,就会忽略JSON字符串中存在,但实体类不存在的属性,不予赋值,也不会出现异常。
  • 忽略json中的 不对应的属性
  • @JsonIgnoreProperties({ “xxx”, “yyyy” }) 忽略某些属性不进行序列化
  • 排除某些属性(加类上)
  • @JsonProperty(anotherName) 为某个属性换一个名称,体现在JSON数据里面
  • 为属性换名称
  • @JsonInclude(JsonInclude.Include.NON_NULL) 排除为空的元素不做序列化反序列化
  • 校验 不为空
  • @JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”, timezone = “GMT+8”)指定日期类型的属性格式,返回给前端
  • 格式化

案例 ObjectMapper

@JsonPropertyOrder(value={"content","title"})  
public class Article {

    @JsonIgnore
    private Long id;

    @JsonProperty("auther")
    private String author;
    
    private String title;
    private String content;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;
    
    private List<Reader> reader;
}

        Article a = new Article();
        a.setId(1L);
        a.setAuthor("张三");
        a.setContent("内容");
        a.setTitle("title");
        a.setCreateTime(new Date());

        ObjectMapper mapper = new ObjectMapper();

        try {
            String s2 = "{\"content\":\"内容\",\"title\":\"title\",\"createTime\":\"2023-04-24 14:43:39\",\"auther\":\"张三\"}";
            Article article = mapper.readValue(s2, Article.class);
            //Article(id=null, author=张三, title=title, content=内容, createTime=Mon Apr 24 14:43:39 CST 2023)
            System.out.println(article);

            //{"content":"内容","title":"title","createTime":"2023-04-24 14:47:28","auther":"张三"}
            String s = mapper.writeValueAsString(a);
            System.out.println(s);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

上文代码中对应的JSON数据格式可以为:

{
    auther :"",
    content:"",
    title:"",
    createTime:"2019-10-20 12:12:12",
    reader:[{"name":"dhy","age":18},{"name":"xpy","age":18}]
}
  • 因为定义了JsonPropertyOrder,content在先,title在后
  • 因为定义了JsonIgnore,id属性被忽略
  • 因为定义了JsonProperty,author属性变为auther
  • 因为定义了JsonInclude和JsonFormat,createTime不要为空,并且格式为 “yyyy-MM-dd HH:mm:ss”

通常会对日期类型转换,进行全局配置,而不是在每一个java bean里面配置

spring: 
    jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: GMT+8

手动数据转换 readValue

除了在spring框架内实现自动的前后端JSON数据与java对象的转换,我们还可以使用jackson自己写代码进行转换。

  • ObjectMapper
    • writeValueAsString
    • readValue
//jackson的ObjectMapper 转换对象
ObjectMapper mapper = new ObjectMapper();

//将某个java对象转换为JSON字符串
String jsonStr = mapper.writeValueAsString(javaObj);

//将jsonStr转换为Ademo类的对象
Ademo ademo = mapper.readValue(jsonStr, Ademo.class);

当JSON字符串代表的对象的字段 多于类定义的字段时,使用readValue会抛出UnrecognizedPropertyException异常,在类的定义处加上**@JsonIgnoreProperties(ignoreUnknown = true)**可以解决这个问题。

Bug:需无参的构造函数

在有些版本JsonFormat注解(比如:Spring Boot 2.3.0.RELEASE),不能生效。我经过反复的实验,为实体类增加一个无参的构造函数和一个全参的构造函数,JsonFormat注解就生效了

Jackson全局配置

在Spring框架内使用Jackson的时候,通常需要一些特殊的全局配置,来应对我们JSON序列化与反序列化中出现的各种问题。
Spring Boot 提供了两种配置方式,一是配置文件的方式

配置文件

spring:
  jackson:
    #日期类型格式化
    date-format: yyyy-MM-dd HH:mm:ss
    
    serialization:
      #格式化输出,通常为了节省网络流量设置为false。因为格式化之后会带有缩进,方便阅读。
      indent_output: false
      
      #某些类对象无法序列化的时候,是否报错
      fail_on_empty_beans: false
      
    #设置空如何序列化,见下文代码方式详解
    defaultPropertyInclusion: NON_EMPTY
    deserialization:
      #对象json中有不存在的属性时候,是否报错
      fail_on_unknown_properties: false
      
    parser:
      #允许出现特殊字符和转义符
      allow_unquoted_control_chars: true
      
      #允许出现单引号
      allow_single_quotes: true

代码配置

二是通过代码的方式,方式一更容易,方式二更灵活。方式一无法解决的问题,尝试使用方式二。

@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder)
{
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();

        // 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
    
        // Include.Include.ALWAYS 默认
        // Include.NON_DEFAULT 属性为默认值不序列化
        // Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
        // Include.NON_NULL 属性为NULL 不序列化
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
    
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 允许出现特殊字符和转义符
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        // 允许出现单引号
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        // 字段保留,将null值转为""
        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>()
        {
            @Override
            public void serialize(Object o, JsonGenerator jsonGenerator,
                                  SerializerProvider serializerProvider)
                    throws IOException
            {
                jsonGenerator.writeString("");
            }
        });
        return objectMapper;
}

//bean放入配置类
@Configuration
public class JsonConfig {
}

@SpringBootTest
class Demo1ApplicationTests {

    @Test
    void contextLoads() {}
}

糊涂工具

        <!--工具类-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.3</version>
        </dependency>
            StationTheir stationTheir = JSONUtil.toBean(json, StationTheir.class);

			JSONUtil.toJsonStr(Object);
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 是一个基于 Spring 的轻量级框架,可以快速搭建基于 Spring 的应用程序。而 Fastjson 是一个高性能的 Java 序列化和反序列化库,可以处理复杂的 JSON 数据。 如果想要在 Spring Boot 中自定义 Fastjson 作为 JSON 消息转换器,可以按照以下步骤进行操作: 首先,在 pom.xml 文件中引入 Fastjson 的依赖,可以通过以下代码来添加依赖: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.78</version> </dependency> ``` 然后,在 Spring Boot配置类中配置 Fastjson 作为 JSON 消息转换器。可以通过以下代码来实现: ```java @Configuration public class FastjsonConfig { @Bean public HttpMessageConverters fastjsonHttpMessageConverter() { FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); converter.setDefaultCharset(Charset.forName("UTF-8")); List<MediaType> supportedMediaTypes = new ArrayList<>(); supportedMediaTypes.add(MediaType.APPLICATION_JSON); converter.setSupportedMediaTypes(supportedMediaTypes); FastJsonConfig config = new FastJsonConfig(); config.setSerializerFeatures(SerializerFeature.PrettyFormat); converter.setFastJsonConfig(config); return new HttpMessageConverters(converter); } } ``` 最后,在 Spring Boot 的主类中加上 @EnableWebMvc 注解,启用自定义的 JSON 消息转换器。 通过以上步骤,就成功地使用Spring Boot 自定义 Fastjson 作为 JSON 消息转换器。这样可以方便地处理 JSON 数据,提升了系统的性能和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值