[轉] SpringBoot返回json 數據以及數據封裝


作者:武哥     來源:武哥聊編程   https://mp.weixin.qq.com/s/QZk0sKxBX4QZiCTHQIA6pg

 

1. Spring Boot關於Json的知識點

  在項目開發中,接口與接口之間,前后端之間數據的傳輸都使用 Json 格式,在 Spring Boot 中,接口返回 Json 格式的數據很簡單,在 Controller 中使用@RestController注解即可返回 Json 格式的數據,@RestController也是 Spring Boot 新增的一個注解,我們點進去看一下該注解都包含了哪些東西。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
    String value() default "";
}

  可以看出, @RestController 注解包含了原來的 @Controller@ResponseBody 注解,使用過 Spring 的朋友對 @Controller 注解已經非常了解了,這里不再贅述, @ResponseBody注解是將返回的數據結構轉換為 Json 格式。所以在默認情況下,使用了 @RestController 注解即可將返回的數據結構轉換成 Json 格式,Spring Boot 中默認使用的 Json 解析技術框架是 jackson。我們點開 pom.xml 中的 spring-boot-starter-web 依賴,可以看到一個 spring-boot-starter-json 依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
    <version>2.0.3.RELEASE</version>
    <scope>compile</scope>
</dependency>

  Spring Boot 中對依賴都做了很好的封裝,可以看到很多 spring-boot-starter-xxx 系列的依賴,這是 Spring Boot 的特點之一,不需要人為去引入很多相關的依賴了,starter-xxx 系列直接都包含了所必要的依賴,所以我們再次點進去上面這個 spring-boot-starter-json 依賴,可以看到:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.6</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jdk8</artifactId>
    <version>2.9.6</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.9.6</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-parameter-names</artifactId>
    <version>2.9.6</version>
    <scope>compile</scope>
</dependency>

  到此為止,我們知道了 Spring Boot 中默認使用的 json 解析框架是 jackson。下面我們看一下默認的 jackson 框架對常用數據類型的轉 Json 處理。

 

2. Spring Boot默認對Json的處理

  在實際項目中,常用的數據結構無非有類對象、List對象、Map對象,我們看一下默認的 jackson 框架對這三個常用的數據結構轉成 json 后的格式如何。

 

1.1 創建 User 實體類

  為了測試,我們需要創建一個實體類,這里我們就用 User 來演示。

public class User {
    private Long id;
    private String username;
    private String password;
    /* 省略get、set和帶參構造方法 */
}

 

1.2 創建Controller類

  然后我們創建一個 Controller,分別返回 User對象、List<User> 和 Map<String, Object>。

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

    @RequestMapping("/user")
    public User getUser() {
        return new User(1, "倪升武", "123456");
    }

    @RequestMapping("/list")
    public List<User> getUserList() {
        List<User> userList = new ArrayList<>();
        User user1 = new User(1, "倪升武", "123456");
        User user2 = new User(2, "達人課", "123456");
        userList.add(user1);
        userList.add(user2);
        return userList;
    }

    @RequestMapping("/map")
    public Map<String, Object> getMap() {
        Map<String, Object> map = new HashMap<>(3);
        User user = new User(1, "倪升武", "123456");
        map.put("作者信息", user);
        map.put("博客地址", "http://blog.itcodai.com");
        map.put("CSDN地址", "http://blog.csdn.net/eson_15");
        map.put("粉絲數量", 4153);
        return map;
    }
}

 

1.3 測試不同數據類型返回的json

  OK,寫好了接口,分別返回了一個 User 對象、一個 List 集合和一個 Map 集合,其中 Map 集合中的 value 存的是不同的數據類型。接下來我們依次來測試一下效果。

  在瀏覽器中輸入:localhost:8080/json/user 返回 json 如下:

{"id":1,"username":"倪升武","password":"123456"}

  在瀏覽器中輸入:localhost:8080/json/list 返回 json 如下:

[{"id":1,"username":"倪升武","password":"123456"},
{"id":2,"username":"達人課","password":"123456"}]

  在瀏覽器中輸入:localhost:8080/json/map 返回 json 如下:

{"作者信息":{"id":1,"username":"倪升武","password":"123456"},"CSDN地址":"http://blog.csdn.net/eson_15","粉絲數量":4153,"博客地址":"http://blog.itcodai.com"}

  可以看出,map 中不管是什么數據類型,都可以轉成相應的 json 格式,這樣就非常方便。

 

1.4 jackson 中對null的處理

  在實際項目中,我們難免會遇到一些 null 值出現,我們轉 json 時,是不希望有這些 null 出現的,比如我們期望所有的 null 在轉 json 時都變成 "" 這種空字符串,那怎么做呢?在 Spring Boot 中,我們做一下配置即可,新建一個 jackson 的配置類:

@Configuration
public class JacksonConfig {
    @Bean
    @Primary
    @ConditionalOnMissingBean(ObjectMapper.class)
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                jsonGenerator.writeString("");
            }
        });
        return objectMapper;
    }
}

  然后我們修改一下上面返回 map 的接口,將幾個值改成 null 測試一下:

@RequestMapping("/map")
public Map<String, Object> getMap() {
    Map<String, Object> map = new HashMap<>(3);
    User user = new User(1, "倪升武", null);
    map.put("作者信息", user);
    map.put("博客地址", "http://blog.csdn.com/eson_15");
    map.put("CSDN地址", null);
    map.put("粉絲數量", 4153);
    return map;
}

  重啟項目,再次輸入:localhost:8080/json/map,可以看到 jackson 已經將所有 null 字段轉成了空字符串了。

{"作者信息":{"id":1,"username":"倪升武","password":""},"CSDN地址":"","粉絲數量":4153,"博客地址":"http://blog.csdn.com/eson_15"}

 

2. 使用阿里巴巴FastJson的設置

2.1 jackson 和 fastJson 的對比

  有很多朋友習慣於使用阿里巴巴的 fastJson 來做項目中 json 轉換的相關工作,目前我們項目中使用的就是阿里的 fastJson,那么 jackson 和 fastJson 有哪些區別呢?根據網上公開的資料比較得到下表。

選項 fastJson jackson
上手難易程度 容易 中等
高級特性支持 中等 豐富
官方文檔、Example支持 中文 英文
處理json速度 略快

  關於 fastJson 和 jackson 的對比,網上有很多資料可以查看,主要是根據自己實際項目情況來選擇合適的框架。從擴展上來看,fastJson 沒有 jackson 靈活,從速度或者上手難度來看,fastJson 可以考慮,我們項目中目前使用的是阿里的 fastJson,挺方便的。

 

2.2 fastJson依賴導入

  使用 fastJson 需要導入依賴,本課程使用 1.2.35 版本,依賴如下:

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.35</version>
</dependency>

  使用 fastJson 時,對 null 的處理和 jackson 有些不同,需要繼承  WebMvcConfigurationSupport 類,然后覆蓋 configureMessageConverters 方法,在方法中,我們可以選擇對要實現 null 轉換的場景,配置好即可。如下:

@Configuration
public class fastJsonConfig extends WebMvcConfigurationSupport {

    /**
     * 使用阿里 FastJson 作為JSON MessageConverter
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(
                // 保留map空的字段
                SerializerFeature.WriteMapNullValue,
                // 將String類型的null轉成""
                SerializerFeature.WriteNullStringAsEmpty,
                // 將Number類型的null轉成0
                SerializerFeature.WriteNullNumberAsZero,
                // 將List類型的null轉成[]
                SerializerFeature.WriteNullListAsEmpty,
                // 將Boolean類型的null轉成false
                SerializerFeature.WriteNullBooleanAsFalse,
                // 避免循環引用
                SerializerFeature.DisableCircularReferenceDetect);

        converter.setFastJsonConfig(config);
        converter.setDefaultCharset(Charset.forName("UTF-8"));
        List<MediaType> mediaTypeList = new ArrayList<>();
        // 解決中文亂碼問題,相當於在Controller上的@RequestMapping中加了個屬性produces = "application/json"
        mediaTypeList.add(MediaType.APPLICATION_JSON);
        converter.setSupportedMediaTypes(mediaTypeList);
        converters.add(converter);
    }
}

 

3. 封裝統一返回的數據結構

  以上是 Spring Boot 返回 json 的幾個代表的例子,但是在實際項目中,除了要封裝數據之外,我們往往需要在返回的 json 中添加一些其他信息,比如返回一些狀態碼 code ,返回一些 msg 給調用者,這樣調用者可以根據 code 或者 msg 做一些邏輯判斷。所以在實際項目中,我們需要封裝一個統一的 json 返回結構存儲返回信息。

 

3.1 定義統一的 json 結構

  由於封裝的 json 數據的類型不確定,所以在定義統一的 json 結構時,我們需要用到泛型。統一的 json 結構中屬性包括數據、狀態碼、提示信息即可,構造方法可以根據實際業務需求做相應的添加即可,一般來說,應該有默認的返回結構,也應該有用戶指定的返回結構。如下:

public class JsonResult<T> {

    private T data;
    private String code;
    private String msg;

    /**
     * 若沒有數據返回,默認狀態碼為0,提示信息為:操作成功!
     */
    public JsonResult() {
        this.code = "0";
        this.msg = "操作成功!";
    }

    /**
     * 若沒有數據返回,可以人為指定狀態碼和提示信息
     * @param code
     * @param msg
     */
    public JsonResult(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    /**
     * 有數據返回時,狀態碼為0,默認提示信息為:操作成功!
     * @param data
     */
    public JsonResult(T data) {
        this.data = data;
        this.code = "0";
        this.msg = "操作成功!";
    }

    /**
     * 有數據返回,狀態碼為0,人為指定提示信息
     * @param data
     * @param msg
     */
    public JsonResult(T data, String msg) {
        this.data = data;
        this.code = "0";
        this.msg = msg;
    }
    // 省略get和set方法
}

 

3.2 修改 Controller 中的返回值類型及測試

  由於 JsonResult 使用了泛型,所以所有的返回值類型都可以使用該統一結構,在具體的場景將泛型替換成具體的數據類型即可,非常方便,也便於維護。在實際項目中,還可以繼續封裝,比如狀態碼和提示信息可以定義一個枚舉類型,以后我們只需要維護這個枚舉類型中的數據即可(在本課程中就不展開了)。根據以上的 JsonResult,我們改寫一下 Controller,如下:

@RestController
@RequestMapping("/jsonresult")
public class JsonResultController {

    @RequestMapping("/user")
    public JsonResult<User> getUser() {
        User user = new User(1, "倪升武", "123456");
        return new JsonResult<>(user);
    }

    @RequestMapping("/list")
    public JsonResult<List> getUserList() {
        List<User> userList = new ArrayList<>();
        User user1 = new User(1, "倪升武", "123456");
        User user2 = new User(2, "達人課", "123456");
        userList.add(user1);
        userList.add(user2);
        return new JsonResult<>(userList, "獲取用戶列表成功");
    }

    @RequestMapping("/map")
    public JsonResult<Map> getMap() {
        Map<String, Object> map = new HashMap<>(3);
        User user = new User(1, "倪升武", null);
        map.put("作者信息", user);
        map.put("博客地址", "http://blog.csdn.com/eson_15");
        map.put("CSDN地址", null);
        map.put("粉絲數量", 4153);
        return new JsonResult<>(map);
    }
}

  我們重新在瀏覽器中輸入:localhost:8080/jsonresult/user 返回 json 如下:

{"code":"0","data":{"id":1,"password":"123456","username":"倪升武"},"msg":"操作成功!"}

  輸入:localhost:8080/jsonresult/list,返回 json 如下:

{"code":"0","data":[{"id":1,"password":"123456","username":"倪升武"},{"id":2,"password":"123456","username":"達人課"}],"msg":"獲取用戶列表成功"}

  輸入:localhost:8080/jsonresult/map,返回 json 如下:

{"code":"0","data":{"作者信息":{"id":1,"password":"","username":"倪升武"},"CSDN地址":null,"粉絲數量":4153,"博客地址":"http://blog.csdn.com/eson_15"},"msg":"操作成功!"}

  通過封裝,我們不但將數據通過 json 傳給前端或者其他接口,還帶上了狀態碼和提示信息,這在實際項目場景中應用非常廣泛。

 

4. 總結

  本節主要對 Spring Boot 中 json 數據的返回做了詳細的分析,從 Spring Boot 默認的 jackson 框架到阿里巴巴的 fastJson 框架,分別對它們的配置做了相應的講解。另外,結合實際項目情況,總結了實際項目中使用的 json 封裝結構體,加入了狀態碼和提示信息,使得返回的 json 數據信息更加完整。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM