Spring Boot返回Json数据及数据封装

Posted 明天的明天 永远的永远 未知的一切 我与你一起承担 ??

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot返回Json数据及数据封装相关的知识,希望对你有一定的参考价值。

1.1 简介

在项目开发中,接口与接口之间,前后端之间数据的传输都使用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处理。
1.2 Spring Boot 默认对Json的处理

在实际项目中,常用的数据结构无非有类对象、List对象、Map对象,我们看一下默认的jackson 框架对这三个常用的数据结构转成 json后的格式如何。
1.2.1 创建 User实体类

为了测试,我们需要创建一个实体类,这里我们就用 User 来演示。

public class User 
    private Long id;
    private String username;
    private String password;
    /* 省略get、set和带参构造方法 */

 

1.2.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://");
        map.put("CSDN地址", "http://");
        map.put("粉丝数量", 4153);
        return map;
    

 

1.2.3 测试不同数据类型返回的json

OK,写好了接口,分别返回了一个User 对象、一个List集合和一个Map集合,其中Map 集合中的 value存的是不同的数据类型。接下来我们依次来测试一下效果。

在浏览器中输入:localhost:8080/json/user返回 json 如下:

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

    1

在浏览器中输入:localhost:8080/json/list返回 json 如下:

["id":1,"username":"倪升武","password":"123456","id":2,"username":"达人课","password":"123456"]

    1

在浏览器中输入:localhost:8080/json/map 返回 json 如下:

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

    1

可以看出,map中不管是什么数据类型,都可以转成相应的json格式,这样就非常方便。

1.2.4 jackson 中对null的处理

在实际项目中,我们难免会遇到一些 null值出现,我们转json 时,是不希望有这些 null出现的,比如我们期望所有的null在转json时都变成“”这种空字符串,那怎么做呢?在Spring Boot中,我们做一下配置即可,新建一个jackson 的配置类:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import java.io.IOException;

@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://");
    map.put("CSDN地址", null);
    map.put("粉丝数量", 4153);
    return map;

 

重启项目,再次输入:localhost:8080/json/map,可以看到jackson已经将所有null字段转成了空字符串了。

"作者信息":"id":1,"username":"倪升武","password":"","CSDN地址":"","粉丝数量":4153,"博客地址":"http://blog.itcodai.com"

    1

1.3 使用阿里巴巴FastJson的设置
1.3.1 jackson和fastJson的对比

有很多朋友习惯于使用阿里巴巴的fastJson 来做项目中 json转换的相关工作,目前我们项目中使用的就是阿里的fastJson,那么jackson 和 fastJson 有哪些区别呢?根据网上公开的资料比较得到下表。

选项fastJsonjackson
上手难易程度 容易 中等
高级特性支持 中等 丰富
官方文档、Example支持 中文 英文
处理json速度 略快

 

1.3.2 fastJson依赖导入

使用fastJson 需要导入依赖,本课程使用1.2.35 版本,依赖如下:

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

 

1.3.3 使用fastJson处理null

使用fastJson 时,对 null的处理和jackson有些不同,需要继承WebMvcConfigurationSupport 类,然后覆盖 configureMessageConverters方法,在方法中,我们可以选择对要实现 null转换的场景,配置好即可。如下:

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

@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);
    

 

1.4 封装统一返回的数据结构

以上是 Spring Boot 返回json 的几个代表的例子,但是在实际项目中,除了要封装数据之外,我们往往需要在返回的json中添加一些其他信息,比如返回一些状态码code ,返回一些 msg给调用者,这样调用者可以根据 code或者 msg做一些逻辑判断。所以在实际项目中,我们需要封装一个统一的json返回结构存储返回信息。
1.4.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方法

 

1.4.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://");
        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":"操作成功!"

    1

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

"code":"0","data":["id":1,"password":"123456","username":"倪升武","id":2,"password":"123456","username":"达人课"],"msg":"获取用户列表成功"

    1

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

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

    1

通过封装,我们不但将数据通过json传给前端或者其他接口,还带上了状态码和提示信息,这在实际项目场景中应用非常广泛。

2. Spring Boot返回json数据

(注:这篇文章的方式不是最好的方式,可以废弃不读,在章节66. Spring Boot完美使用FastJson解析JSON数据,提供最完美的方案。)

       在做如下操作之前,我们对之前的Hello进行简单的修改,我们新建一个包com.kfit.test.web 然后新建一个类HelloControoler, 然后修改App.java类,主要是的这个类就是一个单纯的启动类。

主要代码如下:

App.java

packagecom.kfit;

importorg.springframework.boot.SpringApplication;

importorg.springframework.boot.autoconfigure.SpringBootApplication;

/**

 * Hello world!

 *

 */

//其中@SpringBootApplication申明让spring boot自动给程序进行必要的配置,等价于以默认属性使用@Configuration,@EnableAutoConfiguration和@ComponentScan

@SpringBootApplication

publicclassApp{

              publicstatic void main(String[] args) {

                 SpringApplication.run(App.class, args);

       }

}

 

com.kfit.test.web.HelloController

package com.kfit.test.web;

 

importorg.springframework.web.bind.annotation.RequestMapping;

importorg.springframework.web.bind.annotation.RestController;

 

@RestController// 标记为:restful

publicclass HelloController{

      

       @RequestMapping("/")

       public String hello(){

              return"Helloworld!";

    }

}

运行代码和之前是一样的效果的。

 

我们在编写接口的时候,时常会有需求返回json数据,那么在spring boot应该怎么操作呢?主要是在class中加入注解@RestController,。

返回JSON之步骤:

       (1)编写一个实体类Demo

   (2)编写DemoController;

   (3)在DemoController加上@RestController和@RequestMapping注解;

   (4)测试

具体代码如下:

com.kfit.test.bean.Demo :

package com.kfit.test.bean;

/**

 * 测试实体类.

 * @author Administrator

 *

 */

publicclass Demo {

       privatelongid;//主键.

       private String name;//测试名称.

       publiclong getId() {

              returnid;

       }

       publicvoid setId(longid) {

              this.id = id;

       }

       public StringgetName() {

              returnname;

       }

       publicvoid setName(String name) {

              this.name = name;

       }

}

 

com.kfit.test.web.DemoController

package com.kfit.test.web;

importorg.springframework.web.bind.annotation.RequestMapping;

importorg.springframework.web.bind.annotation.RestController;

import com.kfit.test.bean.Demo;

/**

 * 测试.

 * @author Administrator

 *

 */

@RestController

@RequestMapping("/demo")

publicclass DemoController{

      

       /**

        * 返回demo数据:

        * @return

        */

       @RequestMapping("/getDemo")

       public Demo getDemo(){

              Demo demo = new Demo();

              demo.setId(1);

              demo.setName("Angel");

              returndemo;

       }

}

 

 

{

       id: 1,

       name:"Angel"

}

       是不是很神奇呢,其实Spring Boot也是引用了JSON解析包Jackson,那么自然我们就可以在Demo对象上使用Jackson提供的json属性的注解,对时间进行格式化,对一些字段进行忽略等等。


以上是关于Spring Boot返回Json数据及数据封装的主要内容,如果未能解决你的问题,请参考以下文章

上手spring boot项目之springboot如何返回json数据

spring boot 啥注解可以让返回的json数据都为字符串

Spring Boot 处理异常返回json

2. Spring Boot返回json数据

从 Spring Boot 控制器返回非 JSON 数据(对象列表)

spring boot 解决后台返回 json 到前台中文乱码之后出现返回json数据报错 500:no convertter for return value of type