天天看點

Spring Mvc:HttpMessageConverter 消息轉換器

作者:是啊超ya

HttpMessageConverter 簡介

HttpMessageConverter 是SpringMVC中提供的一個政策接口,它是一個消息轉換器類,Spring Mvc中就是由HttpMessageConverter負責轉換HTTP的請求和響應。

預設情況下,Spring Boot 會自動加載如下消息類型轉換器:

Spring Mvc:HttpMessageConverter 消息轉換器

常見消息類型轉換器介紹:

  • StringHttpMessageConverter:負責讀取字元串格式的資料和寫出二進制格式的資料(當傳回值是或者接受值是String類型時,是由這個處理)
  • MappingJacksonHttpMessageConverter:負責讀取和寫入json格式的資料;(當傳回值是對象或者List,就由這個處理)
  • ByteArrayHttpMessageConverter:負責讀取二進制格式的資料和寫出二進制格式的資料;
  • FormHttpMessageConverter:負責讀取form送出的資料(能讀取的資料格式為 application/x-www-form-urlencoded,不能讀取multipart/form-data格式資料);負責寫入application/x-www-from-urlencoded和multipart/form-data格式的資料;
  • ResourceHttpMessageConverter:負責讀取資源檔案和寫出資源檔案資料;
  • SourceHttpMessageConverter:負責讀取和寫入xml中javax.xml.transform.Source定義的資料;
  • Jaxb2RootElementHttpMessageConverter:負責讀取和寫入xml 标簽格式的資料;
  • AtomFeedHttpMessageConverter:負責讀取和寫入Atom格式的資料;
  • RssChannelHttpMessageConverter:負責讀取和寫入RSS格式的資料;

資料轉換流程

利用SpringMVC架構,可以使得我們在開發時,隻要在代碼中使用@RequestBody和@ResponseBody兩個注解,就可以分别完成從請求封包到對象和從對象到響應封包的轉換。而在源碼内部,其實這種靈活的消息轉換機制就是利用HttpMessageConverter來實作的。

HttpMessageConverter的調用是RequestResponseBodyMethodProcessor類的解析請求參數的方法resolveArgument()和處理傳回值的方法handleReturnValue()中進行調用的。這是關于@RequestBody和@ResponseBody兩個注解的原理。

Spring Mvc:HttpMessageConverter 消息轉換器

消息轉換器接口

public interface HttpMessageConverter<T> {

	boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

	boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);

	List<MediaType> getSupportedMediaTypes();

	default List<MediaType> getSupportedMediaTypes(Class<?> clazz) {
		return (canRead(clazz, null) || canWrite(clazz, null) ?
				getSupportedMediaTypes() : Collections.emptyList());
	}

	T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
			throws IOException, HttpMessageNotReadableException;


	void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException;

}           

轉換器加載流程

消息轉換器是在項目啟動的時候通過WebMvcConfigurationSupport進行加載,當getMessageConverters()被調用的時候會通過configureMessageConverters()、addDefaultHttpMessageConverters()和extendMessageConverters()三個方法進行初始話消息轉換器。生成的消息轉換器放在List<HttpMessageConverter<?>> messageConverters集合中

protected final List<HttpMessageConverter<?>> getMessageConverters() {
        if (this.messageConverters == null) {
            this.messageConverters = new ArrayList();
            // 加載委托給WebMvcConfigurer類型的Bean
            this.configureMessageConverters(this.messageConverters);
            if (this.messageConverters.isEmpty()) {
                // 加載預設的轉換器
                this.addDefaultHttpMessageConverters(this.messageConverters);
            }
            // 加載擴充消息轉換器
            this.extendMessageConverters(this.messageConverters);
        }
        return this.messageConverters;
    }           

自定義消息轉換器

  1. FastJson 、Gson 等元件自帶常用json消息轉換器
  2. 實作HttpMessageConverter 接口
  3. 繼承 AbstractHttpMessageConverter 類

加載自定義消息轉換器

  1. 直接注入Bean 的方式替換
  2. 實作 WebMvcConfigurer#extendMessageConverters 接口方法
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {

    /**
     * 直接注入 HttpMessageConverters
     */
    @Bean
    public HttpMessageConverters customConverters() {
        return new HttpMessageConverters(configFastJsonHttpMessageConverter());
    }

    /**
     * 實作 WebMvcConfigurer#extendMessageConverters 接口
     */
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 注意加載順序
        converters.add(0, configFastJsonHttpMessageConverter());
    }

    /**
     * 配置JSON 消息轉換器
     */
    private HttpMessageConverter<Object> configFastJsonHttpMessageConverter() {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        // 配置轉換特性
        fastJsonConfig.setSerializerFeatures(
            SerializerFeature.DisableCircularReferenceDetect,
            SerializerFeature.WriteNonStringKeyAsString,
            SerializerFeature.WriteMapNullValue
        );
        converter.setFastJsonConfig(fastJsonConfig);
        // 設定處理消息類型
        converter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON));
        return converter;
    }
}