【熵增教育】詳解SpringBoot中的JSON——熵增學院

對於每個開發web的人來說,JSON肯定都不陌生.它的輕量級與簡潔性,使得它備受青睞.同時,隨着前後臺技術的不斷成熟,Json解析技術也發展地越來越完善.在這衆多的Json解析技術中,備受歡迎的則是我們今天要講的以下三種:

  1. Jackson

  2. Gson

  3. json-b

 

1.jackson

Jackson是一個簡單基於Java應用庫,Jackson可以輕鬆的將Java對象轉換成json對象和xml文檔,同樣也可以將json、xml轉換成Java對象。Jackson所依賴的jar包較少,簡單易用並且性能也要相對高些,並且Jackson社區相對比較活躍,更新速度也比較快。從SpringMVC到SpringBoot,官方推薦的都是jackson.,它主要具備以下幾個優點:容易使用。

 

  • 容易使用 - jackson API提供了一個高層次外觀,以簡化常用的用例。

  • 無需創建映射 - API提供了默認的映射大部分對象序列化。

  • 性能高 - 快速,低內存佔用,適合大型對象圖表或系統。

  • 乾淨的JSON - jackson創建一個乾淨和緊湊的JSON結果,這是讓人很容易閱讀。

  • 不依賴 - 庫不需要任何其他的庫,除了JDK。

  • 開源代碼 - jackson是開源的,可以免費使用。

 

1.1 jackson的常規使用

對於我們而言,我們比較關心的是他的序列化操作,這裏我們先引入jackson的依賴包

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

構建成功後,我們看到依賴裏出現了:

jackson-annotations-2.9.0.jar
jackson-core-2.9.7.jar
jackson-databind-2.9.7.jar

這是jackson的依賴庫,接下來我們創建一個基本的實體類:

package top.lianmengtu.testjson.domain;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class UserInfo {

    private Long id;

    private String nickName;

    private Boolean gender;

}

我們來一個測試類:

package top.lianmengtu.testjson;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import top.lianmengtu.testjson.domain.UserInfo;

public class MyJsonTest  {

    public static void main(String[] args) {
        ObjectMapper objectMapper=new ObjectMapper();
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1l);
        userInfo.setNickName("Nick");
        userInfo.setGender(false);

        String userInfoString= null;
        try {
            userInfoString = objectMapper.writeValueAsString(userInfo);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        System.out.println(userInfoString);
    }
}

運行結果如下:

{"id":1,"nickName":"Nick","gender":false}

 

這是一個基本類型,我們這裏添加兩個屬性,一個基本類型的List,另一個是日期類型:

package top.lianmengtu.testjson.domain;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;

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

@Getter
@Setter
public class UserInfo {

    private Long id;

    private String nickName;

    private Boolean gender;

    private List<String> roleList;

    private Date createTime;

}

測試類如下:

package top.lianmengtu.testjson;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import top.lianmengtu.testjson.domain.UserInfo;

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

public class MyJsonTest  {

    public static void main(String[] args) {
        ObjectMapper objectMapper =new ObjectMapper();
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1l);
        userInfo.setNickName("Nick");
        userInfo.setGender(false);
        List<String> roleList=new ArrayList<>();
        roleList.add("admin");
        roleList.add("manager");
        userInfo.setRoleList(roleList);
        userInfo.setCreateTime(new Date());
        String userInfoString= null;
        try {
            userInfoString = objectMapper.writeValueAsString(userInfo);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        System.out.println(userInfoString);
    }
}

運行結果如下:

{"id":1,"nickName":"Nick","gender":false,"roleList":["admin","manager"],"createTime":1540451548817}

這裏我們看到基本類型的List按着我們的期望解析了,但日期明顯不是我們想要的,這裏我們可以使用@JsonFormat來傳入我們想要的格式,如下所示:

package top.lianmengtu.testjson.domain;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;

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

@Getter
@Setter
public class UserInfo {

    private Long id;

    private String nickName;

    private Boolean gender;

    private List<String> roleList;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;

}

這裏我們的測試類不變,運行結果如下所示:

{"id":1,"nickName":"Nick","gender":false,"roleList":["admin","manager"],"createTime":"2018-10-25 07:16:12"}

此時,我們看到日期類型已經按着我們期望的格式進行展示了.我們在使用的時候,常會使用內嵌類型,這裏我們給用戶定義一個公司:

package top.lianmengtu.testjson.domain;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Company {

    private Long id;

    private String name;

    private String address;
}

我們再給用戶定義一個公司列表,表明用戶工作過的公司:

package top.lianmengtu.testjson.domain;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;

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

@Getter
@Setter
public class UserInfo {

    private Long id;

    private String nickName;

    private Boolean gender;

    private List<String> roleList;

    private List<Company> companies;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
}

我們也修改一下測試類:

package top.lianmengtu.testjson;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import top.lianmengtu.testjson.domain.Company;
import top.lianmengtu.testjson.domain.UserInfo;

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

public class MyJsonTest  {

    public static void main(String[] args) {
        ObjectMapper objectMapper =new ObjectMapper();
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1l);
        userInfo.setNickName("Nick");
        userInfo.setGender(false);
        List<String> roleList=new ArrayList<>();
        roleList.add("admin");
        roleList.add("manager");
        userInfo.setRoleList(roleList);
        Company baidu=new Company();
        baidu.setId(1l);
        baidu.setName("百度");
        baidu.setAddress("西二旗");
        List<Company> companies = new ArrayList<>();
        companies.add(baidu);
        userInfo.setCompanies(companies);
        userInfo.setCreateTime(new Date());
        String userInfoString= null;
        try {
            userInfoString = objectMapper.writeValueAsString(userInfo);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        System.out.println(userInfoString);
    }
}

運行結果如下:

{"id":1,"nickName":"Nick","gender":false,"roleList":["admin","manager"],"companies":[{"id":1,"name":"百度","address":"西二旗"}],"createTime":"2018-10-25 07:19:42"}

1.2 SpringBoot中的jackson

展示了基本使用之後,我們現在來看一下SpringBoot對Jackson的支持,當我們在pom中添加了spring-boot-starter-web 之後,我們發現已經自動加入了jackson的三個包.啓動類如下:

package top.lianmengtu.testjson;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

JsonController類代碼如下所示:

package top.lianmengtu.testjson.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.lianmengtu.testjson.domain.Company;
import top.lianmengtu.testjson.domain.UserInfo;

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

@RestController
@RequestMapping("json/")
public class JsonController {

    @RequestMapping("basic_json")
    public UserInfo basicJson(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1l);
        userInfo.setNickName("Nick");
        userInfo.setGender(false);
        List<String> roleList=new ArrayList<>();
        roleList.add("admin");
        roleList.add("manager");
        userInfo.setRoleList(roleList);
        Company baidu=new Company();
        baidu.setId(1l);
        baidu.setName("百度");
        baidu.setAddress("西二旗");
        List<Company> companies = new ArrayList<>();
        companies.add(baidu);
        userInfo.setCompanies(companies);
        userInfo.setCreateTime(new Date());
        return userInfo;
    }
}

我們啓動項目,然後打開瀏覽器,結果如下所示:

 
{"id":1,"nickName":"Nick","gender":false,"roleList":["admin","manager"],"companies":[{"id":1,"name":"百度","address":"西二旗"}],"createTime":"2018-10-25 07:44:13"}

 

和我們剛剛演示的一樣,但現在有兩個問題,首先,包含日期類型的model可能不只一個,如果我們在model裏添加@JsonFormat可能每一個都需要加,比較地繁瑣.其次,有些時候我們可能沒有辦法改變model的源碼,因此不能給諸如日期這樣的字段添加@JsonFormat註解,那怎麼辦呢?此時我們就可以將我們的配置外移,移到application.yml裏,如下所示:

spring:
  jackson:
    date-format: 'yyyy-MM-dd'

然後我們將實體類裏的@JsonFormat去掉,如下所示:

package top.lianmengtu.testjson.domain;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;

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

@Getter
@Setter
public class UserInfo {

    private Long id;

    private String nickName;

    private Boolean gender;

    private List<String> roleList;

    private List<Company> companies;

    private Date createTime;
}

我們運行我們的代碼,發現日期現在變成了我們在配置文件裏配置的yyyy-MM-dd的格式:

{"id":1,"nickName":"Nick","gender":false,"roleList":["admin","manager"],"companies":[{"id":1,"name":"百度","address":"西二旗"}],"createTime":"2018-10-25"}

不過這裏有一點需要說明一下,如果我們即在yml裏進行了配置,同時也使用了@JsonFormat註解,那麼@JsonFormat會覆蓋yml裏的。除此之外,springBoot還支持jackson以下一些屬性的使用:

spring.jackson.default-property-inclusion=
spring.jackson.deserialization.*=
spring.jackson.generator.*=
spring.jackson.joda-date-time-format= 
spring.jackson.locale=
spring.jackson.mapper.*=
spring.jackson.parser.*=
spring.jackson.property-naming-strategy=
spring.jackson.serialization.*=
spring.jackson.time-zone=

它使用的方式和objectMapper使用的方式幾乎一模一樣,比如,我們剛剛嘗試過關於日期格式的問題,在我們沒有寫JsonFormat的時候,jackson會自動將我們的日期格式轉換爲時間戳,現在我們來禁用這個屬性

public static void main(String[] args) {
    ObjectMapper objectMapper=new ObjectMapper();
    UserInfo userInfo = new UserInfo();
    userInfo.setId(1l);
    userInfo.setNickName("Nick");
    userInfo.setGender(false);
    userInfo.setCreateTime(new Date());
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    String userInfoString= null;
    try {
        userInfoString = objectMapper.writeValueAsString(userInfo);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
    System.out.println(userInfoString);
}

因爲serialization是一個map,所以在yml裏這麼寫

spring:
  jackson:
    serialization:
      /write_dates_as_timestamps: false

當我們禁用之後,打印出來的字符串如下所示:

{"id":1,"nickName":"Nick","gender":false,"roleList":null,"companies":null,"createTime":"2018-10-25T08:46:32.192+0000"}

我們發現,已經不在是時間戳了,說明我們的配置已經生效了,其他的,大家可以進到相應的實現裏去一一查看.

 

2. gson的使用

gson是google出的一個json解析工具.使用它的時候,我們只需要在pom中添加gson一個包就可以了,如下所示:

 

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.5</version>
</dependency>

 

2.1 gson的基本使用

我們還是先來看一下gson的基本使用.我們仍然使用剛剛那個實體類:

 

package top.lianmengtu.testjson.domain;

import lombok.Getter;
import lombok.Setter;

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

@Getter
@Setter
public class UserInfo {

    private Long id;

    private String nickName;

    private Boolean gender;

    private List<String> roleList;

    private List<Company> companies;

    private Date createTime;

}

然後是我們的測試類:

 

package top.lianmengtu.testjson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import top.lianmengtu.testjson.domain.Company;
import top.lianmengtu.testjson.domain.UserInfo;

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

public class GsonTest {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1l);
        userInfo.setNickName("Nick");
        userInfo.setGender(false);
        List<String> roleList=new ArrayList<>();
        roleList.add("admin");
        roleList.add("manager");
        userInfo.setRoleList(roleList);
        Company baidu=new Company();
        baidu.setId(1l);
        baidu.setName("百度");
        baidu.setAddress("西二旗");
        List<Company> companies = new ArrayList<>();
        companies.add(baidu);
        userInfo.setCompanies(companies);
        userInfo.setCreateTime(new Date());
        Gson gson=new Gson();
        String userInfoString=gson.toJson(userInfo);
        System.out.println(userInfoString);

    }
}

然後運行結果如下所示:

{"id":1,"nickName":"Nick","gender":false,"roleList":["admin","manager"],"companies":[{"id":1,"name":"百度","address":"西二旗"}],"createTime":"Oct 25, 2018, 5:12:44 PM"}

現在我們來展示他的日期轉換,在gson中我們處理日期轉換可以使用gsonbuilder去處理,如下所示(因爲重點是日期,所以略過其他字段):

package top.lianmengtu.testjson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import top.lianmengtu.testjson.domain.UserInfo;

import java.util.Date;

public class GsonTest {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        userInfo.setCreateTime(new Date());
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setDateFormat("yyyy-MM-dd");
        Gson gson=gsonBuilder.create();
        String userInfoString=gson.toJson(userInfo);
        System.out.println(userInfoString);
    }
}

測試結果如下所示:

{"createTime":"2018-10-25"}

gsonbuilder的這種處理方式,除了能處理date類型外,還能處理long類型,可以將long轉換爲字符串或者轉換爲數字類型.默認是將long轉換爲數字,這裏我們處理成字符串,測試類如下所示:

package top.lianmengtu.testjson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.LongSerializationPolicy;
import top.lianmengtu.testjson.domain.UserInfo;

import java.util.Date;

public class GsonTest {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1l);
        userInfo.setCreateTime(new Date());
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setDateFormat("yyyy-MM-dd");
        gsonBuilder.setLongSerializationPolicy(LongSerializationPolicy.STRING);
        Gson gson=gsonBuilder.create();
        String userInfoString=gson.toJson(userInfo);
        System.out.println(userInfoString);
    }
}

運行結果如下:

{"id":"1","createTime":"2018-10-25"}

之前在json的時候出現過一種情況,就是循環解析導致報錯的,最典型的情況是對tree的解析,之前我們曾在tree裏設置children來存放子節點,同時又設置了parent來存放父節點,後來就直接報錯了.除了這些之外,還有一些純粹是爲了我們的業務邏輯而設置的屬性,這些我們也需要忽略,那gson如何實現這個功能呢:

1.字段上標註transient或@Expose


實體類代碼如下所示:

package top.lianmengtu.testjson.domain;

import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;

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

@Getter
@Setter
public class UserInfo {

    private transient Long id;

    private String nickName;

    private Boolean gender;

    private List<String> roleList;

    private List<Company> companies;

    private Date createTime;

}

然後我們仍然運行上面的測試代碼,運行結果如下所示:

{"createTime":"2018-10-25"}

使用transient是標記需要排除的,而@Expose則標記的是需要序列化的字段.實體類修改如下:

package top.lianmengtu.testjson.domain;

import com.google.gson.annotations.Expose;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;

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

@Getter
@Setter
public class UserInfo {

    @Expose
    private  Long id;

    @Expose
    private String nickName;

    @Expose
    private Boolean gender;

    private List<String> roleList;

    private List<Company> companies;

    @Expose
    private Date createTime;

}

測試代碼修改如下:

package top.lianmengtu.testjson;

import com.google.gson.*;
import top.lianmengtu.testjson.domain.Company;
import top.lianmengtu.testjson.domain.UserInfo;

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

public class GsonTest {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1l);
        userInfo.setCreateTime(new Date());
        userInfo.setNickName("Nick");
        userInfo.setGender(false);
        List<String> roleList=new ArrayList<>();
        roleList.add("admin");
        roleList.add("manager");
        userInfo.setRoleList(roleList);
        Company baidu=new Company();
        baidu.setId(1l);
        baidu.setName("百度");
        baidu.setAddress("西二旗");
        List<Company> companies = new ArrayList<>();
        companies.add(baidu);
        userInfo.setCompanies(companies);
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setDateFormat("yyyy-MM-dd");
        gsonBuilder.excludeFieldsWithoutExposeAnnotation();
        Gson gson=gsonBuilder.create();
        String userInfoString=gson.toJson(userInfo);
        System.out.println(userInfoString);
    }
}

運行結果如下:

{"id":1,"nickName":"Nick","gender":false,"createTime":"2018-10-25"}

 

2.使用排除策略 exclusionStrategy


排除策略有很多種,另一種是傳字符串去匹配,測試代碼修改如下:

package top.lianmengtu.testjson;

import com.google.gson.*;
import top.lianmengtu.testjson.domain.Company;
import top.lianmengtu.testjson.domain.UserInfo;

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

public class GsonTest {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1l);
        userInfo.setCreateTime(new Date());
        userInfo.setNickName("Nick");
        userInfo.setGender(false);
        List<String> roleList=new ArrayList<>();
        roleList.add("admin");
        roleList.add("manager");
        userInfo.setRoleList(roleList);
        Company baidu=new Company();
        baidu.setId(1l);
        baidu.setName("百度");
        baidu.setAddress("西二旗");
        List<Company> companies = new ArrayList<>();
        companies.add(baidu);
        userInfo.setCompanies(companies);
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setDateFormat("yyyy-MM-dd");
        final List<String> filedList= new ArrayList<>();
        filedList.add("companies");
        filedList.add("nickName");
        gsonBuilder.addSerializationExclusionStrategy(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes fieldAttributes) {
                String name=fieldAttributes.getName();
                for(String filed: filedList){
                    if(filed.equals(name)){
                        return true;
                    }
                }

                return false;
            }

            @Override
            public boolean shouldSkipClass(Class<?> clazz) {
                return false;
            }
        });
        Gson gson=gsonBuilder.create();
        String userInfoString=gson.toJson(userInfo);
        System.out.println(userInfoString);
    }
}

然後我們再運行,得到結果如下:

{"id":1,"gender":false,"roleList":["admin","manager"],"createTime":"2018-10-25"}

 

2.2 SpringBoot中的GSON

因爲SpringBoot是支持SPI的,簡單理解就是能抓到哪個,就用哪個實現,因爲spring-boot-starter-web默認是用jackson,所以此時爲了能夠讓springboot抓到gson,我們一方面要在pom里加上gson的配置,另一方面還需要將jackson排除掉,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>top.lianmengtu</groupId>
    <artifactId>test-json</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
    </parent>
    <name>test-json</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <lombok.version>1.18.2</lombok.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-databind</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-annotations</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.5</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

這樣就可以在SpringBoot中啓用Gson了.我們可以打開日誌查看一下:

 
GsonAutoConfiguration matched:
      - @ConditionalOnClass found required class 'com.google.gson.Gson'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)

   GsonAutoConfiguration#gson matched:
      - @ConditionalOnMissingBean (types: com.google.gson.Gson; SearchStrategy: all) did not find any beans (OnBeanCondition)

   GsonAutoConfiguration#gsonBuilder matched:
      - @ConditionalOnMissingBean (types: com.google.gson.GsonBuilder; SearchStrategy: all) did not find any beans (OnBeanCondition)

   GsonHttpMessageConvertersConfiguration matched:
      - @ConditionalOnClass found required class 'com.google.gson.Gson'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)

   GsonHttpMessageConvertersConfiguration.GsonHttpMessageConverterConfiguration matched:
      - AnyNestedCondition 1 matched 1 did not; NestedCondition on GsonHttpMessageConvertersConfiguration.PreferGsonOrJacksonAndJsonbUnavailableCondition.JacksonJsonbUnavailable NoneNestedConditions 0 matched 2 did not; NestedCondition on GsonHttpMessageConvertersConfiguration.JacksonAndJsonbUnavailableCondition.JsonbPreferred @ConditionalOnProperty (spring.http.converters.preferred-json-mapper=jsonb) did not find property 'spring.http.converters.preferred-json-mapper'; NestedCondition on GsonHttpMessageConvertersConfiguration.JacksonAndJsonbUnavailableCondition.JacksonAvailable @ConditionalOnBean (types: org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; SearchStrategy: all) did not find any beans of type org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; NestedCondition on GsonHttpMessageConvertersConfiguration.PreferGsonOrJacksonAndJsonbUnavailableCondition.GsonPreferred @ConditionalOnProperty (spring.http.converters.preferred-json-mapper=gson) did not find property 'spring.http.converters.preferred-json-mapper' (GsonHttpMessageConvertersConfiguration.PreferGsonOrJacksonAndJsonbUnavailableCondition)
      - @ConditionalOnBean (types: com.google.gson.Gson; SearchStrategy: all) found bean 'gson' (OnBeanCondition)

現在我們來演示一下日期排除,Controller代碼如下:

package top.lianmengtu.testjson.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.lianmengtu.testjson.domain.Company;
import top.lianmengtu.testjson.domain.UserInfo;

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

@RestController
@RequestMapping("gson/")
public class GsonController {

    @RequestMapping("basic")
    public UserInfo basic(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1l);
        userInfo.setCreateTime(new Date());
        userInfo.setNickName("Nick");
        userInfo.setGender(false);
        List<String> roleList=new ArrayList<>();
        roleList.add("admin");
        roleList.add("manager");
        userInfo.setRoleList(roleList);
        Company baidu=new Company();
        baidu.setId(1l);
        baidu.setName("百度");
        baidu.setAddress("西二旗");
        List<Company> companies = new ArrayList<>();
        companies.add(baidu);
        userInfo.setCompanies(companies);
        return userInfo;
    }
}

與jackson配置類似,springboot支持gson,其相關配置在spring.gson下,yml配置修改如下:

spring:
  gson:
    date-format: 'yyyy-MM-dd HH:mm:ss'

運行後,結果如下:

{"id":1,"nickName":"Nick","gender":false,"roleList":["admin","manager"],"companies":[{"id":1,"name":"百度","address":"西二旗"}],"createTime":"2018-10-25 18:38:38"}

現在我們來演示字段排除,因爲transient是自動支持的,所以我們不再演示,我們來演示一下@Expose的使用,配置文件修改如下:

spring:
  gson:
    date-format: 'yyyy-MM-dd HH:mm:ss'
    exclude-fields-without-expose-annotation: true

然後實體類修改如下:

package top.lianmengtu.testjson.domain;

import com.google.gson.annotations.Expose;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;

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

@Getter
@Setter
public class UserInfo {

    @Expose
    private  Long id;

    @Expose
    private String nickName;

    private Boolean gender;

    private List<String> roleList;

    private List<Company> companies;

    private Date createTime;

}

我們在id和nickName字段上加上@Expose,,然後運行代碼,效果如下所示:

{"id":1,"nickName":"Nick"}

除了這些之外,它支持的配置如下所示:

spring.gson.date-format=
spring.gson.disable-html-escaping=
spring.gson.disable-inner-class-serialization=
spring.gson.enable-complex-map-key-serialization=
spring.gson.exclude-fields-without-expose-annotation=
spring.gson.field-naming-policy=
spring.gson.generate-non-executable-json=
spring.gson.lenient=
spring.gson.long-serialization-policy=
spring.gson.pretty-printing=
spring.gson.serialize-nulls=

這裏有個屬性是disable-html-escaping,可以幫助我們過濾html標籤,這個在某些場景下還是很有用的

3. JSON-B

json-b是Java EE8中提供的一種json標準.該 API提供了適配器及一些自定義序列化器和反序列化器。對於較高級的場景,可以使用類中的註解或運行時配置構建器來覆蓋 JSON-B 的默認設置。

 

總而言之,JSON-B整理了已在企業開發人員中廣泛應用的行業實踐和方法。它使用註解通過映射語義來標記類和字段,提供了處理複雜數據結構時常常需要的可擴展性。

 

最重要的是,這個 API 支持以一種直觀且容易的方式在 Java 類與 JSON 文檔之間進行綁定。甚至沒有 JSON經驗的開發人員,應該也能夠輕鬆上手使用 Java API for JSON Binding。對 JSON 反/序列化庫(比如 GSONBoon 和 Jackson)經驗豐富的開發人員將發現 JSON-B 很熟悉且用起來很舒適。

 

我們仍然從兩方面來闡述JSON-B的使用,首先是非SpringBoot項目中的使用,其次是SpringBoot項目中的使用

3.1 常規使用

json-b是一種規範,其中Yasson是eclipse實現的,而johnzon-jsonb則是apache實現的.因爲json-b是一種規範,所以我們只要加入實現即可,無論哪種實現,使用起來幾乎是一樣的,我們添加了Yasson,GAV座標如下:

 

<dependency>
    <groupId>org.eclipse</groupId>
    <artifactId>yasson</artifactId>
    <version>1.0.2</version>
</dependency>
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.json</artifactId>
    <version>1.1.2</version>
</dependency>

測試代碼如下:

package top.lianmengtu.testjson;

import top.lianmengtu.testjson.domain.Company;
import top.lianmengtu.testjson.domain.UserInfo;

import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class JSONBTest {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1l);
        userInfo.setCreateTime(new Date());
        userInfo.setNickName("Nick");
        userInfo.setGender(false);
        List<String> roleList=new ArrayList<>();
        roleList.add("admin");
        roleList.add("manager");
        userInfo.setRoleList(roleList);
        Company baidu=new Company();
        baidu.setId(1l);
        baidu.setName("百度");
        baidu.setAddress("西二旗");
        List<Company> companies = new ArrayList<>();
        companies.add(baidu);
        userInfo.setCompanies(companies);
        Jsonb userJson=JsonbBuilder.create();
        String userInfoString=userJson.toJson(userInfo);
        System.out.println(userInfoString);
    }
}

運行代碼後的結果如下:

 

{"companies":[{"address":"西二旗","id":1,"name":"百度"}],"createTime":"2018-10-25T11:32:17.337Z[UTC]","gender":false,"id":1,"nickName":"Nick","roleList":["admin","manager"]}

首先,我們還是來看日期格式化的問題,測試代碼如下:

package top.lianmengtu.testjson;

import top.lianmengtu.testjson.domain.Company;
import top.lianmengtu.testjson.domain.UserInfo;

import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class JSONBTest {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1l);
        userInfo.setCreateTime(new Date());
        userInfo.setNickName("Nick");
        userInfo.setGender(false);
        List<String> roleList=new ArrayList<>();
        roleList.add("admin");
        roleList.add("manager");
        userInfo.setRoleList(roleList);
        Company baidu=new Company();
        baidu.setId(1l);
        baidu.setName("百度");
        baidu.setAddress("西二旗");
        List<Company> companies = new ArrayList<>();
        companies.add(baidu);
        userInfo.setCompanies(companies);
        JsonbConfig config=new JsonbConfig();
        config.withDateFormat("yyyy-MM-dd",Locale.CHINESE);
        Jsonb userJson=JsonbBuilder.create(config);
        String userInfoString=userJson.toJson(userInfo);
        System.out.println(userInfoString);
    }
}

運行就結果如下:

 

{"companies":[{"address":"西二旗","id":1,"name":"百度"}],"createTime":"2018-10-25","gender":false,"id":1,"nickName":"Nick","roleList":["admin","manager"]}

3.2 SpringBoot中的JSON-B

在springBoot中使用JSON-B的方式和GSON相似,我們只需要排除掉jackson然後添加上apache-johnzon的jackson就可以了.這裏我們添加的是Apache Johnzon. GAV座標如下:

 

       
 <dependency>
            <groupId>org.apache.johnzon</groupId>
            <artifactId>johnzon-jsonb</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>org.apache.johnzon</groupId>
            <artifactId>jsonb-api</artifactId>
            <version>1.0.0</version>
        </dependency>

配置文件如下所示:

 

JsonbHttpMessageConvertersConfiguration matched:
      - @ConditionalOnClass found required class 'javax.json.bind.Jsonb'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)

我們看懂這裏匹配到的是jsonb,這說明我們的配置已經成功了.controller不變,我們打開瀏覽器,然後訪問localhost:8080/jsonb/basic,結果如下所示:

 

{"companies":[{"address":"西二旗","id":1,"name":"百度"}],"createTime":"2018-10-25","gender":false,"id":1,"nickName":"Nick","roleList":["admin","manager"]}

本文視頻請點擊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章