SpringBoot系列(5):SpringBoot对JSON数据的处理

目录

前言

1. SpringBoot默认的JSON依赖

2. SpringBoot默认对JSON的处理

2.1 实体类

2.2 Controller控制器

2.3 测试返回的JSON数据

2.4 jackson中对null的处理

3. SpringBoot配置阿里巴巴fastjson

3.1 jackson和fastjson对比

3.2 pom.xml文件配置fastjson依赖

3.3 使用fastjson处理null值

4. 封装统一返回的数据结构

4.1 定义统一的 json 结构

4.2 改造Controller控制器

4.3 测试统一返回的JSON数据格式

5. 小结


前言

JSON的可读性比XML强几条长安街,解析规则也简单许多。XML解析的时候规则太多了,动不动就非法字符,动不动就抛异常。这对追求高开发速度和低开发门槛的企业来说是个致命伤。

在一个项目的各接口间、前后端之间数据的传输多使用 JSON格式的数据进行传输交互。而Spring Boot框架项目接口返回 JSON格式的数据比较简单:在 Controller 类中使用@RestController注解即可返回 JSON格式的数据。

@RestController是SpringBoot 新增的一个注解,OK,看下这个注解类:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {

    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any (or empty String otherwise)
     * @since 4.0.1
     */
    @AliasFor(annotation = Controller.class)
    String value() default "";

}

可以看出, @RestController 注解包含了:@Controller@ResponseBody两个核心注解。

  • @Controller:当一个类引入这个注解,表明当前的这个类是一个controller控制器类;
  • @ResponseBody:表示方法返回值的注释应该绑定到web响应的消息体中。支持带注释的处理程序方法。从4.0版本开始,这个注释也可以添加到类型级别,在这种情况下,它是继承的,不需要添加到方法级别。

1. SpringBoot默认的JSON依赖

@ResponseBody注解是将返回的数据结构转换为 Json 格式。所以,默认情况下,使用了`@RestController 注解,即可将返回的数据结构转换成 JSON格式。

在Spring Boot 中默认使用的 JSON解析技术框架是 jackson。这里,我们怎么去看SpringBoot默认的JSON依赖呢,OK,直接去找pom.xml文件中的spring-boot-starter-web这个web启步依赖:

进入spring-boot-starter-web依赖,查看一下这个包它的JSON依赖关系:

这里,我们知道,SpringBoot的web起步依赖,已经封装了spring-boot-starter-json依赖,也可以看到很多spring-boot-starter-xxx系列的依赖,这是 Spring Boot 的特点之一,不需要去引入很多相关的依赖了,"spring-boot-starter-xxx "系列直接都包含了所必要的依赖。所以,再次点上面这个 "spring-boot-starter-json"依赖,一探究竟:

 看上图jar包依赖,原来SpringBoot中默认使用的JSON解析框架是 jackson。下面我们看一下默认的 jackson 框架对常用数据类型的转 JSON处理。


2. SpringBoot默认对JSON的处理

在项目开发过程中,我们常用的数据结构大致有:类对象、List对象、Map对象。

OK,来看一下SpringBoot默认的jackson框架对这三种常用的数据结构转成 JHSON后的格式如何。

2.1 实体类

测试需要,先来一个实体类:SysUser.java

**
 * 系统用户实体类
 */
public class SysUser{

    private String id;
    private String userName;
    private String password;

   /**此处省略构造方法、setr和getr方法**/
}

2.2 Controller控制器

有了实体类,还得一个controller把它的信息返回给前端。

controller控制器:SysUserController.java

@RestController
@RequestMapping("/jsonFormat1")
public class SystemUser1Controller {

    @GetMapping("/user")
    public SystemUser getUser() {
        return new SystemUser("1", "小明", "xiaoming123");
    }

    @GetMapping("/list")
    public List<SystemUser> getUserList() {
        List<SystemUser> list= new ArrayList<>();
        SystemUser xiaoming= new SystemUser("1", "小明", "xiaoming123");
        SystemUser xiaoli = new SystemUser("2", "小丽", "xiaoli123");
        list.add(xiaoming);
        list.add(xiaoli);
        return list;
    }

    @GetMapping("/map")
    public Map<String, Object> getMap() {
        Map<String, Object> map = new HashMap<>();
        SystemUser user = new SystemUser("1", "xiaoming", "xiaomign123");
        map.put("用户信息", user);
        map.put("在干啥呢", "working");
        map.put("备注说明", "hello world");
        map.put("一串数字",123456789);
        return map;
    }
}

2.3 测试返回的JSON数据

OK,准备工作已完成,分别返回:一个实体类对象、一个List 集合和一个Map 集合。其中 Map 集合中的 value 存的是不同的数据类型。接下来,我们依次来测试一下各自返回的JSON数据。

【1】返回实体类对象

访问地址:

127.0.0.1:8080/jsonFormat1/user

返回结果:

{"id":"1","userName":"小明","password":"xiaoming123"}

【2】返回List集合

访问地址:

127.0.0.1:8080/jsonFormat1/list

返回结果:

[{"id":"1","userName":"小明","password":"xiaoming123"},{"id":"2","userName":"小丽","password":"xiaoli123"}]

【3】返回Map集合

访问地址:

127.0.0.1:8080/jsonFormat1/map

返回结果:

{"用户信息":{"id":"1","userName":"xiaoming","password":"xiaomign123"},"备注说明":"hello world","在干啥呢":"working","一串数字":123456789}

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

2.4 jackson中对null的处理

在项目开发中,难免会遇到null 值出现。数据封装为JSON格式时,实际上是不希望数据出现null。如果我们期望所有的null 在转换为JSON格式时都变成 "" 这种空字符串,那怎么做呢?

在SpringBoot 中,做以下配置即可,新建一个 jackson 的配置类:

/**
 * jackson数据格式处理类:null值处理
 */
@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;
    }
}

OK,修改一下上面返回map的接口中的部分传值,将其改为null测试:

修改程序:

@GetMapping("/map")
public Map<String, Object> getMap() {
    Map<String, Object> map = new HashMap<>();
    SystemUser user = new SystemUser("1", "xiaoming", "xiaomign123");
    map.put("用户信息", user);
    map.put("在干啥呢", null);
    map.put("备注说明", "hello world");
    map.put("一串数字", null);
    return map;
}

 浏览器访问:localhost:8080/jsonFormat2/map

返回结果:

{"用户信息":{"id":"1","userName":"xiaoming","password":"xiaomign123"},"备注说明":"hello world","在干啥呢":"","一串数字":""}

OK,JacksonConfig配置类已将所有null值字段转换为空字符串了。


3. SpringBoot配置阿里巴巴fastjson

3.1 jackson和fastjson对比

【1】开源jsckson

  • Jackson所依赖的jar包较少,简单易用并且性能也要相对高些。
  • 而且Jackson社区相对比较活跃,更新速度也比较快。
  • Jackson对于复杂类型的json转换bean会出现问题,一些集合Map,List的转换出现问题。
  • Jackson对于复杂类型的bean转换Json,转换的json格式不是标准的Json格式

【2】阿里巴巴fastjson

  • fastjson是一个Java语言编写的高性能的JSON处理器,由阿里巴巴公司开发。
  • 无依赖,不需要例外额外的jar,能够直接跑在JDK上。
  • fastJson在复杂类型的Bean转换Json上会出现一些问题,可能会出现引用的类型,导致Json转换出错,需要制定引用。
  • fastJson采用独创的算法,将parse的速度提升到极致,超过所有json库。
jsckson和fastjson对比
指标 jsckson fastjson
难易度 容易 中等
高级特性支持 中等 丰富
官方文档、Example支持 中文 英文
处理json速度 略快

从扩展上来看,fastJson没有 jackson 灵活,从速度或者上手难度来看,fastJson 可以考虑。目前项目中使用的是阿里的 fastJson,挺方便的。

3.2 pom.xml文件配置fastjson依赖

SpringBoot项目配置fastjson较为简单,直观。在pom.xml文件的<dependencies></dependencies>标签中配置依赖信息即可。

这里,我们配置的fastjson版本:1.2.60。配置如下:

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

3.3 使用fastjson处理null值

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


4. 封装统一返回的数据结构

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

4.1 定义统一的 json 结构

由于封装的 json 数据的类型不确定,所以在定义统一的 json 结构时,我们需要用到泛型。统一的 json 结构中属性包括数据、状态码、提示信息即可,构造方法可以根据实际业务需求做相应的添加即可,一般来说,应该有默认的返回结构,也应该有用户指定的返回结构。

【1】控制器响应实体类,返回接口调用信息描述

/**
 * 控制器响应结果实体类,返回接口调用信息描述
 */
public class ResponseMessage extends BaseModel {

    private static final long serialVersionUID = -7127875856370230011L;

    /**
     * 状态
     */
    private int status = 20000;
    /**
     * 消息说明
     */
    private String message;
    /**
     * 数据信息
     */
    private Object data;

    public ResponseMessage() {
    }

    public ResponseMessage(int status, String message) {
        this.status = status;
        this.message = message;
    }

    public ResponseMessage(int status, String message, Object data) {
        this.status = status;
        this.message = message;
        this.data = data;
    }
    
    /**此处省略变量的set和get方法**/
}

【2】信息状态

public enum ResponseStatus {
    /**
     * 操作成功
     */
    SUCCESS(20000, "操作成功"),
    /**
     * 操作失败
     */
    FAILURE(50000, "操作失败"),
    /**
     * 请求错误
     */
    REQUEST_ERROR(100, "请求错误"),
    /**
     * 服务端程序错误
     */
    SERVER_INTERNAL_ERROR(500, "服务端内部错误"),
    /**
     * 服务类错误
     */
    SERVICE_EXCEPTION(600, "业务逻辑错误");
    /**
     * 响应码
     */
    private int status;
    /**
     * 描述信息
     */
    private String message;
    ResponseStatus() {
    }
    ResponseStatus(int status, String message) {
        this.status = status;
        this.message = message;
    }
    public int getStatus() {
        return status;
    }
    public String getMessage() {
        return message;
    }
}

4.2 改造Controller控制器

定义了返回结果的消息响应实体和消息状态后,所有的接口方法均可以返回消息响应实体对象,而返回的JSON数据可以统一作为入参传递给实体对象。

在具体的接口场景中,将只需将不同的返回数据替换成具体的数据类型即可,非常方便,也便于维护。在实际项目中,还可以继续封装,比如状态码和提示信息还封装为一个枚举类型,这样只需要维护这个枚举类型中的数据即可(暂不赘述)。

根据以上统一定义JSON结构,我们改造一下Controller控制器:

@RestController
@RequestMapping("/jsonFormat3")
public class SystemUser3Controller {

    @GetMapping("/user")
    public ResponseMessage getUser() {
        SystemUser systemUser = new SystemUser("1", "小明", "xiaoming123");
        return new ResponseMessage(ResponseStatus.SUCCESS.getStatus(), ResponseStatus.SUCCESS.getMessage(), systemUser);
    }

    @GetMapping("/list")
    public ResponseMessage getUserList() {
        List<SystemUser> list = new ArrayList<>();
        SystemUser xiaoming = new SystemUser("1", "小明", "xiaoming123");
        SystemUser xiaoli = new SystemUser("2", "小丽", "xiaoli123");
        list.add(xiaoming);
        list.add(xiaoli);
        return new ResponseMessage(ResponseStatus.SUCCESS.getStatus(), ResponseStatus.SUCCESS.getMessage(), list);
    }

    @GetMapping("/map")
    public ResponseMessage getMap() {
        Map<String, Object> map = new HashMap<>();
        SystemUser user = new SystemUser("1", "xiaoming", "xiaomign123");
        map.put("用户信息", user);
        map.put("在干啥呢", "working");
        map.put("备注说明", "hello world");
        map.put("一串数字", 123456789);
        return new ResponseMessage(ResponseStatus.SUCCESS.getStatus(), ResponseStatus.SUCCESS.getMessage(), map);
    }
}

4.3 测试统一返回的JSON数据格式

OK,准备工作已完成。接下来,我们依次来测试一下定义的统一各自返回的JSON数据。

【1】返回实体类对象

访问地址:

127.0.0.1:8080/jsonFormat3/user

返回结果:

{"data":{"id":"1","password":"xiaoming123","userName":"小明"},"message":"操作成功","status":20000}

【2】返回List集合

访问地址:

127.0.0.1:8080/jsonFormat3/list

返回结果:

{"data":[{"id":"1","password":"xiaoming123","userName":"小明"},{"id":"2","password":"xiaoli123","userName":"小丽"}],"message":"操作成功","status":20000}

【3】返回Map集合

访问地址:

127.0.0.1:8080/jsonFormat3/map

返回结果:

{"data":{"用户信息":{"id":"1","password":"xiaomign123","userName":"xiaoming"},"备注说明":"hello world","在干啥呢":"working","一串数字":123456789},"message":"操作成功","status":20000}

通过定义统一返回的JSON数据格式,并对其重新封装封装,将JSON格式数据传给了前端或者其他接口,返回的消息响应体带上了消息状态码和操作提示信息,这在实际项目场景中应用非常广泛。


5. 小结

本节内容主要对SpringBoot中JSON数据的返回、数据格式处理及响应信息结构体封装做了详细的分析与总结。

从Spring Boot 默认的 jackson 框架到阿里巴巴的fastJson 框架,分别对它们的配置做了相应的学习与总结。结合实际项目情况,总结了项目开发过程中使用的 JSON封装结构体,加入了状态码和提示信息,使返回的JSON数据信息更加完整。

项目名称:spring-boot-json

源码地址:https://github.com/JohnnyHL/SpringBoot-Item


愿你就像早晨八九点钟的太阳,活力十足,永远年轻。

发布了93 篇原创文章 · 获赞 136 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_27706119/article/details/104852054