SpringBoot2.x系列教程15--SpringBoot中整合HttpMessageConverters实现JSON格式化

简介: 前言在之前的章节中,壹哥 带着各位学习了如何在Spring Boot中进行SSM整合。那么接下来,我们会继续深入研究SpringBoot对SpringMVC框架的支持,学习SpringBoot如何进行更深度的定制化Web开发。前面我讲过,SpringBoot严格的来说,应该是一种负责把其他已有框架整合在一起的工具,SpringBoot主要是把各种框架都整合集中在一起,简化我们的Web开发。所以很多的功能,其实都不是SpringBoot完成的,而是由SpringBoot中整合的其他框架来完成的。比如Web开发,更多的是由SpringMVC来完成,只是SpringBoot很好的把Spring

前言

在之前的章节中,壹哥 带着各位学习了如何在Spring Boot中进行SSM整合。那么接下来,我们会继续深入研究SpringBoot对SpringMVC框架的支持,学习SpringBoot如何进行更深度的定制化Web开发。

前面我讲过,SpringBoot严格的来说,应该是一种负责把其他已有框架整合在一起的工具,SpringBoot主要是把各种框架都整合集中在一起,简化我们的Web开发。所以很多的功能,其实都不是SpringBoot完成的,而是由SpringBoot中整合的其他框架来完成的。比如Web开发,更多的是由SpringMVC来完成,只是SpringBoot很好的把SpringMVC整合了进来,而且对SpringMVC的定制化开发也提供了很多便利。

本文会给大家讲解SpringBoot中是如何对SpringMVC进行整合支持的,以此为我们以后学习其他框架的整合提供借鉴思路。

一. SpringMVC简介

Spring Boot中内嵌了Tomcat,Jetty或Undertow等服务器,使得我们可以非常轻松的创建出一个HTTP服务器,而大多数的web应用都可以使用spring-boot-starter-web模块进行快速搭建和运行,Web模块的开发主要是基于SpringMVC框架来进行实现。

1. SpringMVC概念

SpringMVC框架是一个“模型,视图,控制器”的Web框架,允许用户创建特定的@Controller或@RestController类,来处理传入的HTTP请求,通过@RequestMapping注解可以将控制器中的方法映射到相应的HTTP请求。

2. SpringMVC的自动配置特性

Spring Boot为Spring MVC提供的auto-configuration特性适用于大多数应用,并在Spring默认功能上添加了以下特性:

  1. 引入ContentNegotiatingViewResolver和BeanNameViewResolver beans。
  2. 对静态资源的支持,包括对WebJars的支持。
  3. 自动注册Converter,GenericConverter,Formatter beans。
  4. 对HttpMessageConverters的支持,负责Http信息转换。
  5. 自动注册MessageCodeResolver。
  6. 对静态index.html的支持。
  7. 对自定义Favicon的支持。
  8. 自动使用ConfigurableWebBindingInitializer bean。

我们可以添加自己的WebMvcConfigurerAdapter类型的@Configuration类,而不需要@EnableWebMvc注解;也可以添加自定义的HttpMessageConverters实现JSON、XML信息的自定义转换。

二. HttpMessageConverter简介

1. 概述

现在我们进行Web开发,一般都要设计成RESTful风格的API,通过JSON格式的数据进行交互。但是前端传入的 JSON 数据到底是如何被解析成 Java 对象作为 API入参的,后端返回的结果又是如何把 Java 对象解析成 JSON 格式的数据返回给前端的,在整个数据流转的过程中,这些工作都是由谁来完成的呢?

其实这都是由HttpMessageConverter起到的作用!

2. HttpMessageConverter简介

org.springframework.http.converter.HttpMessageConverter 是SpringMVC中提供的一个策略接口,它是一个转换器类,负责转换HTTP的请求和响应,可以把对象自动转换为JSON(使用Jackson库或Gson库)或XML(使用Jackson XML或者JAXB2),对字符串默认使用UTF-8编码处理,一般情况下我们采用默认配置就可以。

该接口说明如下:

Strategy interface that specifies a converter that can convert from and to HTTP requests and responses。


简单说就是 HTTP request(请求)和response(响应)的转换器。该接口里有5个方法,接收到请求时判断是否能读(canRead),能读则读(read);返回结果时判断是否能写(canWrite),能写则写(write),以及获取支持的 MediaType(application/json之类)方法。

booleancanRead(Class<?>clazz, MediaTypemediaType);
booleancanWrite(Class<?>clazz, MediaTypemediaType);
List<MediaType>getSupportedMediaTypes();
Tread(Class<?extendsT>clazz, HttpInputMessageinputMessage) throwsIOException, HttpMessageNotReadableException;
voidwrite(Tt, MediaTypecontentType, HttpOutputMessageoutputMessage) throwsIOException, HttpMessageNotWritableException;

3. HttpMessageConverter转换原理

利用SpringMVC框架,可以使得我们在开发时,只要在代码中使用@RequestBody和@ResponseBody两个注解,就可以分别完成从请求报文到对象和从对象到响应报文的转换。而在源码内部,其实这种灵活的消息转换机制就是利用HttpMessageConverter来实现的。

实现过程参考下图:

SpringMVC在启动时会自动配置一些默认的HttpMessageConverter转换器,在 WebMvcConfigurationSupport类中添加了缺省的MessageConverter,比如MappingJackson2HttpMessageConverter,StringHttpMessageConverter等。

protectedfinalvoidaddDefaultHttpMessageConverters(List<HttpMessageConverter<?>>messageConverters) {
StringHttpMessageConverterstringConverter=newStringHttpMessageConverter();
stringConverter.setWriteAcceptCharset(false);
messageConverters.add(newByteArrayHttpMessageConverter());
messageConverters.add(stringConverter);
messageConverters.add(newResourceHttpMessageConverter());
messageConverters.add(newSourceHttpMessageConverter<Source>());
messageConverters.add(newAllEncompassingFormHttpMessageConverter());
if (romePresent) {
messageConverters.add(newAtomFeedHttpMessageConverter());
messageConverters.add(newRssChannelHttpMessageConverter());
        }
if (jackson2XmlPresent) {
ObjectMapperobjectMapper=Jackson2ObjectMapperBuilder.xml().applicationContext(this.applicationContext).build();
messageConverters.add(newMappingJackson2XmlHttpMessageConverter(objectMapper));
        }
elseif (jaxb2Present) {
messageConverters.add(newJaxb2RootElementHttpMessageConverter());
        }
if (jackson2Present) {
ObjectMapperobjectMapper=Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build();
messageConverters.add(newMappingJackson2HttpMessageConverter(objectMapper));
        }
elseif (gsonPresent) {
messageConverters.add(newGsonHttpMessageConverter());
        }
    }

从源码中可以看到,SpringMVC中使用Jackson库或Gson库来转换json字符串,使用使用Jackson XML或者JAXB2来转换XML。

而如果我们没有配置自己的 MessageConverter,SpringMVC启动时就会调用 addDefaultHttpMessageConverters()方法。

4. SpringBoot中自定义HttpMessageConverters的实现思路

如果我们想在SpringBoot中自定义自己的HttpMessageConverters该怎么办呢?这时候,我们可以使用HttpMessageConverters添加HttpMessageConverter原生转换类或自定义转换类,如下所示:

importorg.springframework.boot.autoconfigure.web.HttpMessageConverters;
importorg.springframework.context.annotation.*;
importorg.springframework.http.converter.*;
@ConfigurationpublicclassMyConfiguration {
@BeanpublicHttpMessageConverterscustomConverters() {
HttpMessageConverter<?>additional= ...
HttpMessageConverter<?>another= ...
returnnewHttpMessageConverters(additional, another);
    }
}

从上面的代码示例中,我们看到,可以把HttpMessageConverter类添加到converters列表中,通过这种方式来覆盖默认的转换器列表(converters)。

5. 自定义消息转换器的方式

我们可以自定义自己的消息转换器来满足特定的需求,一般自定义消息转换器有两种方式:

  • 1. 使用Spring或者第三方提供的现成的HttpMessageConverter;
  • 2. 自己重写一个HttpMessageConverter。

三. 使用FastJsonHttpMessageConverter替换默认的转换器

接下来 壹哥 就通过一个案例,利用FastJsonHttpMessageConverter来替换掉默认的消息转换器。

1. 创建SpringBoot项目

我们在之前的基础上,新建一个模块demo10,并将其改造为SpringBoot项目。

2. 添加FastJson依赖

在SpringBoot项目中,当我们在控制器类或者其内部的方法上添加@RestController注解和@ResponseBody注解后,默认会使用jackson插件来返回json格式的数据,但是我们也可以利用fastjson为我们提供的FastJsonHttpMessageConverter来返回json格式的数据。所以这里首先引入fastjson的依赖包。

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

3. 配置FastJsonHttpMessageConverter

我们可以通过实现WebMvcConfigurer接口,来配置FastJsonHttpMessageConverter,在Spring Boot2.0版本以后推荐使用这种方式来进行Web配置,这样不会覆盖掉Spring Boot的一些默认配置。

接下来我们在项目包中创建config包,并创建一个CustomWebMvcConfigurer类,代码结构如下图所示:

CustomWebMvcConfigurer类中的内容:

/***实现WebMvcConfigurer接口来配置FastJsonHttpMessageConverter,*Spring Boot2.0版本以后推荐使用这种方式来进行web配置,这样不会覆盖掉Spring Boot的一些默认配置.*/@ConfigurationpublicclassCustomWebMvcConfigurerimplementsWebMvcConfigurer {
@OverridepublicvoidextendMessageConverters(List<HttpMessageConverter<?>>converters) {
FastJsonHttpMessageConverterconverter=newFastJsonHttpMessageConverter();
FastJsonConfigconfig=newFastJsonConfig();
config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
converter.setFastJsonConfig(config);
converter.setDefaultCharset(Charset.forName("UTF-8"));
converters.add(converter);
    }
}

3.1 FastJson中的SerializerFeature简介

在FastJson配置实体时,会调用setSerializerFeatures方法配置多个过滤方式,常用的配置如下:

3.2 常用的SerializerFeature释义

QuoteFieldNames,//输出key时是否使用双引号,默认为true;UseSingleQuotes,//使用单引号而不是双引号,默认为false;WriteMapNullValue,//是否输出值为null的字段,默认为false; WriteEnumUsingToString,//Enum输出name()或者original,默认为false;UseISO8601DateFormat,//Date使用ISO8601格式输出,默认为false;WriteNullListAsEmpty,//List字段如果为null,输出为[],而非null;WriteNullStringAsEmpty,//字符类型字段如果为null,输出为"",而非null; WriteNullNumberAsZero,//数值字段如果为null,输出为0,而非null;WriteNullBooleanAsFalse,//Boolean字段如果为null,输出为false,而非null;SkipTransientField,//如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true;SortField,//按字段名称排序后输出,默认为false;@DeprecatedWriteTabAsSpecial,//把\t做转义输出,默认为false;PrettyFormat,//结果是否格式化,默认为false;WriteClassName,//序列化时写入类型信息,默认为false,反序列化是需用到;DisableCircularReferenceDetect,//消除对同一对象循环引用的问题,默认为false;WriteSlashAsSpecial,//对斜杠'/'进行转义;BrowserCompatible,//将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6,默认为false;WriteDateUseDateFormat,//全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd";JSON.toJSONString(obj,SerializerFeature.WriteDateUseDateFormat);DisableCheckSpecialChar,//一个对象的字符串属性中如果有特殊字符如双引号,将会在转成json时带有反斜杠转移符。如果不需要转义,可以使用这个属性,默认为false.

4. 创建对象实体

然后我们再创建一个“com.yyg.boot.domain”包,在这里创建一个User实体类。

packagecom.yyg.boot.domain;
importlombok.AllArgsConstructor;
importlombok.Data;
@Data@AllArgsConstructorpublicclassUser {
privateStringname;
privateStringaddress;
}

5. 创建Controller

再创建一个“com.yyg.boot.web”包,在里面创建Controller类,定义一个”/users“接口。

packagecom.yyg.boot.web;
importcom.yyg.boot.domain.User;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
importorg.springframework.web.bind.annotation.RestController;
importjava.util.ArrayList;
importjava.util.List;
@RestControllerpublicclassUserController {
@RequestMapping(value="/users", method=RequestMethod.GET)
publicObjectgetList() {
List<User>list=newArrayList<>();
//测试字符串有null的情况Useru1=newUser("一一哥", null);
list.add(u1);
returnlist;
    }
}

6. 创建程序入口类

最后我们在项目根目录下创建启动类。

packagecom.yyg.boot;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
/*** 自定义HttpMessageConverter*/@SpringBootApplicationpublicclassConvertApplication {
publicstaticvoidmain(String[] args) {
SpringApplication.run(ConvertApplication.class, args);
    }
}

7. 项目结构

最后整个项目的代码结构如下图所示,各位可以参考创建:

8. 启动项目进行测试

最后我们启动项目,在浏览器中访问http://localhost:8080/users接口。


因为我们CustomWebMvcConfigurer类的代码中,没有配置WriteMapNullValue,所以如果返回结果中有null值则不显示,效果如下:

接着我们在CustomWebMvcConfigurer中添加WriteMapNullValue配置,如下图:

然后重新启动项目并访问,从结果可以看出,我们配置的消息转换器起了作用,null值展示了出来。

然后我们在CustomWebMvcConfigurer类中,再改为WriteNullStringAsEmpty配置,如下图:

然后重新启动项目并访问,从结果中可以看出,我们配置的消息转换器又起了作用,null被替换成了""。

结语

通过定义一个Config配置类,我们就把自定义的HttpMessageConverter类整合到了SpringBoot中,替换掉了默认的HttpMessageConverter类,你会发现在这个过程中,其实也非常的简单,我们基本没有进行过多的参与。今天的内容你学会了吗?评论区和大家讨论一下吧。

今日小作业:

请在学生管理系统中,把所有的请求和响应信息中的null值替换为""。

相关文章
|
1月前
|
Cloud Native Java C++
Springboot3新特性:开发第一个 GraalVM 本机应用程序(完整教程)
文章介绍如何在Spring Boot 3中利用GraalVM将Java应用程序编译成独立的本机二进制文件,从而提高启动速度、减少内存占用,并实现不依赖JVM运行。
195 1
Springboot3新特性:开发第一个 GraalVM 本机应用程序(完整教程)
|
1月前
|
前端开发 Java 数据安全/隐私保护
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
文章通过一个简单的SpringBoot项目,详细介绍了前后端如何实现用户登录功能,包括前端登录页面的创建、后端登录逻辑的处理、使用session验证用户身份以及获取已登录用户信息的方法。
176 2
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
|
1月前
|
Java API Apache
Springboot+shiro,完整教程,带你学会shiro
这篇文章提供了一个完整的Apache Shiro与Spring Boot结合使用的教程,包括Shiro的配置、使用以及在非Web和Web环境中进行身份验证和授权的示例。
65 2
Springboot+shiro,完整教程,带你学会shiro
|
1月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
300 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
|
1月前
|
缓存 NoSQL Java
springboot的缓存和redis缓存,入门级别教程
本文介绍了Spring Boot中的缓存机制,包括使用默认的JVM缓存和集成Redis缓存,以及如何配置和使用缓存来提高应用程序性能。
96 1
springboot的缓存和redis缓存,入门级别教程
|
2月前
|
JavaScript Java 关系型数据库
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
本文介绍了一个基于Spring Boot和Vue.js实现的在线考试系统。随着在线教育的发展,在线考试系统的重要性日益凸显。该系统不仅能提高教学效率,减轻教师负担,还为学生提供了灵活便捷的考试方式。技术栈包括Spring Boot、Vue.js、Element-UI等,支持多种角色登录,具备考试管理、题库管理、成绩查询等功能。系统采用前后端分离架构,具备高性能和扩展性,未来可进一步优化并引入AI技术提升智能化水平。
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
|
2月前
|
Java 关系型数据库 MySQL
毕设项目&课程设计&毕设项目:springboot+jsp实现的房屋租租赁系统(含教程&源码&数据库数据)
本文介绍了一款基于Spring Boot和JSP技术的房屋租赁系统,旨在通过自动化和信息化手段提升房屋管理效率,优化租户体验。系统采用JDK 1.8、Maven 3.6、MySQL 8.0、JSP、Layui和Spring Boot 2.0等技术栈,实现了高效的房源管理和便捷的租户服务。通过该系统,房东可以轻松管理房源,租户可以快速找到合适的住所,双方都能享受数字化带来的便利。未来,系统将持续优化升级,提供更多完善的服务。
毕设项目&课程设计&毕设项目:springboot+jsp实现的房屋租租赁系统(含教程&源码&数据库数据)
|
1月前
|
数据采集 监控 Java
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
本文是关于SpringBoot日志的详细教程,涵盖日志的定义、用途、SLF4J框架的使用、日志级别、持久化、文件分割及格式配置等内容。
132 0
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
|
1月前
|
存储 JSON 算法
JWT令牌基础教程 全方位带你剖析JWT令牌,在Springboot中使用JWT技术体系,完成拦截器的实现 Interceptor (后附源码)
文章介绍了JWT令牌的基础教程,包括其应用场景、组成部分、生成和校验方法,并在Springboot中使用JWT技术体系完成拦截器的实现。
72 0
JWT令牌基础教程 全方位带你剖析JWT令牌,在Springboot中使用JWT技术体系,完成拦截器的实现 Interceptor (后附源码)
|
1月前
|
JSON JavaScript 前端开发
js如何格式化一个JSON对象?
js如何格式化一个JSON对象?
65 3