Spring 3 中的 REST:RestTemplate

工程 | Arjen Poutsma | 2009 年 3 月 27 日 | ...

在之前的一篇文章中,我寫了關於我們在 Spring @MVC 3.0 版本中新增的 REST 功能。後來,Alef 寫了一篇文章,介紹瞭如何使用這些功能為 Pet Clinic 應用程式新增 Atom 檢視。在這篇文章中,我想介紹一下我們在 Milestone 2 中新增的客戶端功能。

RestTemplate

RestTemplate 是 Spring 中用於客戶端 HTTP 訪問的核心類。從概念上講,它與 JdbcTemplateJmsTemplate 以及 Spring Framework 和其他組合專案中的各種其他模板非常相似。這意味著,例如,RestTemplate 在構建後是執行緒安全的,並且您可以使用回撥來定製其操作。

RestTemplate 方法

該模板的主要入口點以六個主要的 HTTP 方法命名

HTTPRestTemplate
DELETEdelete(String, String...)
GETgetForObject(String, Class, String...)
HEADheadForHeaders(String, String...)
OPTIONSoptionsForAllow(String, String...)
POSTpostForLocation(String, Object, String...)
PUTput(String, Object, String...)

這些方法的名稱清楚地表明它們呼叫了哪個 HTTP 方法,而名稱的第二部分則表明了返回值。例如,getForObject()將執行 GET 請求,將 HTTP 響應轉換為您選擇的物件型別,並返回該物件。postForLocation將執行 POST 請求,將給定物件轉換為 HTTP 請求,並返回響應中的 HTTP Location 頭,其中可以找到新建立的物件。如您所見,這些方法試圖強制遵循 REST 最佳實踐。

URI 模板

這些方法都將 URI 作為第一個引數。該 URI 可以是一個 URI 模板,並且可以使用變數將模板擴充套件為普通 URI。模板變數可以透過兩種形式傳遞:作為 String 變數引數陣列,或作為 Map<String, String>。String varargs 變體按順序擴充套件給定的模板變數,因此


String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21");

將對以下 URI 執行 GET 請求:http://example.com/hotels/42/bookings/21。Map 變體根據變數名擴充套件模板,因此在使用許多變數或單個變數被多次使用時更有用。例如


Map<String, String> vars = new HashMap<String, String>();
vars.put("hotel", "42");
vars.put("booking", "21");
String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class, vars);

也將對以下 URI 執行 GET 請求:http://example.com/hotels/42/rooms/42.

HttpMessageConverters

傳遞給方法和從方法返回的物件getForObject(), postForLocation(),以及put()HttpMessageConverters 轉換為 HTTP 請求並從 HTTP 響應中轉換。主要 mime 型別和 Java 型別的轉換器預設註冊,但您也可以編寫自己的轉換器並將其插入 RestTemplate。在下面的示例中,我將向您展示如何做到這一點。

使用 RestTemplate 從 Flickr 獲取照片

與其逐一介紹 RestTemplate 的各種方法,不如向您展示如何使用它從雅虎的線上照片共享應用程式 Flickr 中檢索圖片。這個示例應用程式會在 Flickr 中搜索與給定搜尋詞匹配的照片,然後使用一個簡單的 Swing UI 顯示這些圖片。要自己執行該應用程式,您需要建立一個 Flickr 帳戶並申請一個 API 金鑰

搜尋照片

Flickr 提供了各種 API 來操作其龐大的照片庫。flickr.photos.search 方法允許您透過向以下地址發出 GET 請求來搜尋照片:http://www.flickr.com/services/rest?method=flickr.photos.search&api+key=xxx&tags=penguins,其中輸入您的 API 金鑰和要搜尋的內容(本例中為企鵝)。結果是返回一個 XML 文件,描述符合您查詢條件的照片。例如:

<photos page="2" pages="89" perpage="10" total="881">
	<photo id="2636" owner="47058503995@N01" 
		secret="a123456" server="2" title="test_04"
		ispublic="1" isfriend="0" isfamily="0" />
	<photo id="2635" owner="47058503995@N01"
		secret="b123456" server="2" title="test_03"
		ispublic="0" isfriend="1" isfamily="1" />
	<photo id="2633" owner="47058503995@N01"
		secret="c123456" server="2" title="test_01"
		ispublic="1" isfriend="0" isfamily="0" />
	<photo id="2610" owner="12037949754@N01"
		secret="d123456" server="2" title="00_tall"
		ispublic="1" isfriend="0" isfamily="0" />
</photos>

使用 RestTemplate,獲取這樣的文件非常簡單:


final String photoSearchUrl =
   "http://www.flickr.com/services/rest?method=flickr.photos.search&api+key={api-key}&tags={tag}&per_page=10";
Source photos = restTemplate.getForObject(photoSearchUrl, Source.class, apiKey, searchTerm);

其中apiKeysearchTerm是命令列上給定的兩個字串。此方法使用SourceHttpMessageConverter將 HTTP XML 響應轉換為javax.xml.transform.Source(請注意,SourceHttpMessageConverter 是我們在釋出 Spring 3.0 M2 後不久引入的,因此您需要獲取最新的快照版本(或即將釋出的 M3)才能使用它。下面提供的示例專案已配置為透過 Maven 獲取這些依賴項)。

獲取照片

接下來,我們將使用 XPath 表示式來獲取所有photo元素。為此,我們將使用 Spring Web Services 中的 XPathTemplate。我們將執行//photo表示式,返回文件中出現的每個photo元素。NodeMapper 是一個回撥介面,其mapNode()方法將為文件中的每個photo元素呼叫。在本例中,我們獲取了該元素的server, id,以及secret屬性,並用它們填充一個 Map。最後,我們再次使用 RestTemplate,將照片作為java.awt.image.BufferedImage獲取。因此,當 XPath 評估完成後,結果imageList將包含 XML 文件中每張照片對應的圖片。

List<BufferedImage> imageList = xpathTemplate.evaluate("//photo", photos, new NodeMapper() {
    public Object mapNode(Node node, int i) throws DOMException {
        Element photo = (Element) node;

        Map<String, String> variables = new HashMap<String, String>(3);
        variables.put("server", photo.getAttribute("server"));
        variables.put("id", photo.getAttribute("id"));
        variables.put("secret", photo.getAttribute("secret"));

        String photoUrl = "http://static.flickr.com/{server}/{id}_{secret}_m.jpg";
        return restTemplate.getForObject(photoUrl, BufferedImage.class, variables);
    }
});

例如,給定上面提供的 XML 文件,imageList將包含 4 張圖片。獲取的第一張圖片的 URL 將是http://static.flickr.com/2/2636_ a123456_m.jpg,第二張是http://static.flickr.com/2/2635_ b123456_m.jpg,等等。

轉換圖片

為了讓程式碼工作,還需要做一件事:我們需要編寫一個HttpMessageConverter,它能夠從 HTTP 響應中讀取並建立一個BufferedImage。使用 Java Image I/O API 實現這一點非常簡單,我們只需要實現read()方法,該方法定義在HttpMessageConverter介面中。總的來說,我們簡單的轉換器看起來像這樣:

public class BufferedImageHttpMessageConverter implements HttpMessageConverter<BufferedImage> {

    public List<MediaType> getSupportedMediaTypes() {
        return Collections.singletonList(new MediaType("image", "jpeg"));
    }

    public boolean supports(Class<? extends BufferedImage> clazz) {
        return BufferedImage.class.equals(clazz);
    }

    public BufferedImage read(Class<BufferedImage> clazz, HttpInputMessage inputMessage) throws IOException {
        return ImageIO.read(inputMessage.getBody());
    }

    public void write(BufferedImage image, HttpOutputMessage message) throws IOException {
        throw new UnsupportedOperationException("Not implemented");
    }

}

請注意,我們沒有實現write()因為我們不是上傳圖片,只是下載它們。現在我們只需將這個轉換器插入 RestTemplate。我們在 Spring 應用程式上下文中這樣做:


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="flickrClient" class="com.springsource.samples.resttemplate.FlickrClient">
        <constructor-arg ref="restTemplate"/>
        <constructor-arg ref="xpathTemplate"/>
    </bean>

    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
                <bean class="com.springsource.samples.resttemplate.BufferedImageHttpMessageConverter"/>
            </list>
        </property>
    </bean>

    <bean id="xpathTemplate" class="org.springframework.xml.xpath.Jaxp13XPathTemplate"/>

</beans>

顯示照片

最後一步是在一個簡單的 GUI 中顯示照片。為此,我們使用 Swing:

JFrame frame = new JFrame(searchTerm + " photos");
frame.setLayout(new GridLayout(2, imageList.size() / 2));
for (BufferedImage image : imageList) {
    frame.add(new JLabel(new ImageIcon(image)));
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);

結果如下:

Penguins

總的來說,我希望這篇文章向您展示了使用 RestTemplate 與 HTTP 伺服器互動是多麼簡單。只需不到 30 行 Java 程式碼,我們就建立了一個 GUI,可以顯示每個人最喜歡的鳥類的照片:企鵝!檢視 RestTemplate 並告訴我們您的想法!

下載

包含上述程式碼的 Maven 專案可以在此處下載。請注意,該專案基於 Spring 的每晚快照構建。即將釋出的 Spring Milestone 3 也將包含必要的類。

獲取 Spring 新聞通訊

訂閱 Spring 新聞通訊,保持聯絡

訂閱

搶佔先機

VMware 提供培訓和認證,助您快速進步。

瞭解更多

獲取支援

Tanzu Spring 透過一個簡單的訂閱,為 OpenJDK™、Spring 和 Apache Tomcat® 提供支援和二進位制檔案。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視全部