使用Spring MVC建立 REST API--2

1.提供資源以外的其餘內容

@ResponseBody提供了一種頗有用的方式,可以將控制器返回的Java對象轉換爲發送到客戶端的資源表述。實際上,將資源表述發送給客戶端只是整個過程的一部分。一個好的REST API不只可以在客戶端和服務器之間傳遞資源,它還可以給客戶端提供額外的元數據,幫助客戶端理解資源或者在請求中出現了什麼狀況。java

 

發送錯誤信息到客戶端瀏覽器

 

若是根據給定的ID,沒法找到某個Spittle對象的ID屬性可以與之匹配,findOne()方法返回null的時候,你以爲會發生什麼呢?結果就是spittleById()方法會返回null,響應體爲空,不會返回任何有用的數據給客戶端。同時,響應中默認的HTTP狀態碼是200(OK),表示全部的事情運行正常服務器

 

Spring提供了多種方式來處理這樣的場景:架構

  1. 使用@ResponseStatus註解能夠指定狀態碼;
  2. 控制器方法能夠返回ResponseEntity對象,該對象可以包含更多響應相關的元數據;
  3. 異常處理器可以應對錯誤場景,這樣處理器方法就能關注於正常的情況。

 

 

 

使用ResponseEntity性能

做爲@ResponseBody的替代方案,控制器方法能夠返回一個ResponseEntity對象。ResponseEntity中能夠包含響應相關的元數據(如頭部信息和狀態碼)以及要轉換成資源表述的對象。由於ResponseEntity容許咱們指定響應的狀態碼,因此當沒法找到Spittle的時候,咱們能夠返回HTTP 404錯誤。以下是新版本的spittleById(),它會返回ResponseEntity:fetch

 

 

 咱們重構一下代碼來使用錯誤處理器。首先,定義可以對應SpittleNotFound-Exception的錯誤處理器ui

 

 

@ExceptionHandler註解可以用到控制器方法中,用來處理特定的異常。這裏,它代表若是在控制器的任意處理方法中拋出SpittleNotFoundException異常,就會調用spittleNotFound()方法來處理異常。至於SpittleNotFoundException,它是一個很簡單異常類:spa

 

 

 

 在響應中設置頭部信息.net

 

在saveSpittle()處理完請求以後,服務器在響應體中包含了Spittle的表述以及HTTP狀態碼200(OK),將其返回給客戶端。這裏沒有什麼大問題,可是還不是徹底準確。固然,假設處理請求的過程當中成功建立了資源,狀態能夠視爲OK。可是,咱們不只僅須要說「OK」。咱們建立了新的內容,HTTP狀態碼也將這種狀況告訴給了客戶端。不過,HTTP 201不只可以代表請求成功完成,並且還能描述建立了新資源。若是咱們但願完整準確地與客戶端交流,那麼響應是否是應該爲201(Created),而不只僅是200(OK)呢?根據咱們目前所學到的知識,這個問題解決起來很容易。咱們須要作的就是爲saveSpittle()方法添加@ResponseStatus註解,以下所示:設計

 

但這只是問題的一部分。客戶端知道新建立了資源,你以爲客戶端會不會感興趣新建立的資源在哪裏呢?畢竟,這是一個新建立的資源,會有一個新的URL與之關聯。難道客戶端只能猜想新建立資源的URL是什麼嗎?咱們能不能以某種方式將其告訴客戶端?當建立新資源的時候,將資源的URL放在響應的Location頭部信息中,並返回給客戶端是一種很好的方式。所以,咱們須要有一種方式來填充響應頭部信息,此時咱們的老朋友ResponseEntity就能提供幫助了。以下的程序清單展示了一個新版本的saveSpittle(),它會返回ResponseEntity用來告訴客戶端新建立的資源

 

 

咱們其實沒有必要手動構建URL,Spring提供了UriComponentsBuilder,能夠給咱們一些幫助。它是一個構建類,經過逐步指定URL中的各類組成部分(如host、端口、路徑以及查詢),咱們可以使用它來構建UriComponents實例。藉助UriComponentsBuilder所構建的UriComponents對象,咱們就能得到適合設置給Location頭部信息的URI。爲了使用UriComponentsBuilder,咱們須要作的就是在處理器方法中將其做爲一個參數,以下面的程序清單所示。

 

2.編寫REST客戶端

 

瞭解RestTemplate的操做

RestTemplate定義了36個與REST資源交互的方法,其中的大多數都對應於HTTP的方法。可是,在本章中我沒有足夠的篇幅涵蓋全部的36個方法。其實,這裏面只有11個獨立的方法,其中有十個有三種重載形式,而第十一個則重載了六次,這樣一共造成了36個方法。表16.2描述了RestTemplate所提供的11個獨立方法。除了TRACE之外,RestTemplate涵蓋了全部的HTTP動做。除此以外,execute()和exchange()提供了較低層次的通用方法來使用任意的HTTP方法

 

表16.2中的大多數操做都以三種方法的形式進行了重載:

  1. 一個使用java.net.URI做爲URL格式,不支持參數化URL;
  2. 一個使用String做爲URL格式,並使用Map指明URL參數;
  3. 一個使用String做爲URL格式,並使用可變參數列表指明URL參數。

 

明確了RestTemplate所提供的11個操做以及各個變種如何工做之後,你就能以本身的方式編寫使用REST資源的客戶端了。咱們經過對四個主要HTTP方法的支持(也就是GET、PUT、DELETE和POST)來研究RestTemplate的操做。咱們從GET方法的getForObject()和getForEntity()開始

 

 GET資源

你可能意識到在表16.2中列出了兩種執行GET請求的方法:getForObject()和getForEntity()。正如以前所描述的,每一個方法又有三種形式的重載

 

除了返回類型,getForEntity()方法就是getForObject()方法的鏡像。實際上,它們的工做方式大同小異。它們都執行根據URL檢索資源的GET請求。它們都將資源根據responseType參數匹配爲必定的類型。惟一的區別在於getForObject()只返回所請求類型的對象,而getForEntity()方法會返回請求的對象以及響應相關的額外信息。讓咱們首先看一下稍微簡單的getForObject()方法。而後再看看如何使用getForEntity()方法來從GET響應中獲取更多的信息

 

檢索資源

getForObject()方法是檢索資源的合適選擇。咱們請求一個資源並按照所選擇的Java類型接收該資源。做爲getForObject()可以作什麼的一個簡單示例,讓咱們看一

下fetchFacebookProfile()的另外一個實現:

 

咱們沒有使用字符串鏈接來構建URL,而是利用了RestTemplate能夠接受參數化URL這一功能。URL中的{id}佔位符最終將會用方法的id參數來填充。getForObject()方法的最後一個參數是大小可變的參數列表,每一個參數都會按出現順序插入到指定URL的佔位符中。另一種替代方案是將id參數放到Map中,並以id做爲key,而後將這個Map做爲最後一個參數傳遞給getForObject():

 

 

這裏沒有任何形式的JSON解析和對象映射。在表面之下,getForObject()爲咱們將響應體轉換爲對象。它實現這些須要依賴表16.1中所列的HTTP消息轉換器,與帶有@ResponseBody註解的Spring MVC處理方法所使用的同樣。這個方法也沒有任何異常處理。這不是由於getForObject()不能拋出異常,而是由於它拋出的異常都是非檢查型的。若是在getForObject()中有錯誤,將拋出非檢查型RestClientException異常(或者它的一些子類)。若是願意的話,你能夠捕獲它——但編譯器不會強制你捕獲它

 

 

相似的方法

 

 

RESTful架構使用Web標準來集成應用程序,使得交互變得簡單天然。系統中的資源採用URL進行標識,使用HTTP方法進行管理而且會以一種或多種適合客戶端的方式來進行表述。在本章中,咱們看到了如何編寫響應RESTful資源管理請求的SpringMVC控制器。藉助參數化的URL模式並將控制器處理方法與特定的HTTP方法關聯,控制器可以響應對資源的GET、POST、PUT以及DELETE請求。爲了響應這些請求,Spring可以將資源背後的數據以最適合客戶端的形式展示。對於基於視圖的響應,ContentNegotiatingViewResolver可以在多個視圖解析器產生的視圖中選擇出最適合客戶端指望內容類型的那一個。或者,控制器的處理方法能夠藉助@ResponseBody註解徹底繞過視圖解析,並使用信息轉換器將返回值轉換爲客戶端的響應。REST API爲客戶端暴露了應用的功能,它們暴露功能的方式恐怕最原始的API設計者作夢都想不到。REST API的客戶端一般是移動應用或運行在Web瀏覽器中的JavaScript。可是,Spring應用也能夠藉助RestTemplate來使用這些API。

相關文章
相關標籤/搜索