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

简介: Spring Boot中,通过@RestController可自动返回Json数据,默认使用Jackson框架。该注解等价于@Controller + @ResponseBody。可通过配置自定义null值处理方式,也可替换为FastJson等其他解析器,并封装统一的返回结构(如包含code、msg、data的JsonResult),提升前后端交互规范性与可维护性。

在项目开发中,接口与接口之间,前后端之间数据的传输都使用 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 依赖:


org.springframework.boot
spring-boot-starter-json
2.0.3.RELEASE
compile

Spring Boot 中对依赖都做了很好的封装,可以看到很多 spring-boot-starter-xxx 系列的依赖,这是 Spring Boot 的特点之一,不需要人为去引入很多相关的依赖了,starter-xxx 系列直接都包含了所必要的依赖,所以我们再次点进去上面这个 spring-boot-starter-json 依赖,可以看到:


com.fasterxml.jackson.core
jackson-databind
2.9.6
compile


com.fasterxml.jackson.datatype
jackson-datatype-jdk8
2.9.6
compile


com.fasterxml.jackson.datatype
jackson-datatype-jsr310
2.9.6
compile


com.fasterxml.jackson.module
jackson-module-parameter-names
2.9.6
compile

到此为止,我们知道了 Spring Boot 中默认使用的 json 解析框架是 jackson。下面我们看一下默认的 jackson 框架对常用数据类型的转 Json 处理。

  1. 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 和 Map。
    import com.itcodai.course02.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;
    @RestController
    @RequestMapping("/json")
    public class JsonController {
    @RequestMapping("/user")
    public User getUser() {
     return new User(1, "倪升武", "123456");
    
    }
    @RequestMapping("/list")
    public 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 userList;
    
    }
    @RequestMapping("/map")
    public Map 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 的配置类:
    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 getMap() {
    Map map = new HashMap<>(3);
    User user = new User(1, "倪升武", null);
    map.put("作者信息", user);
    map.put("博客地址", "http://blog.itcodai.com");
    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"}
  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 版本,依赖如下:

    com.alibaba
    fastjson
    1.2.35

    2.2 使用 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> 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 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 {
    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 getUser() {
      User user = new User(1, "倪升武", "123456");
      return new JsonResult<>(user);
      }
      @RequestMapping("/list")
      public JsonResult getUserList() {
      List 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 getMap() {
      Map map = new HashMap<>(3);
      User user = new User(1, "倪升武", null);
      map.put("作者信息", user);
      map.put("博客地址", "http://blog.itcodai.com");
      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.itcodai.com"},"msg":"操作成功!"}
      通过封装,我们不但将数据通过 json 传给前端或者其他接口,还带上了状态码和提示信息,这在实际项目场景中应用非常广泛。
  4. 总结
    本节主要对 Spring Boot 中 json 数据的返回做了详细的分析,从 Spring Boot 默认的 jackson 框架到阿里巴巴的 fastJson 框架,分别对它们的配置做了相应的讲解。另外,结合实际项目情况,总结了实际项目中使用的 json 封装结构体,加入了状态码和提示信息,使得返回的 json 数据信息更加完整。
相关文章
|
4月前
|
JSON 前端开发 Java
Spring Boot 返回 JSON 数据及数据封装
本课讲解Spring Boot中JSON处理:通过@RestController返回JSON,利用内置Jackson实现对象、List、Map自动序列化,并自定义配置优雅处理null值,提升前后端交互体验。
|
JSON 前端开发 Java
SpringBoot之JSON参数,路径参数的详细解析
SpringBoot之JSON参数,路径参数的详细解析
1249 0
|
数据采集 JSON 前端开发
SpringBoot 如何统一后端返回格式?老鸟们都是这样玩的!
SpringBoot 如何统一后端返回格式?老鸟们都是这样玩的!
514 1
|
4月前
|
前端开发 JavaScript Java
Spring Boot中使用拦截器
拦截器是Spring Boot中AOP的一种实现,用于拦截动态请求,常用于权限控制、登录验证等场景。它不拦截静态资源(如static目录下的文件),但需注意配置方式对静态资源的影响。通过实现HandlerInterceptor接口,可在请求前、后及完成后执行逻辑。自定义拦截器后,通过WebMvcConfigurer添加路径匹配规则即可生效。支持灵活配置,如排除特定方法拦截,结合注解实现可插拔控制,适用于前后端分离或传统项目中的请求过滤需求。
|
9月前
|
JSON Java 数据格式
Spring Boot返回Json数据及数据封装
在Spring Boot中,接口间及前后端的数据传输通常使用JSON格式。通过@RestController注解,可轻松实现Controller返回JSON数据。该注解是Spring Boot新增的组合注解,结合了@Controller和@ResponseBody的功能,默认将返回值转换为JSON格式。Spring Boot底层默认采用Jackson作为JSON解析框架,并通过spring-boot-starter-json依赖集成了相关库,包括jackson-databind、jackson-datatype-jdk8等常用模块,简化了开发者对依赖的手动管理。
797 3
|
12月前
|
安全 Java 数据库
Spring Security 实战指南:从入门到精通
本文详细介绍了Spring Security在Java Web项目中的应用,涵盖登录、权限控制与安全防护等功能。通过Filter Chain过滤器链实现请求拦截与认证授权,核心组件包括AuthenticationProvider和UserDetailsService,负责用户信息加载与密码验证。文章还解析了项目结构,如SecurityConfig配置类、User实体类及自定义登录逻辑,并探讨了Method-Level Security、CSRF防护、Remember-Me等进阶功能。最后总结了Spring Security的核心机制与常见配置,帮助开发者构建健壮的安全系统。
1832 0
|
存储 Java Spring
深入理解org.springframework.web.context.request.RequestContextHolder
`RequestContextHolder`是Spring提供的一个便捷工具类,用于在非Controller层访问请求上下文信息。通过理解其工作原理和应用场景,可以更好地在Spring应用中管理和使用请求信息,提升代码的可维护性和扩展性。
903 0
|
Java API 开发者
如何在Spring Boot中设计API返回码?
如何在Spring Boot中设计API返回码?
424 0
如何在Spring Boot中设计API返回码?
|
Java 开发者 Spring
springboot DDD的概念以及实战
【5月更文挑战第15天】领域驱动设计(Domain-Driven Design,简称DDD)是一种软件设计方法论,它强调基于业务领域的复杂性来构建软件
1469 2
|
NoSQL Redis 数据安全/隐私保护
若依框架----token权限控制逻辑
若依框架----token权限控制逻辑
1862 0