list json格式_008 Spring Boot 返回JSON数据格式封装

c8e0c71c93126fe56038c4dfda8b0ace.png

在软件开发过程中,数据之间的交互运用最广泛的格式是JSON,那JSON是什么呢?给我们带来哪些方便呢?

JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

对,JSON就是这么棒,那在Spring Boot 项目中我们应该如何使用它呢?

答案:只需要在控制器类上加@RestController注解即可。

1. Spring Boot 默认对Json的处理

常用的数据结构有类对象、List对象、Map对象,对于此类数据,比如在做前后端分离的项目中,我们需要将封装好的数据返回给前端,那Spring Boot 默认对Json的处理是如何实现的呢?

下面一步步来实现:

1.1 创建 User 实体类

我们首先需要创建一个用户对象,包含了用户ID(id)、用户名(username)、用户密码(password),此处省略N行代码。

1.2 创建Controller类

然后我们创建一个 Controller,在控制器类上我们需要加上注解@RestController,用于返回JSON格式。

package com.bowen.controller;

import com.bowen.entity.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <h3>springboot-study</h3>
 * <p>json Controller</p>
 * @author : zhang.bw
 * @date : 2020-07-17 21:37
 **/
@RestController
@RequestMapping("/json")
public class JsonController {

    @RequestMapping("/user")
    public User getUser() {
        return new User(1, "猿码天地", "公众号【猿码天地】");
    }

    @RequestMapping("/list")
    public List<User> getUserList() {
        List<User> userList = new ArrayList<>();

        User user1 = new User(1, "猿码天地001", "公众号1【猿码天地】");
        User user2 = new User(2, "猿码天地002", "公众号2【猿码天地】");
        userList.add(user1);
        userList.add(user2);
        return userList;
    }

    @RequestMapping("/map")
    public Map<String, Object> getMap() {
        Map<String, Object> map = new HashMap<>();

        User user = new User(1, "猿码天地", null);
        map.put("作者信息", user);
        map.put("博客地址", "https://blog.csdn.net/zbw125");
        map.put("CSDN地址", "https://blog.csdn.net/zbw125");
        map.put("粉丝数量", 100000);
        return map;
    }
}

1.3 测试json格式返回

分别返回一个 User 对象、一个 List 集合和一个 Map 集合,具体测试结果如下所示:

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

{"id":1,"password":"公众号【猿码天地】","username":"猿码天地"}

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

[{"id":1,"password":"公众号1【猿码天地】","username":"猿码天地001"},{"id":2,"password":"公众号2【猿码天地】","username":"猿码天地002"}]

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

{"作者信息":{"id":1,"password":"","username":"猿码天地"},"粉丝数量":100000,"博客地址":"https://blog.csdn.net/zbw125","微信公众号":"猿码天地"}

从测试结果来看,无论我们返回什么样的数据格式,在浏览器发送请求后,都会返回我们想要的JSON格式,前端攻城狮们拿到这些JSON数据后,就可以任由发挥了。

1.4 jackson 中对null的处理

在开发过程中,如果JSON格式中的数据有null怎么办,不要怕,我们新建一个配置类,可以将null转换为"""

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<>();
    User user = new User(1, "猿码天地", null);
    map.put("作者信息", user);
    map.put("博客地址", "https://blog.csdn.net/zbw125");
    map.put("微信公众号", "猿码天地");
    map.put("粉丝数量", null);
    return map;
}

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

{"作者信息":{"id":1,"username":"猿码天地","password":""},"粉丝数量":"","博客地址":"https://blog.csdn.net/zbw125","微信公众号":"猿码天地"}

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

2.1 jackson 和 fastJson 的对比

调用方便性而言:

FastJSON提供了大量静态方法,调用简洁方便
Jackson须实例化类,调用相对繁琐,可通过封装成JSON工具类简化调用

性能而言:

FastJSON反序列化的性能略差,对于256k的json字符串,平均700ms
Jackson 的 data binding反序列化的性能稍好,对于256k的json字符串,平均600ms
两者的序列化性能基本相同,对于256k的json字符串,平均140ms
相对data binding方式(ObjectMapper.writeValueAsString()),Jackson的流输出方式(JsonGenerator.writeObject())性能稍好,平均130ms

总结如下:

选项fastJsonjackson

2.2 fastJson依赖导入

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

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

2.3 使用 fastJson 处理 null

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

package com.bowen.config;

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;

/**
 * <h3>springboot-study</h3>
 * <p>使用阿里 FastJson 作为JSON MessageConverter</p>
 * @author : zhang.bw
 * @date : 2020-07-17 21:37
 **/
@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 结构中属性包括数据、状态码、提示信息即可,构造方法可以根据实际业务需求做相应的添加即可,一般来说,应该有默认的返回结构,也应该有用户指定的返回结构。如下:

package com.bowen.entity;

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;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

3.2 修改 Controller 中的返回值类型及测试

由于 JsonResult 使用了泛型,所以所有的返回值类型都可以使用该统一结构,在具体的场景将泛型替换成具体的数据类型即可,非常方便,也便于维护。在实际项目中,还可以继续封装,比如状态码和提示信息可以定义一个枚举类型,以后我们只需要维护这个枚举类型中的数据即可。根据以上的 JsonResult,我们改写一下 Controller,如下:

package com.bowen.controller;

import com.bowen.entity.JsonResult;
import com.bowen.entity.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <h3>springboot-study</h3>
 * <p>jsonresult Controller</p>
 * @author : zhang.bw
 * @date : 2020-07-17 21:37
 **/
@RestController
@RequestMapping("/jsonresult")
public class JsonResultController {

    @RequestMapping("/user")
    public JsonResult<User> getUser() {

        User user = new User(1, "猿码天地", "公众号【猿码天地】");
        return new JsonResult<>(user);
    }

    @RequestMapping("/list")
    public JsonResult<List> getUserList() {
        List<User> userList = new ArrayList<>();

        User user1 = new User(1, "猿码天地001", "公众号1【猿码天地】");
        User user2 = new User(2, "猿码天地002", "公众号2【猿码天地】");
        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("博客地址", "https://blog.csdn.net/zbw125");
        map.put("CSDN地址", "https://blog.csdn.net/zbw125");
        map.put("粉丝数量", 100000);
        return new JsonResult<>(map);
    }
}

我们重新在浏览器中输入:localhost:8080/jsonresult/user 返回 json 如下:

{
    "code":"0",
    "data":{
        "id":1,
        "password":"公众号【猿码天地】",
        "username":"猿码天地"
    },
    "msg":"操作成功!"
}

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

{
    "code":"0",
    "data":[
        {
            "id":1,
            "password":"公众号1【猿码天地】",
            "username":"猿码天地001"
        },
        {
            "id":2,
            "password":"公众号2【猿码天地】",
            "username":"猿码天地002"
        }
    ],
    "msg":"获取用户列表成功"
}

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

{
    "code":"0",
    "data":{
        "作者信息":{
            "id":1,
            "password":"",
            "username":"猿码天地"
        },
        "CSDN地址":"https://blog.csdn.net/zbw125",
        "粉丝数量":100000,
        "博客地址":"https://blog.csdn.net/zbw125"
    },
    "msg":"操作成功!"
}

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

4. 总结

本节课主要系统的讲解了Spring Boot 返回JSON数据格式封装,主要包括 Spring Boot 默认对Json的处理、使用阿里巴巴FastJson的设置、封装统一返回的数据结构等,并通过详细的例子进行演示,非常详细,相信通过这节课程的学习对springboot 集成 json 格式的理解更加深刻。

5. 源码获取

我是猿人,一个在互联网打拼的工具人 Java研究猿,感谢各位点赞、收藏和评论,我们下期见!
文章持续更新,源码地址下载:源码地址
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值