百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

SpringBoot系列教程22-整合SpringMVC之HttpMessageConverters

toyiye 2024-06-21 12:19 12 浏览 0 评论

一.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之类)方法。

boolean canRead(Class<?> clazz, MediaType mediaType);
boolean canWrite(Class<?> clazz, MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException;
void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;

3.HttpMessageConverter转换原理

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

实现过程参考下图:

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

protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
        StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
        stringConverter.setWriteAcceptCharset(false);

        messageConverters.add(new ByteArrayHttpMessageConverter());
        messageConverters.add(stringConverter);
        messageConverters.add(new ResourceHttpMessageConverter());
        messageConverters.add(new SourceHttpMessageConverter<Source>());
        messageConverters.add(new AllEncompassingFormHttpMessageConverter());

        if (romePresent) {
            messageConverters.add(new AtomFeedHttpMessageConverter());
            messageConverters.add(new RssChannelHttpMessageConverter());
        }

        if (jackson2XmlPresent) {
            ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.xml().applicationContext(this.applicationContext).build();
            messageConverters.add(new MappingJackson2XmlHttpMessageConverter(objectMapper));
        }
        else if (jaxb2Present) {
            messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
        }

        if (jackson2Present) {
            ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build();
            messageConverters.add(new MappingJackson2HttpMessageConverter(objectMapper));
        }
        else if (gsonPresent) {
            messageConverters.add(new GsonHttpMessageConverter());
        }
    }

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

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

4.Spring Boot中自定义HttpMessageConverters实现思路

在Spring Boot中我们可以使用HttpMessageConverters添加HttpMessageConverter原生转换类或自定义转换类。

import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;

@Configuration
public class MyConfiguration {

    @Bean
    public HttpMessageConverters customConverters() {
        HttpMessageConverter<?> additional = ...
        HttpMessageConverter<?> another = ...
        return new HttpMessageConverters(additional, another);
    }
}

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

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

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

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

二.Spring Boot中用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的一些默认配置.

我们创建如下的目录结构。

/**
 *实现WebMvcConfigurer接口来配置FastJsonHttpMessageConverter,
 *Spring Boot2.0版本以后推荐使用这种方式来进行web配置,这样不会覆盖掉Spring Boot的一些默认配置.
 */
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
        converter.setFastJsonConfig(config);
        converter.setDefaultCharset(Charset.forName("UTF-8"));
        converters.add(converter);
    }

}

3.1 fastJson中的SerializerFeature

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

常用的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;

@Deprecated
WriteTabAsSpecial,//把\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实体类。

package com.yyg.boot.domain;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class User {

    private String name;

    private String address;

}

5.创建Controller

我们创建“com.yyg.boot.web”包,在里面创建一个Controller类。

package com.yyg.boot.web;

import com.yyg.boot.domain.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class UserController {

    @RequestMapping(value = "/get", method = RequestMethod.GET)
    public Object getList() {
        List<User> list = new ArrayList<>();
        //测试字符串有null的情况
        User u1 = new User("一一哥", null);
        list.add(u1);
        return list;
    }

}

6.创建程序入口类

在项目根目录下创建启动类。

package com.yyg.boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 自定义HttpMessageConverter
 */
@SpringBootApplication
public class ConvertApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConvertApplication.class, args);
    }

}

整个项目结构:

7.启动类进行测试

启动项目访问http://localhost:8080/users

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

接着我们可以在CustomWebMvcConfigurer中添加WriteMapNullValue,如下图:

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

接着我们可以在CustomWebMvcConfigurer中添加WriteNullStringAsEmpty,如下图:

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

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码