SpringMvc之HttpMessageConverter

HTTP請求和響應是基於文本的,意味着瀏覽器和服務器通過交換原始文本進行通信。但是使用 Spring的controller 類中的方法,返回純 String類型和域模型(或其他 Java 內建對象)。如何將對象序列化/反序列化爲原始文本?這由HttpMessageConverter 處理。

Http請求和響應報文本質上都是一串字符串,當請求報文來到java世界,它會被封裝成爲一個ServletInputStream的輸入流,供我們讀取報文。響應報文則是通過一個ServletOutputStream的輸出流,來輸出響應報文。

我們從流中,只能讀取到原始的字符串報文,同樣,我們往輸出流中,也只能寫原始的字符。而在java世界中,處理業務邏輯,都是以一個個有業務意義的對象爲處理維度的,那麼在報文到達SpringMVC和從SpringMVC出去,都存在一個字符串到java對象的轉換的問題。這一過程,不可能由開發者手工轉換。我們知道,在Struts2中,採用了OGNL來應對這個問題,在SpringMVC中,可以使用@RequestBody和@ResponseBody兩個註解,分別完成請求報文到對象和對象到響應報文的轉換,底層這種靈活的消息轉換機制,就是Spring3.x中新引入的HttpMessageConverter即消息轉換器機制。我們先來看兩個接口。對消息轉換器最高層次的接口抽象,描述了一個消息轉換器的一般特徵,我們可以從這個接口中定義的方法,來領悟Spring3.x的設計者對這一機制的思考過程。

public interface HttpMessageConverter<T> {
 
    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;
 
}

HttpMessageConverter接口的定義出現了成對的canRead(),read()和canWrite(),write()方法,MediaType是對請求的MediaType屬性的封裝。舉個例子,當我們聲明瞭下面這個處理方法。 

@RequestMapping(value="/string", method=RequestMethod.POST)
public @ResponseBody String readString(@RequestBody String string) {
    return "Read string '" + string + "'";
}

在SpringMVC進入readString方法前,會根據@RequestBody註解選擇適當的HttpMessageConverter實現類來將請求參數解析到string變量中,具體來說是使用了StringHttpMessageConverter類,它的canRead()方法返回true,然後它的read()方法會從請求中讀出請求參數,綁定到readString()方法的string變量中。當SpringMVC執行readString方法後,由於返回值標識了@ResponseBody,SpringMVC將使用StringHttpMessageConverter的write()方法,將結果作爲String值寫入響應報文,當然,此時canWrite()方法返回true。我們可以用下面的圖,簡單描述一下這個過程。

在我們對SpringMVC源碼分析的過程中,我們可以從HttpMessageConverter機制中領悟到類似的道理。在SpringMVC的設計者眼中,一次請求報文和一次響應報文,分別被抽象爲一個請求消息HttpInputMessage和一個響應消息HttpOutputMessage。

處理請求時,由合適的消息轉換器將請求報文綁定爲方法中的形參對象,在這裏,同一個對象就有可能出現多種不同的消息形式,比如json和xml。同樣,當響應請求時,方法的返回值也同樣可能被返回爲不同的消息形式,比如json和xml。

在SpringMVC中,針對不同的消息形式,我們有不同的HttpMessageConverter實現類來處理各種消息形式。但是,只要這些消息所蘊含的“有效信息”是一致的,那麼各種不同的消息轉換器,都會生成同樣的轉換結果。至於各種消息間解析細節的不同,就被屏蔽在不同的HttpMessageConverter實現類中了。

SpringMVC 啓動時會自動配置一些默認的HttpMessageConverter,在 WebMvcConfigurationSupport 類中添加了缺省 MessageConverter:

加入 jackson jar包後,啓動的時候加載 7個 HttpMessageConverter 的實現類,如下所示:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章