avatar

SpringBoot的JSON解析方案

摘要:本文介绍了Springboot的JSON解析方案,包括自动化配置的Jackson和Gson,以及阿里的fastjson

SpringBoot的默认JSON解析方案


SpringBoot默认使用的是Jackson,在项目的maven依赖里面可以看到。同时SpringBoot也为我们自动配置好了Jackson和Gson的HttpMessageConverter。因此,如果用户使用Jackson和Gson时没有额外的自定义配置,则只需要引入依赖即可。

HttpMessageConverter是一个消息转换工具,其主要功能有:

  • 将服务端返回的对象序列化成JSON字符串
  • 将前端传来的JSON字符串反序列化为Java对象
1
2
3
4
5
<!--Jackson依赖已经内嵌到starter里面了-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

那么我们使用一个简单的User类和UserController来测试一下SpringBoot的默认JSON解析方案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.example.json.bean;

import com.fasterxml.jackson.annotation.JsonFormat;

import java.util.Date;

/**
* @author: WJZheng
* @date: 2020/3/15 16:18
* @description:
*/
public class User {
private Integer id;
private String username;
private String address;
@JsonFormat(pattern = "yyyy-MM-dd:")
private Date birthday;

public Date getBirthday() {
return birthday;
}

public void setBirthday(Date birthday) {
this.birthday = birthday;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.example.json.controller;

import com.example.json.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
* @author: WJZheng
* @date: 2020/3/15 16:19
* @description:
*/
@RestController
public class UserController {
@GetMapping("/user")
public List<User> getUsers() {
List<User> userList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
User user = new User();
user.setId(i);
user.setUsername("user:" + i);
user.setAddress("home:" + i);
user.setBirthday(new Date());
userList.add(user);
}
return userList;
}
}

运行后我们可以看到,使用默认的解析方案已经可以自动序列化JSON了

那么这些自动化配置是在哪里实现的呢?我们可以找到一个JacksonHttpMessageConvertersConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Configuration(proxyBeanMethods = false)
class JacksonHttpMessageConvertersConfiguration {

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ObjectMapper.class)
@ConditionalOnBean(ObjectMapper.class)
@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY,
havingValue = "jackson", matchIfMissing = true)
static class MappingJackson2HttpMessageConverterConfiguration {

@Bean
@ConditionalOnMissingBean(value = MappingJackson2HttpMessageConverter.class,
ignoredType = {
"org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter",
"org.springframework.data.rest.webmvc.alps.AlpsJsonHttpMessageConverter" })
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
return new MappingJackson2HttpMessageConverter(objectMapper);
}
}
······
}

这里我们看到,该配置首先需要一个ObjectMapper,这是一个JSON序列化工具。然后再为其自动配置一个MappingJackson2HttpMessageConverter转换工具类。

那么如果我们想自己配置JSON的格式呢?比如说日期的格式,我们可以通过在User类中的birthday属性上添加@JsonFormat注解来局部格式化JSON,又或者我们可以通过创建一个配置类来自定义一个全局的JSON解析方案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.example.json.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import java.text.SimpleDateFormat;

/**
* @author: WJZheng
* @date: 2020/3/15 16:34
* @description:
*/
@Configuration
public class WebMVCConfig {

//进行全局配置,如编码方式
@Bean
MappingJackson2HttpMessageConverter messageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("yyy-MM-dd"));
converter.setObjectMapper(objectMapper);
return converter;
}

//进行全局配置,如日期
@Bean
ObjectMapper objectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("yyy-MM-dd"));
return objectMapper;
}
}

再次运行我们可以发现日期的格式改变了

SpringBoot整合Gson


现在我们来使用Gson的解析方案,我们已经说过SpringBoot已经为我们自动配置好了Gson,因此我们只需要引入依赖即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--在引入Gson的依赖之前,我们首先需要将jackson的依赖排除掉-->
<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>

<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>

添加完了依赖即可像上面使用Jackson那样使用Gson了。那么Gson的自动化配置又在哪里呢?我们找到一个GsonHttpMessageConvertersConfiguration类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Gson.class)
class GsonHttpMessageConvertersConfiguration {

@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(Gson.class)
@Conditional(PreferGsonOrJacksonAndJsonbUnavailableCondition.class)
static class GsonHttpMessageConverterConfiguration {

@Bean
@ConditionalOnMissingBean
GsonHttpMessageConverter gsonHttpMessageConverter(Gson gson) {
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
converter.setGson(gson);
return converter;
}
}
}

在这里我们可以看到若用户没有自定义一个GsonHttpMessageConverter的话,SpringBoot会自动为我们提供一个转换器。那么我们同样可以创建一个配置类来自定义Gson配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.example.gson.config;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.GsonHttpMessageConverter;

/**
* @author: WJZheng
* @date: 2020/3/15 17:04
* @description:
*/
@Configuration
public class WebMvcConfig {

@Bean
GsonHttpMessageConverter httpMessageConverter(){
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
converter.setGson(new GsonBuilder().setDateFormat("yyyy-MM-dd").create());
return converter;
}

@Bean
Gson gson(){
return new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
}
}

SpringBoot整合fastjson


SpringBoot没有自动配置fastjson的HttpMessageConverter,因此需要用户自己额外配置。

1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.49</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.example.gson.config;

import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.GsonHttpMessageConverter;

/**
* @author: WJZheng
* @date: 2020/3/15 17:04
* @description:
*/
@Configuration
public class WebMvcConfig {
FastJsonHttpMessageConverter httpMessageConverter(){
FastJsonHttpMessageConverter converter=new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setDateFormat("yyyy-MM-dd");
converter.setFastJsonConfig(config);
return converter;
}
}
Author: WJZheng
Link: https://wellenzheng.github.io/2020/03/15/SpringBoot%E7%9A%84JSON%E8%A7%A3%E6%9E%90%E6%96%B9%E6%A1%88/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.

Comment