原帖地址:http://www.infoq.com/cn/articles/restlet-for-restful-service

用Restlet創(chuàng)建面向資源的服務(wù)

作者 徐涵 發(fā)布于 2008年5月30日 上午9時5分

社區(qū)Java 主題Web服務(wù),Web框架,REST 標(biāo)簽Restlet

Restlet項目(http://www.restlet.org) 為“建立REST概念與Java類之間的映射”提供了一個輕量級而全面的框架。它可用于實現(xiàn)任何種類的REST式系統(tǒng),而不僅僅是REST式Web服務(wù); 而且,事實證明它自從2005年誕生之時起,就是一個可靠的軟件。

Restlet項目受到Servlet API、JSP(Java Server Pages)、HttpURLConnection及Struts等Web開發(fā)技術(shù)的影響。該項目的主要目標(biāo)是:在提供同等功能的同時,盡量遵守Roy Fielding博士論文中所闡述的REST的目標(biāo)。它的另一個主要目標(biāo)是:提出一個既適于客戶端應(yīng)用又適于服務(wù)端的應(yīng)用的、統(tǒng)一的Web視圖。

Restlet的思想是:HTTP客戶端與HTTP服務(wù)器之間的差別,對架構(gòu)來說無所謂。一個軟件應(yīng)可以既充當(dāng)Web客戶端又充當(dāng)Web服務(wù)器,而 無須采用兩套完全不同的APIs。

Restlet包括Restlet API和Noelios Restlet Engine(NRE)兩部分,NRE是對Restlet API的一種參考實現(xiàn)。這種劃分,使得不同實現(xiàn)可以具有同樣的API。NRE包括若干HTTP服務(wù)器連接器(HTTP server connector),它們都是基于Mortbay的Jetty、Codehaus的AsyncWeb,以及Simple框架這些流行的HTTP Java開源項目的。它甚至提供一個適配器(adapter),使你可以在標(biāo)準(zhǔn)Servlet容器(如Apache Tomcat)內(nèi)部署一個Restlet應(yīng)用。

Restlet還提供兩個HTTP客戶端連接器(HTTP client connector)。它們一個是基于官方的HttpURLConnection類,一個是基于Apache的HTTP客戶端庫。還有一個連接器允許你容 易地按REST風(fēng)格通過XML文檔來處理JDBC源(source);此外,一個基于JavaMail API的SMTP連接器允許你發(fā)送內(nèi)容為XML的Email。

Restlet API包括一些能夠創(chuàng)建基于字符串、文件、流(stream)、通道(channel)及XML文檔的表示(representation),它支持 SAX、DOM及XSLT。使用FreeMaker或Apache Velocity模板引擎,你可以很容易地創(chuàng)建基于JSP式模板的表示(representations)。你甚至可以像普通Web服務(wù)器那樣,用一個支 持內(nèi)容協(xié)商(content negotiation)的Directory類來返回靜態(tài)文件與目錄。

簡單性(simplicity)和靈活性(flexibility)是貫穿整個框架的設(shè)計原則。Restlet API旨在把HTTP、URI及REST的概念抽象成一系列類(classes),同時又不把低層信息(如原始HTTP報頭)完全隱藏起來。

基本概念

Restlet在術(shù)語上參照了Roy Fielding博士論文在講解REST時采用的術(shù)語,如:資源(resource)、表示(representation)、連接器 (connector)、組件(component)、媒體類型(media type)、語言(language),等等。這些術(shù)語你應(yīng)該不會陌生。Restlet增加了一些專門的類(如Application、Filter、 Finder、Router和Route),用以簡化restlets的彼此結(jié)合,以及簡化把收到的請求(incoming requests)映射為處理它們的資源。

圖12-1:Restlet的類層次結(jié)構(gòu)

抽象類Uniform及其具體子類Restlet,是Restlet的核心概念。正如其名稱所暗示的,Uniform暴露一個符合REST規(guī)定的統(tǒng) 一接口(uniform interface)。雖然該接口是按HTTP統(tǒng)一接口定義的,但它也可用于其他協(xié)議(如FTP和SMTP)。

handle是一個重要的方法,它接受兩個參數(shù):Request和Response。正如你可以從圖12-1中看到的,每個暴露于網(wǎng)上的調(diào)用處理者 (call handler)(無論作為客戶端還是服務(wù)端)都是Restlet的一個子類——也就是說,它是一個restlets——并遵守這個統(tǒng)一接口。由于有統(tǒng)一 接口,restlets可以非常復(fù)雜的方式組合在一起。

Restlet支持的每一個協(xié)議都是通過handle方法暴露的。這就是說,HTTP(服務(wù)器和客戶端)、HTTPS、SMTP,以及JDBC、文 件系統(tǒng),甚至類加載器(class loaders)都是通過調(diào)用handle方法來操作的。這減少了開發(fā)者需掌握的APIs的數(shù)量。

過濾、安全、數(shù)據(jù)轉(zhuǎn)換及路由是“通過把Restlet的子類鏈起來”進行處理的。Filters可以在處理下個restlet調(diào)用之前或之后進行處 理。Filters實例的工作方式與Rails過濾器差不多,只不過Filters實例跟其他Restlet類一樣響應(yīng)handle方法,而不是具有一個 專門的API。

一個Router restlet有許多附屬的Restlet對象,它把每個收到的協(xié)議調(diào)用(incoming protocol call)路由給適當(dāng)?shù)腞estlet處理器。路由(routing)通常是根據(jù)目標(biāo)URI進行的。跟Rails不同的是,Restlet沒有對資源層次 結(jié)構(gòu)(resource hierarchy)作URI規(guī)則限定,所以可以隨意設(shè)置想要的URI,只要對Routers作相應(yīng)編程就行了。

除了這一常見用途,Router還可用于其他用途。你可以用一個Router在多臺遠程機器之間以動態(tài)負載均衡的方式來轉(zhuǎn)發(fā)調(diào)用。即使在這種復(fù)雜的 情況下,它也一樣響應(yīng)Restlet的統(tǒng)一接口,并且可成為一個更大路由系統(tǒng)中的一個組件。VirtualHost類(Router的一個子類)使我們可 以在同一臺物理主機上運行多個具有不同域名的應(yīng)用。在過去,你要引入一個前端Web服務(wù)器(如Apache的httpd)才能實現(xiàn)此功能;而用 Restlet的話,它只是另一個響應(yīng)統(tǒng)一接口的Router實現(xiàn)。

一個Application對象能夠管理一組restlets,并提供常見的服務(wù),比方說對壓縮的請求進行透明解碼,或者利用method查詢參數(shù) 在重載的POST(overloaded POST)之上實現(xiàn)PUT和DELETE請求。最后,Component對象可以包含并編配(orchestrate)一組Connectors、 VirtualHosts及Applications(作為獨立Java應(yīng)用運行的,或者嵌入在一個更大系統(tǒng)(如J2EE環(huán)境)中的)。

在第6章,我向你介紹了“把一個問題劃分為一組響應(yīng)HTTP統(tǒng)一接口的資源”的步驟。在第7章,為了處理Ruby on Rails的簡單化假設(shè)(simplifying assumptions),我對該步驟作了相應(yīng)的調(diào)整。因為Restlet沒有做簡單化假設(shè)(simplifying assumptions),所以我們無須對此步驟進行修改。它可以實現(xiàn)任何REST式系統(tǒng)。如果你剛好想實現(xiàn)一個REST式面向資源的Web服務(wù),可以按 愿意的方式來組織和實現(xiàn)這些資源。Restlet確實提供了一些便于創(chuàng)建面向資源的應(yīng)用的類。其中特別值得一提的是Resource類,它可作為你所有應(yīng) 用資源的基礎(chǔ)。

我在本書中一直用URI模板作為一組URIs的簡化表達(見第9章)。Restlet用URI模板來進行URI與資源的映射。假如用Restlet 來實現(xiàn)第7章那個社會性書簽服務(wù)的話,它也許要指定一個代表特定書簽的URI:

/users/{username}/bookmarks/{URI}

你可以在把Resource子類附加到Router上時使用這種語法。假如你不相信真會這么好的話,可以等到下一節(jié),那時我會實際實現(xiàn)部分書簽服 務(wù)。

編寫Restlet客戶端

在示例2-1中,你看到的是一個從Yahoo!搜索服務(wù)獲取XML搜索結(jié)果的Ruby客戶端。示例12-3是一個用Java參照Restlet 1.0實現(xiàn)的具有同樣功能的客戶端。要確保把以下JAR包寫在你的classpath中,才能成功編譯并運行接下來的例子:

  • org.restlet.jar(Restlet API)
  • com.noelios.restlet.jar (Noelios Restlet Engine核心)
  • com.noelios.restlet.ext.net.jar (基于JDK的HttpURLConnection的HTTP客戶端連接器)

這些JAR包可以在Restlet發(fā)布包中的lib目錄里找到。要確保你的Java環(huán)境支持Java SE 5.0(或更高)版本。如果你確實需要的話,可以用Retrotranslator(http://retrotranslator. sourceforge.net/)輕易地把Restlet代碼反移植(backport)到J2SE 4.0版上去。

示例12-3:Yahoo!搜索服務(wù)的一個Restlet客戶端

// YahooSearch.java
import org.restlet.Client;
import org.restlet.data.Protocol;
import org.restlet.data.Reference;
import org.restlet.data.Response;
import org.restlet.resource.DomRepresentation;
import org.w3c.dom.Node;

/**
  * 用返回XML的Yahoo!搜索服務(wù)來搜索Web
 */
public class YahooSearch {
    static final String BASE_URI =
    "http://api.search.yahoo.com/WebSearchService/V1/webSearch";

    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.err.println("You need to pass a term to search");
        } else {
            // 獲取一個資源,即一個包含搜索結(jié)果的XML文檔
            String term = Reference.encode(args[0]);
            String uri = BASE_URI + "?appid=restbook&query=" + term;
            Response response = new Client(Protocol.HTTP).get(uri);
            DomRepresentation document = response.getEntityAsDom();

            // 用XPath找出數(shù)據(jù)結(jié)構(gòu)中重要部分
            String expr = "/ResultSet/Result/Title";
            for (Node node : document.getNodes(expr)) {
                  System.out.println(node.getTextContent());
            }
        }
    }
}

跟示例2-1一樣,你可以在執(zhí)行這個類時把一個搜索關(guān)鍵字作為命令行參數(shù)傳給它。比如像下面這樣:

$ java YahooSearch xslt
     XSL Transformations (XSLT)
     The Extensible Stylesheet Language Family (XSL)
     XSLT Tutorial
          ...

該示例證明了“用Restlet從Web服務(wù)獲取XML數(shù)據(jù),并用標(biāo)準(zhǔn)工具處理它”是極其簡單的事。Yahoo!資源的URI是用一個常量和用戶提 供的搜索關(guān)鍵字構(gòu)造而成的。客戶端連接器(client connector)是用HTTP協(xié)議來初始化的。XML文檔是通過get方法獲得的,該方法對應(yīng)于HTTP統(tǒng)一接口的GET方法。當(dāng)調(diào)用返回時,程序?qū)? 得到一個DOM表示。跟前面的Ruby例子一樣,XPath是對XML進行查詢的最簡單方式。

跟前面的Ruby例子一樣,這個程序也忽略了XML文檔里的XML名稱空間(namespaces)。Yahoo!為整個文檔采用名稱空間 urn:yahoo:srch,但我是直接引用標(biāo)簽的,比方說,我用ResultSet,而不是urn:yahoo:srch:ResultSet。前面 的Ruby例子忽略名稱空間,是因為Ruby的默認XML解析器不支持名稱空間。Java的XML解析器支持名稱空間,而且Restlet API令正確處理名稱空間變得更加容易。雖然對上面那個簡單例子來說,它們區(qū)別不大,但支持名稱空間可以避免一些因名稱空間而導(dǎo)致的微妙的問題。

當(dāng)然,若一直用urn:yahoo:srch:ResultSet,是比較煩人的。Restlet API可以容易地把一個簡短前綴跟一個名稱空間進行關(guān)聯(lián),然后就可以在XPath表達式中使用這個簡短前綴而不是整個名稱空間了。示例12-4對示例 12-3后半部分代碼作了改動,它使用了帶名稱空間的Xpath,這樣就不會把來自Yahoo!的ResultSet標(biāo)簽與來自其他名稱空間的標(biāo)簽搞混 了。

示例12-4:支持名稱空間的文檔處理代碼

            DomRepresentation document = response.getEntityAsDom();

            // 把該名稱空間與前綴‘y’關(guān)聯(lián)起來
            document.setNamespaceAware(true);
            document.putNamespace("y", "urn:yahoo:srch");

            // 用XPath找出數(shù)據(jù)結(jié)構(gòu)中重要部分
            String expr = "/y:ResultSet/y:Result/y:Title/text()";
            for (Node node : document.getNodes(expr)) {
                  System.out.println(node.getTextContent());
            }

示例2-15是Yahoo!搜索服務(wù)的另一個Ruby客戶端。它請求的是JSON格式(而不是XML格式)的搜索數(shù)據(jù)。示例12-5是一個與之功能 等價的Restlet客戶端。它通過Restlet里的另兩個JAR文件獲取JSON支持:

  • org.restlet.ext.json_2.0.jar(用于JSON的Restlet擴展)
  • org.json_2.0/org.json.jar(JSON官方程序庫)

示例12-5:Yahoo!的JSON搜索服務(wù)的一個Restlet客戶端

// YahooSearchJSON.java
import org.json.JSONArray;
import org.json.JSONObject;
import org.restlet.Client;
import org.restlet.data.Protocol;
import org.restlet.data.Reference;
import org.restlet.data.Response;
import org.restlet.ext.json.JsonRepresentation;

/**
  * 用返回JSON的Yahoo!搜索服務(wù)來搜索Web
 */
public class YahooSearchJSON {
    static final String BASE_URI =
    "http://api.search.yahoo.com/WebSearchService/V1/webSearch";

    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.err.println("You need to pass a term to search");
        } else {

            // 獲取一個資源,即一個包含搜索結(jié)果的JSON文檔
            String term = Reference.encode(args[0]);
            String uri = BASE_URI + "?appid=restbook&output=json&query=" + term;
            Response response = new Client(Protocol.HTTP).get(uri);
            JSONObject json = new JsonRepresentation(response.getEntity())
                     .toJsonObject();

            // 在JSON文檔中尋找并顯示標(biāo)題
            JSONObject resultSet = json.getJSONObject("ResultSet");
            JSONArray results = resultSet.getJSONArray("Result");
            for (int i = 0; i < results.length(); i++) {
                 System.out.println(results.getJSONObject(i).getString("Title"));
            }
        }
    }
}

當(dāng)你為Yahoo!的Web服務(wù)編寫客戶端時,可以選擇表示格式(representation format)。Restlet核心API支持XML,另外還可以通過擴展支持JSON。正如你所預(yù)料的那樣,這兩個例子的區(qū)別僅僅在于對響應(yīng)的處理上。 JsonRepresentation類可以把響應(yīng)實體主體(response entity-body)轉(zhuǎn)換成一個JSONObject實例(而Ruby的JSON庫是把JSON數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換成一個本地數(shù)據(jù)結(jié)構(gòu))。該數(shù)據(jù)結(jié)構(gòu)只能進 行人工遍歷,因為目前JSON中還沒有類似XPath的查詢語言。

編寫Restlet服務(wù)

接下來的例子會稍微復(fù)雜一些。我將向你展示如何設(shè)計并實現(xiàn)一個服務(wù)端應(yīng)用。在第7章,我用Ruby on Rails實現(xiàn)了一個書簽管理應(yīng)用,現(xiàn)在我用Restlet來重新實現(xiàn)其部分功能。為了簡單起見,該應(yīng)用只支持對用戶及其書簽進行安全的(safe)操 作。

Java包結(jié)構(gòu)是這樣的:

org restlet
 example
     book
   rest
    ch7
       -Application
       -ApplicationTest
       -Bookmark
       -BookmarkResource
       -BookmarksResource
       -User
       -UserResource

也就是說,Bookmark等類都在org.restlet.example.book.rest.ch7包里。

我不打算在此展示完整的代碼。如果需要,你可以去本書的官方網(wǎng)站(http://www.oreilly. com/catalog/9780596529260),那里提供了本書的所有示例程序代碼。你也可以在restlet.org(http: //www.restlet.org)上找到本例的完整代碼。如果你已經(jīng)下載了Restlet的話,那么也可以在src/org /restlet.example/org/restlet/example/book/rest目錄里找到本節(jié)的示例代碼。

我將從一些簡單的代碼開始。示例12-6是Application.main方法,它用來建立Web服務(wù)器,并開始處理請求。

示例 12-6:Application.main方法:建立Web服務(wù)器

public static void main(String... args) throws Exception {
    // 用HTTP服務(wù)器連接器創(chuàng)建一個組件
    Component comp = new Component();
    comp.getServers().add(Protocol.HTTP, 3000);

    // 把應(yīng)用附加到默認主機上,并啟動
    comp.getDefaultHost().attach("/v1", new Application());
    comp.start();
}

資源與URI設(shè)計

由于Restlet未對資源設(shè)計作特別的限制,所以你完全可以根據(jù)ROA的設(shè)計原則來進行資源類(resource classes)及URIs的設(shè)計。在第7章,我要圍繞“Rails的基于控制器的架構(gòu)”來進行設(shè)計;而這里,我不需要圍繞Restlet架構(gòu)來進行設(shè) 計。圖12-2 展示了URI是如何經(jīng)由Router映射到資源,再映射到下層restlet類的。

圖12-2:社會性書簽應(yīng)用的Restlet架構(gòu)

為了理解如何用Java代碼實現(xiàn)這些映射,我們來看一下Application類及它的createRoot 方法(見示例12-7)。它跟示例7-3所示的Rails routes.rb文件在功能上是等價的。

示例12-7:Application.createRoot方法:實現(xiàn)URI模板到restlet的映射

public Restlet createRoot() {
    Router router = new Router(getContext());

    // 為用戶資源增加路由
    router.attach("/users/{username}", UserResource.class);

    // 為用戶的書簽資源增加路由
    router.attach("/users/{username}/bookmarks", BookmarksResource.class);

    // 為書簽資源增加路由
    Route uriRoute = router.attach("/users/{username}/bookmarks/{URI}",
                                       BookmarkResource.class);
    uriRoute.getTemplate().getVariables()
      .put("URI", new Variable(Variable.TYPE_URI_ALL));
}

在我創(chuàng)建一個Application對象(比如像示例12-6中的那樣)時,這段代碼便會運行。它會在資源類UserResource與URI模板 “/users/(username)”之間建立起清晰而直觀的映射關(guān)系。Router先拿請求的目標(biāo)URI跟URI模板(URI templates)進行比較,然后把請求轉(zhuǎn)發(fā)給一個新建的相應(yīng)的資源類實例。模板變量的值被存放在請求的屬性地圖(attributes map)里(跟Rails例子中的params地圖類似),以便于在Resource代碼中使用。這既有效,又易于理解;當(dāng)你事隔很久再回顧代碼時,這很 有幫助。

請求處理和表示

假定一個客戶端向URI http://localhost:3000/v1/users/jerome發(fā)出GET請求。我有一個監(jiān)聽本地主機3000端口的Component對 象,和一個隸屬于 /v1 的Application對象。該Application有一個Router和一組Route對象,這些Route對象正等待著跟各個URI模板匹配的請 求。 URI路徑片段“/users/jerome”跟模板“/users/{username}”相匹配,而該模板的Route是與UserResource 類(大致等價于Rails UsersController類)相關(guān)聯(lián)的。

Restlet通過初始化一個新的UserResource對象,并調(diào)用它的handleGet方法來處理該請求。示例12-8是 UserResource類的構(gòu)造方法。

示例12-8:UserResource類的構(gòu)造方法

/**
 * 構(gòu)造方法
 *
 * @param context
 *           上級上下文
 * @param request
 *           要處理的請求
 * @param response
 *           要返回的響應(yīng)
 */
 public UserResource(Context context, Request request, Response response) {
    super(context, request, response);
    this.userName = (String) request.getAttributes().get("username");
    ChallengeResponse cr = request.getChallengeResponse();
    this.login = (cr != null) ? cr.getIdentifier() : null;
    this.password = (cr != null) ? cr.getSecret() : null;
    this.user = findUser();

    if (user != null) {
        getVariants().add(new Variant(MediaType.TEXT_PLAIN));
    }
}

至此,這個架構(gòu)已經(jīng)建立了一個Request對象,它包含了我所需要的關(guān)于請求的所有信息。username屬性來自URI,認證證書來自請求的 Authorization報頭。我還調(diào)用findUser方法來根據(jù)認證證書在數(shù)據(jù)庫中查找用戶(為節(jié)省篇幅,我就不在此展示findUser方法的代 碼了)。這些工作在第7章都是由Rails過濾器完成的。

在框架把一個UserResource實例化后,它會對資源對象調(diào)用適當(dāng)?shù)膆andle方法。HTTP統(tǒng)一接口中的每一個方法,都有一個對應(yīng) handle方法。 在這個例子中,Restlet架構(gòu)最后的任務(wù)是調(diào)用UserResource.handleGet。

由于我沒有定義UserResource.handleGet這個方法,所以它將具有繼承Resource. handleGet方法的行為。HandleGet的默認行為是找到最符合客戶端要求的資源的表示。客戶端通過內(nèi)容協(xié)商(content- negotiation)來表達它的要求。Restlet通過Accept報頭的值來決定返回哪個表示。由于這里只有一個表示格式,所以客戶端的要求不起 作用。這是由getVariants和getRepresentation方法處理的。由于在上述構(gòu)造方法中把text/ plain定義為唯一支持的表示格式,所以我的getRepresentation方法的實現(xiàn)是很簡單的(見示例12-9)。

示例12-9:UserResoure.getRepresentation:構(gòu)造一個用戶的表示

@Override
public Representation getRepresentation(Variant variant) {
    Representation result = null;

    if (variant.getMediaType().equals(MediaType.TEXT_PLAIN)) {
        // 創(chuàng)建一個文本表示
        StingBuilder sb=new StringBuilder();
        sb.append("------------"n");
        sb.append("User details"n");
        sb.append("------------"n"n");
        sb.append("Name:  ").append(this.user.getFullName()).append('"n');
        sb.append("Email: ").append(this.user.getEmail()).append('"n');
        result = new StringRepresentation(sb);
    }

    return result;
}

雖然這只是一個資源的一個方法,但其他資源,以及UserResource的其他HTTP方法的工作原理都差不多,比如:對用戶的PUT請求將被路 由給UserResource.handlePut,等等。正如我前面所提到的,這里的代碼只是社會性書簽應(yīng)用所有代碼的一部分;所以,如果你有興趣進一 步學(xué)習(xí)的話,可以去下載一個完整的示例代碼來閱讀。

現(xiàn)在,你應(yīng)該了解Restlet架構(gòu)是如何把收到的(incoming)HTTP請求路由給特定的Resource類,然后再路由給該類的特定方法 了。你也應(yīng)該知道如何由資源狀態(tài)來構(gòu)造表示(representations)了。一般,只要關(guān)注Application和Router代碼一次就行,因 為一個Router可用于你的所有資源。

編譯、運行與測試

Application類實現(xiàn)了運行社會性書簽服務(wù)的HTTP服務(wù)器。你需要在classpath中加入以下JAR文件:

  • org.restlet.jar
  • com.noelios.restlet.jar
  • com.noelios.restlet.ext.net.jar
  • org.simpleframework_3.1/org.simpleframework.jar
  • com.noelios.restlet.ext.simple_3.1.jar
  • com.db4o_6.1/com.db4o.jar

這些JAR包可以在Restlet發(fā)布包中的lib目錄里找到。有兩點需要注意:第一,Web服務(wù)器的實際工作是由一個非常緊湊的、基于 Simple框架的HTTP服務(wù)器連接器來處理的;第二,我們是用強大的db4o對象數(shù)據(jù)庫(而不是關(guān)系數(shù)據(jù)庫)來存儲領(lǐng)域?qū)ο螅ㄓ脩艉蜁灒┑摹T诰幾g 好所有示例文件后,運行org.restlet.example.book.rest.ch7. Application,它將作為服務(wù)器的端點(endpoint)。

ApplicationTest類為服務(wù)提供了一個客戶端接口。它采用上節(jié)描述的Restlet客戶端類來添加和刪除用戶和書簽。它是通過HTTP 統(tǒng)一接口進行工作的:用PUT請求創(chuàng)建用戶和書簽,用DELETE請求刪除用戶和書簽。

在命令行下運行ApplicationTest類,你將得到以下消息:

   Usage  depends  on  the  number  of  arguments:
-  Deletes  a  user                  :  userName,  password
-  Deletes  a  bookmark         :  userName,  password,  URI
-  Adds  a  new  user             :  userName,  password,  "full  name",  email
-  Adds  a  new  bookmark   :  userName,  password,  URI,  shortDescription,
                                                 longDescription,  restrict[true  /  false]

你可以用這個程序來添加一些用戶,并增加一些書簽。然后,你就可以在Web瀏覽器中通過訪問適當(dāng)?shù)腢RI(如 http://localhost:3000/v1/users/jerome等)來瀏覽用戶書簽的HTML表示了。

小結(jié)

Restlet項目在2007年初發(fā)布了1.0正式版。它只用了12個多月的開發(fā)時間。目前,該項目具有一個繁榮的開發(fā)與用戶群體。Restlet 郵件列表很友好,不論是新手,還是有經(jīng)驗的開發(fā)者,它都歡迎。作為該項目的創(chuàng)建者,Noelios咨詢公司是主要的開發(fā)力量,他們也提供專業(yè)的支持計劃與 培訓(xùn)。

在本書編寫之時,1.0版處于維護中,新的1.1版已經(jīng)開始開發(fā)了。該項目計劃將來把Restlet API提交給JCP(Java Community Process)。還有一個用于REST式Web服務(wù)的高層API,它已由Sun公司提交給JCP(JSR311)。這個高層API使得“把Java領(lǐng)域 對象暴露為REST式資源”更加容易。這將是對Restlet API(尤其是其Resource類)的一個很好的補充。Noelios咨詢公司是最初的專家組成員,他們將根據(jù)標(biāo)準(zhǔn)的進展來對Restlet引擎作相應(yīng) 的更新。


本文節(jié)選自博文視點出版公司即將推出的經(jīng)典著作《RESTful Web Services中文版》中的第12章《REST式服務(wù)框 架》。

《RESTful Web Services中文版》向讀者介紹了什么是REST、什么是面向資源的架構(gòu)(Resource-Oriented Architecture,ROA)、REST式設(shè)計的優(yōu)點、REST式Web服務(wù)的真實案例分析、如何用各種流行的編程語言編寫Web服務(wù)客戶端、如何 用三種流行的框架(Ruby on Rails、Restlet和Django)實現(xiàn)REST式服務(wù)等。不僅講解REST與面向資源的架構(gòu)(ROA)的概念與原理,還向讀者介紹如何編寫符合 REST風(fēng)格的Web 2.0應(yīng)用。本書詳實、易懂,實戰(zhàn)性強,提供了大量RESTful Web服務(wù)開發(fā)的最佳實踐和指導(dǎo),適合廣大的Web開發(fā)人員、Web架構(gòu)師及對Web開發(fā)或Web架構(gòu)感興趣的廣大技術(shù)人員與學(xué)生閱讀。

與此同時,博文視點還授權(quán)InfoQ中文站獨家為大家提供額外的樣章進行試讀:歡迎下載第3章《REST 式服務(wù)有什么不同》