Spring 3 的 REST:RestTemplate

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

在先前的文章中,我撰寫了關於我們在 Spring @MVC 3.0 版本中新增的 REST 功能。 稍後,Alef 撰寫了關於使用導入的功能將 Atom 視圖添加到 Pet Clinic 應用程式。 在這篇文章中,我想介紹我們在 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>。 字串 varargs 變體按順序擴展給定的範本變數,因此


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

將對執行 GEThttp://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);

也將對執行 GEThttp://example.com/hotels/42/rooms/42.

HttpMessageConverters

傳遞到方法和從方法返回的物件getForObject(), postForLocation(),以及put()並由 HttpMessageConverters 轉換為 HTTP 請求和從 HTTP 回應轉換而來。 預設情況下註冊了主要 mime 類型和 Java 類型的轉換器,但您也可以編寫自己的轉換器並將其插入 RestTemplate 中。 在下面的範例中,我將向您展示如何完成此操作。

使用 RestTemplate 從 Flickr 檢索照片

我將向您展示如何使用 RestTemplate 從 Flickr(Yahoo! 的線上照片分享應用程式)檢索圖片,而不是瀏覽 RestTemplate 的各種方法。 這個範例應用程式在 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 社群中所有即將到來的活動。

檢視全部