Apache Wink 是一個促進創建和使用 REST Web 服務的 Apache 孵化器項目。通過 REST Web 服務,客戶機和服務之間的交互局限于一組預定義的操作,客戶機和服務器之間的交互的復雜性限制為客戶機和服務之間交換的資源表示。這種方法支持構建可互操作、可伸縮、可靠的、基于 REST 的分布式超媒體系統。
常用縮略詞
- API: 應用程序編程接口
- HTTP: 超文本傳輸協議
- IDE: 集成開發環境
- JSON: JavaScript 對象符號
- REST: 具象狀態傳輸
- URI: 統一資源標識符
- XML: 可擴展標記語言
本文介紹如何使用 Apache Wink、Eclipse IDE 以及 Maven 項目管理工具開發、部署和運行 RESTful Web 服務。
Web 服務的 REST 方法
設計 Web 服務的 REST 方法將客戶機和服務之間的交互限制到一組創建、讀取、更新和刪除(CRUD)操作。這些操作直接映射到 HTTP 方法 — 具體而言,映射到 POST
、GET
、 PUT
和 DELETE
。盡管 RESTful 樣式沒有綁定到 HTTP 協議,本文假設 HTTP 用于客戶機和服務之間的通信。
REST Web 服務在資源上執行 CRUD 操作。客戶機使用資源狀態的 REST 服務表示進行交換。這些表示使用的數據格式在 HTTP 請求或響應的頭部中指定 — XML 和 JSON 是廣泛使用的格式。數據格式可能在不同操作之間發生變化;例如,創建資源的數據格式與用于讀取資源的數據格式不同。REST 服務保持資源的狀態,但 — 與 servlets 不同的是 — 不保持客戶機會話信息。
REST 方法支持構建可互操作、可伸縮和可靠的基于 REST 的分布式系統。例如,GET
、POST
和 DELETE
方法是等冪的,即多次執行它們與執行一次的結果相同。由于 GET
操作不會更改資源的狀態,因此 GET
請求的結果可以緩存起來以加快 “請求-響應” 循環。
JAX-RS 為基于 HTTP 協議的 RESTful Java Web 服務定義了一個 API。JAX-RS 實現包括 Apache Wink、Sun Jersey 和 JBoss RESTEasy。本文將使用 Apache Wink。
JAX-RS 利用 Java 注釋的威力,使用注釋來執行諸如以下的操作:
- 將 HTTP 方法和 URIs 綁定到 Java 類的方法
- 將來自 URI 或 HTTP 頭部的元素作為方法參數注入
- 在 HTTP 消息體和 Java 類型之間來回轉換
- 將 URI 模式綁定到 Java 類和方法 —
@Path
注釋 - 將 HTTP 操作綁定到 Java 方法 —
@GET
、 @POST
、@PUT
和 @DELETE
注釋
JAX-RS 還提供了一個框架來構建新功能。例如,對于自定義數據格式,程序員可以開發消息閱讀器并將 Java 對象編組到 HTTP 消息并從 HTTP 消息解組它們。
在本文中,您將使用 Eclipse 和 Maven 下載 Apache Wink,運行 Apache Wink 中包含的 HelloWorld 示例,然后將您自己的 REST Web 服務創建為一個 Eclipse 項目。
回頁首
通過 Eclipse 獲取 Apache Wink
在這個小節中,您將使用 Eclipse 以及 Maven Integration for Eclipse(稱為 m2eclipse)和 Subclipse 插件來安裝 Apache Wink。(M2eclipse 提供從 Eclipse 對 Maven 的訪問;Subclipse 提供對 Subversion 資源庫的訪問。)您還可以將 Eclipse 用作一個平臺,從這個平臺構建并運行 Web 服務。
先決條件
在獲取 Apache Wink 之前,要先下載并安裝以下軟件包(參見 參考資料 獲取下載 URLs):
- Java Software Development Kit (JDK) version 6。設置 JAVA_HOME 環境變量并添加到路徑 %JAVA_HOME%\bin(在 Windows® 中)或 $JAVA_HOME/bin(在 Linux® 中)。
- Apache Tomcat version 6.0。設置 CATALINA_HOME 環境變量以指向安裝目錄。
- Eclipse IDE for Java™ Platform, Enterprise Edition (Java EE) developers。本文撰寫之時的當前版本為 Eclipse Galileo。
安裝 Subclipse
要使用 Eclipse 管理具有 Maven 感知的項目,要安裝 Eclipse 插件 Subclipse 和 m2eclipse。要安裝 Subclipse 插件,執行以下步驟:
- 啟動 Eclipse。
- 單擊菜單欄中的 Help,然后選擇 Install new software。
- 在 Available Software 窗口中,單擊 Add。
- 在 Add Site 窗口中,輸入:
Name: Subclipse Location: http://subclipse.tigris.org/update_1.6.x/ |
然后單擊 OK。
- 在 Available Software 窗口中,選擇 Subclipse 下的 Subclipse (Required) 和 SVNKit Client Adapter (Not required) 復選框(如 圖 1 所示),然后單擊 Next。
圖 1. 安裝 Subclipse 插件
- 在 Install Details 窗口中,單擊 Next。
- 在 Review Licenses 窗口中,檢查許可,接受許可協議條款,然后單擊 Finish。
- 單擊 Yes 重新啟動 Eclipse。
安裝 m2eclipse
m2eclipse 插件的安裝步驟與安裝 Subclipse 插件類似,但有以下幾點例外:
- 在 Add Site 窗口中輸入:
Name: Maven Integration for Eclipse Location: http://m2eclipse.sonatype.org/update/ |
然后單擊 OK。
- 在 Available Software 窗口中,選擇 Maven Integration for Eclipse (Required) 和 Maven SCM handler for Subclipse (Optional) 復選框(如 圖 2 所示),然后單擊 Next。
圖 2. 安裝 m2eclipse 插件
獲取 Apache Wink
現在,您可以使用 Eclipse 從資源庫檢查 Apache Wink 示例,將必要的 Java 歸檔(JAR)文件(包括 Apache Wink JAR 文件)下載到一個本地資源庫,構建并運行 Apache Wink HelloWorld 示例。為此,執行以下步驟:
- 在 Eclipse 中,選擇 File > Import 啟動 Import Wizard。
- 在 Select 向導頁面的 Select and import source 文本框中輸入
maven
。 - 在 Maven 下,選擇 Materialize Maven Projects 并單擊 Next。
- 在 Select Maven artifacts 向導頁面上單擊 Add。
- 在 Add Dependency 頁面上的 Enter groupId, artifactId 文本框中輸入
org.apache.wink.example
。
注意: Artifact(工件) 是一個用于 Maven 的術語,指的是設置了版本并存儲在資源庫中的軟件包的層級結構。 - 在 Search Results 區域中,選擇 org.apache.wink.example apps(如 圖 3 所示)并單擊 OK。
圖 3. org.apache.wink.example 組中的應用程序工件
- 在 Select Maven artifacts 向導頁面上,單擊 Next,然后單擊 Finish。
- 在 Maven Projects 向導頁面上,只選擇 /pom.xml 復選框,然后單擊 Finish。
Maven 處理一個工件的所有依賴項的方式是從遠程資源庫下載它們并構建一個本地資源庫。Maven 的優勢之一是能夠處理臨時依賴項;因此,在 Maven Project Object Model (POM) 文件中,只需聲明工件的傳遞依賴項(transitive dependencies),Maven 將為您處理高階依賴項(higher-order dependencies)。
步驟 8 完成后,將創建一個 Eclipse 項目,它包含 Apache Wink 示例的 apps
模塊中的代碼。在 Eclipse 的 Project Explorer 中瀏覽項目文件。
回頁首
Apache Wink HelloWorld 服務
我們來檢查一下 apps
模塊中的 HelloWorld
Java 類。在 Project Explorer 視圖中,單擊 apps > HelloWorld > src > main,然后打開文件 HelloWorld.java,該文件的結構如 清單 1 所示。
清單 1. HelloWorld.java 文件
package org.apache.wink.example.helloworld; ... @Path("/world") public class HelloWorld { public static final String ID = "helloworld:1"; @GET @Produces(MediaType.APPLICATION_ATOM_XML) public SyndEntry getGreeting() { SyndEntry synd = new SyndEntry(new SyndText("Hello World!"), ID, new Date()); return synd; } } |
HelloWorld 是一個 JAX-RS 資源(或服務),正如其類定義前面的 @Path("/world")
注釋所示。字符串 "/world"
是該資源的相對根 URI。JAX-RS 將匹配相對 URI "/world"
的 HTTP 請求路由到 HelloWorld
類的方法。
HelloWorld
類的惟一方法 — getGreeting
— 擁有一個 @GET
注釋,表示它將服務于 HTTP GET
請求。
@Produces(MediaType.APPLICATION_ATOM_XML)
注釋表明 HTTP 響應的媒體類型 — 即,HTTP 響應頭部中的 Content-Type
字段的值。
與相對 URI "/world"
關聯的絕對 URI 由部署描述符 web.xml
中的設置決定,這個部署描述符駐留在 HelloWorld/src/main/webapp/WEB-INF 中,如 圖 4 所示。
圖 4. HelloWorld 應用程序的部署描述符
注意,URI 模式 /rest/*
被綁定到 restSdkService
servlet,這個 servlet 的 context path 是 HelloWorld
,由 HelloWorld/pom.xml 文件中的 <finalName>
元素定義。這樣,HelloWorld
資源的絕對 URI 是:
http://host:port/HelloWorld/rest/world |
圖 4 中的 servlet 名稱 restSdkService
引用 org.apache.wink.server.internal.servlet.RestServlet
Apache Wink 類,如圖中的<servlet>
元素所示。RestServlet
類使用初始參數 applicationConfigLocation
傳遞 HelloWorld
類的名稱,這個初始參數反過來指向位于 HelloWorld/src/main/webapp/WEB-INF 文件夾中的 web.xml 旁邊的 application 文件。這個 application 文件只有一行,即HelloWorld
資源的限定名:
org.apache.wink.example.helloworld.HelloWorld |
RestServlet
servlet 可以在 “無 JAX-RS 感知” 的 servlet 容器中運行,從而支持將 JAX-RS 服務輕松部署到 “無 JAX-RS 感知” 的容器中。
我們現在開始構建 HelloWorld 服務,然后將其部署到 Tomcat 6.0 servlet 容器中并運行。
構建 HelloWorld
在 Eclipse 中,可以使用 m2eclipse 插件來構建、部署和運行 HelloWorld。首先,編譯源代碼并為 HelloWorld 服務構建 Web 歸檔 (WAR) 文件。要構建這個服務,指示 m2eclipse 執行安裝生命周期階段。(執行一個 Maven 生命周期階段將觸發項目生命周期中的此前階段的執行。)要執行安裝階段,在 Project Explorer 視圖中右鍵單擊 HelloWorld,然后單擊 Run As > Maven install,如 圖 5所示。
圖 5. 執行 Maven 安裝階段
Maven (從中央資源庫 http://repo1.maven.org/maven2 或從鏡像資源庫)下載所有依賴項,并在 Windows® 中的 %HOMEPATH%\.m2\repository 或 Linux® 中的 $HOME/.m2/repository 下構建本地資源庫。Maven 執行的動作記錄在 Eclipse 窗口的 Console 視圖中。
如果安裝階段成功結束,那么 WAR 文件 HelloWorld.war 就構建在目標目錄下并部署到本地資源庫中,Console 視圖將顯示消息 “Build successful”。
將 HelloWorld 部署到 Tomcat
您將使用 Maven 的 Tomcat 插件。(與 Eclipse 一樣,Maven 通過插件提供大量功能。)您必須將 Tomcat 插件的位置告知 Maven,方法是指定插件的 groupId
和 artifactId
,如 圖 6 所示(pom.xml 中的 45-46 行)。
圖 6. Tomcat Maven 插件
您還需要告知 Maven 用于訪問 Tomcat manager 應用程序的用戶名和密碼。Maven 使用 manager 應用程序來指導 Tomcat 部署或取消部署一個 Web 應用程序。按照以下步驟告知 Maven 身份驗證信息:
- 聲明
tomcat-maven-plugin
工件的一個 Tomcat 服務器配置 — 稱為 tomcat-localhost
,如 圖 6 所示(pom.xml 中的 47-49 行) - 在 Maven 設置文件 settings.xml(位于 Windows 的 %HOMEPATH%\.m2\ 或 Linux 的 $HOME/.m2 下)中定義這個配置,如清單 2 所示。
清單 2. Maven settings.xml 文件
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <servers> <server> <id>tomcat-localhost</id> <username>admin</username> <password>admin</password> </server> </servers> </settings> |
現在可以將這個服務部署到 Tomcat 了,方法是執行 Tomcat 插件的 redeploy 目標。(一個 Maven 目標(goal) 被自身執行,這與生命周期階段不同,后者的執行由生命周期中的此前階段自動推進。)要執行 redeploy 目標,執行以下步驟:
- 在 Tomcat 配置文件 conf/tomcat-users.xml(位于 CATALINA_HOME 下)中插入身份驗證信息(如 圖 7 所示),但要使用一個密碼,而不是 admin。
圖 7. Tomcat 身份驗證配置
- 通過運行以下命令啟動 Tomcat:
In Windows: %CATALINA_HOME%\bin\catalina.bat start In Linux: $CATALINA_HOME/bin/catalina.sh start |
- 執行
maven tomcat:redeploy
,這條命令使用 Tomcat manager 應用程序將 HelloWorld.war 部署到 Tomcat。為此,執行以下步驟:- 在 Project Explorer 視圖中,右鍵單擊 HelloWorld,然后單擊 Run As > Run configurations。
- 在 Create, manage, and run configurations 窗口中,選擇 Maven Build > New_configuration,然后單擊 Main 選項卡(參見 圖 8)。
圖 8. 運行 tomcat:redeploy 目標
- 單擊 Browse workspace,然后選擇 apps > HelloWorld,然后單擊 OK。
- 在 Goals 文本框中,輸入
tomcat:redeploy
,然后單擊 Run。如果 redeploy 目標成功執行,Console 視圖將顯示消息 “Build successful”。
現在,您可以使用一個 HTTP 客戶機(比如 Curl)調用 HelloWorld 服務,如 清單 3 所示。
清單 3. 在 Curl 中調用 HelloWorld 服務
$ curl -X GET http://localhost:8080/HelloWorld/rest/world <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <entry xmlns="http://www.w3.org/2005/Atom" xmlns:ns2="http://a9.com/-/spec/opensearch/1.1/" xmlns:ns3="http://www.w3.org/1999/xhtml"> <id>helloworld:1</id> <updated>2010-01-06T13:26:43.924+01:00</updated> <title type="text">Hello World!</title> </entry> |
回頁首
開發一個 REST Web 服務
在這個小節中,您將從頭開始創建一個 REST Web 服務來管理一個圖書資源集合。這個 REST 服務的源代碼可以從下面的 下載 表中獲取。
開發這樣一個服務的關鍵步驟是:
- 定義資源的 URIs,用于操作資源的方法,以及每個方法的數據格式。
- 定義表示圖書資源的 Java 對象,提供 Java 代碼或注釋來編組和解組 Java 對象。
- 定義將 URIs 和 HTTP 方法綁定到 Java 方法的 Java 服務。
- 提供
javax.ws.rs.core.Application
抽象類的一個具體子類。
下面我們就執行這些步驟。
將路徑和 HTTP 方法綁定到 Java 方法
這個服務支持 GET
, POST
、PUT
和 DELETE
HTTP 方法,并按如下方式將 HTTP 請求映射到 Java 方法:
- 將
POST /books
請求映射到帶有 createBook(@Context UriInfo, Book)
簽名的 Java 方法。(@Context
注釋將在 JAX-RS Web 服務 小節中介紹。)用于創建一個圖書資源的數據格式為:
POST /books HTTP/1.1 Content-Type: application/xml <book> <title> ... </title> <isbn> .... </isbn> </book> |
- 將
GET /books
請求映射到 Java 方法 getBook()
。用于獲取圖書資源的數據格式為:
GET /books HTTP/1.1 Content-Type: application/xml |
- 將
GET /books/{id}
請求映射到帶有 getBook(@PathParam("id") int)
簽名的 Java 方法。(@PathParam
注釋將在 JAX-RS Web 服務 小節中介紹。)用于獲取帶有 URI 模式 /books/{id}
的圖書資源的數據格式為:
GET /books/{id} HTTP/1.1 Content-Type: application/xml |
- 將
PUT /books/{id}
請求映射到帶有 updateBook(@PathParam("id") int, Book)
簽名的 Java 方法。用于更新帶有 URI 模式/books/{id}
的圖書資源的數據格式為:
PUT /books/{id} HTTP/1.1 Content-Type: application/xml <book> <title> ... </title> <isbn> .... </isbn> </book> |
- 將
DELETE /books/{id}
請求映射到帶有 deleteBook(@PathParam("id") int)
簽名的 Java 方法。用于刪除帶有 URI 模式/books/{id}
的圖書資源的數據格式為:
DELETE /books/{id} HTTP/1.1 Content-Type: application/xml |
圖書的對象模型
用于實現這個圖書集合的 Java 對象模型有 3 個類:
清單 4. Book 類
package com.ibm.devworks.ws.rest.books; import javax.xml.bind.annotation.*; @XmlRootElement(name="book") @XmlAccessorType(XmlAccessType.FIELD) public class Book { @XmlAttribute(name="id") private int id; @XmlElement(name="title") private String title; @XmlElement(name="isbn") private String ISBN; @XmlElement(name = "link") private Link link; public Book() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getISBN() { return ISBN; } public void setISBN(String ISBN) { this.ISBN = ISBN; } public Link getLink() { return link; } public void setLink(String uri) { this.link = new Link(uri); } } |
在 Book
類中,您使用 Java Architecture for XML Binding (JAXB) 注釋來執行 Java 對象的編組和解組。Apache Wink 自動編組和解組帶有 JAXB 注釋的 Java 對象,包括創建執行編組和解組工作的 Marshaller
和 Unmarshaller
實例。
您將使用 BookList
類來表示圖書對象的集合,BookList
類將這些對象以內部存儲方式存儲在 ArrayList
類型的一個字段中,ArrayList
帶有 JAXB 注釋,以便轉換為 XML 格式。
清單 5. BookList 類
package com.ibm.devworks.ws.rest.books; import java.util.ArrayList; import java.util.Map; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlElementRef; @XmlRootElement(name="books") public class BookList { @XmlElementRef ArrayList<Book> books; public BookList() { } public BookList( Map<Integer, Book> bookMap ) { books = new ArrayList<Book>( bookMap.values() ); } } |
您將使用 Link
類將鏈接元素插入到圖書對象的 XML 表示中(參見 清單 6)。
清單 6. Link 類
package com.ibm.devworks.ws.rest.books; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @XmlRootElement(name="link") @XmlAccessorType(XmlAccessType.FIELD) public class Link { @XmlAttribute String href = null; @XmlAttribute String rel = "self"; public Link() { } public Link( String uri) { this.href = uri; } public Link( String href, String rel) { this.href = href; this.rel = rel; } } |
JAX-RS Web 服務
現在,您已經定義了將 URIs 和 HTTP 方法綁定到 Java 方法的 Java 服務。您可以將這個服務定義為一個 Java 接口或一個類;對于前者,還需要定義實現接口的類。在接口中,您本地化 JAX-RS 注釋并添加一個類來實現接口。
清單 7 展示了 BookService
Java 接口。@javax.ws.rs.Path
注釋將這個接口指定為一個 JAX-RS 服務。注釋的 /books
值定義這個服務的相對根 URI。注釋 @javax.ws.rs.POST
、@javax.ws.rs.GET
、@javax.ws.rs.PUT
和 @javax.ws.rs.DELETE
將 HTTPPOST
、GET
、PUT
和 DELETE
操作綁定到緊隨其后的 Java 方法。
清單 7. BookService 接口
package com.ibm.devworks.ws.rest.books; import javax.ws.rs.*; import javax.ws.rs.core.*; @Path("/books") public interface BookService { @POST @Consumes(MediaType.APPLICATION_XML) @Produces(MediaType.APPLICATION_XML) public Response createBook(@Context UriInfo uriInfo, Book book); @GET @Produces(MediaType.APPLICATION_XML) public BookList getBook(); @Path("{id}") @GET @Produces(MediaType.APPLICATION_XML) public Book getBook(@PathParam("id") int id); @Path("{id}") @PUT @Consumes(MediaType.APPLICATION_XML) public void updateBook(@PathParam("id") int id, Book book_updated); @Path("{id}") @DELETE public void deleteBook(@PathParam("id") int id); } |
對于其 URI 與接口的 @PATH("/books")
注釋指定的值不同的方法,您將一個特定的 @PATH
注釋附加到那些方法。@PATH
注釋是可以累積的,即,一個路徑表達式后面的另一個路徑表達式將附加到前面的表達式。因此,綁定到 deleteBook
方法的路徑模式為/books/{id}
。
JAX-RS 提供了一種機制,用于從一個 HTTP 請求提取信息,將信息賦予一個 Java 對象,然后將該對象注入一個 Java 方法參數。這種機制稱為注入(injection)。注入使用 Java 注釋指定。在 BookService
接口中,您將插入兩個注入注釋:
@Context
注釋從 HTTP 請求提取 URI 信息,將其轉換為 UriInfo
對象,然后將這個對象作為方法參數 uriInfo
注入。@PathParam("id")
注釋匹配前面的 @Path({"id"})
注釋。這個注釋從 URI 模式 /books/{id}
提取 {id}
,并將其注入 getBook
方法的 id
參數的值。
注意,BookService
的方法將 Java 對象(比如 Book
)接收為參數并返回 Java 對象;這是可能的,因為這些對象帶有 JAXB 注釋,因此 Apache Wink 能夠對它們進行自動編組和解組。
清單 8 展示了實現 BookService
的類的結構。BookServiceImpl
是一個 singleton 類,使用一個內存映射圖(in-memory map)來維護圖書對象集合。singleton 實例使用多線程服務并發請求,因此它必須是線程安全的(thread-safe)。
清單 8. BookService 實現類
package com.ibm.devworks.ws.rest.books; import javax.ws.rs.*; import java.net.URI; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; @Path("/books") public class BookServiceImpl implements BookService { private static BookServiceImpl instance = null; private BookServiceImpl() { } public synchronized static BookServiceImpl getInstance() { if(instance == null) { instance = new BookServiceImpl(); } return instance; } private Map <Integer, Book> bookMap = new ConcurrentHashMap <Integer, Book>(); private AtomicInteger seqNumber = new AtomicInteger(); public Response createBook(@Context UriInfo uriInfo, Book book) throws WebApplicationException { ... } public BookList getBook() { ... } public Book getBook(@PathParam("id") int id) throws WebApplicationException { ... } public void updateBook(@PathParam("id") int id, Book book_updated) throws WebApplicationException { ... } public void deleteBook(@PathParam("id") int id) throws WebApplicationException { ... } } |
圖書集合存儲在一個映射圖中。要提供對這個映射圖的線程安全訪問,您將使用一個 ConcurrentHashMap
。要生成惟一的圖書 IDs,您將使用一個 AtomicInteger
,它能確保增量操作是原子級的(atomic),從而確保線程安全。
設置 Application 抽象類的子類
JAX-RS Web 應用程序包含一組資源(REST Web 服務),這些資源作為 JAX-RS 抽象類 javax.ws.rs.core.Application
的子類出現。清單 9 中顯示的 BookWebApp
類擴展了 Application
類。
清單 9. javax.ws.rs.core.Application 的具體子類
package com.ibm.devworks.ws.rest.books; import java.util.HashSet; import java.util.Set; import javax.ws.rs.core.Application; public class BookWebApp extends Application { private Set<Object> svc_singletons = new HashSet<Object>(); private Set<Class<?>> svc_classes = new HashSet<Class<?>>(); public BookWebApp() { svc_singletons.add(BookServiceImpl.getInstance()); } @Override public Set<Object> getSingletons() { return svc_singletons; } @Override public Set<Class<?>> getClasses() { return svc_classes; } } |
BookWebApp
的構造函數獲取這個圖書服務實現對象的 singleton 實例。getSingletons
方法返回一個組,其惟一元素就是這個 singleton。JAX-RS 在服務一個請求后并不刪除這個 singleton。
回頁首
構建和部署 REST Web 服務
您將使用 Eclipse 來創建一個動態 Web 項目,這個項目包含上一小節介紹過的 Java 類和其他資源,比如 Web 應用程序部署描述符和必要的 JAR 文件。
注意:創建一個 Eclipse 動態 Web 項目的另一種方法是從一個 archetype(比如 maven-archetype-webapp
或 webapp-jee5
)創建一個 Maven 項目(archetype 是一個 Maven 項目模板)。但是,在 Maven 當前版本中,生成 Eclipse 使用的項目元數據時會出現一些問題:要支持 IDE 中的自動代碼構建,必須手動修改一些 Eclipse 項目文件。因此,本文使用 Eclipse 動態 Web 項目。
Web 服務的 Eclipse 項目
Eclipse 動態 Web 項目支持開發在一個 servlet 容器中運行的 Web 應用程序,因此它是用于開發 Apache Wink 服務的一個不錯的項目模板。要為這個圖書 REST 服務創建一個動態 Web 項目,執行以下步驟:
- 在 Eclipse 中,單擊 File > New > Dynamic Web Project。
- 在 Dynamic Web Project Wizard 中,在 Project name 文本框中輸入
Books
。 - 單擊 Target runtime 方框旁邊的 New 創建一個 Tomcat 運行時。
- 在 New Server Runtime Environment 向導頁面上,單擊 Apache > Apache Tomcat v6.0,然后單擊 Next。
- 在 Tomcat Server 向導頁面上,單擊 Browse,然后導航到 先決條件 小節中定義的 CATALINA_HOME 目錄。
- 單擊 OK,然后單擊 Finish。
- 在 Dynamic Web Project 頁面上,單擊 Finish。
將上一小節中介紹的 Java 類添加到剛才創建的 Books 項目中。為此,執行以下步驟:
- 在 Project Explorer 視圖中,打開 Books 文件夾。右鍵單擊 Java Resources:src,然后單擊 New > Package。
- 在 Java Package 窗口中的 Name 文本框中,輸入包名稱 —
com.ibm.devworks.ws.rest.books
— 并單擊 Finish。 - 將 Java 類添加到
com.ibm.devworks.ws.rest.books
包:- 在 Project Explorer 視圖中,右鍵單擊上述包,然后單擊 New > Class。
- 在 Name 文本框中,輸入類名稱(比如為
Book.java
輸入 Book
),然后單擊 Finish。 - 使用 Eclipse Java 編輯器來創建類。
然后,向項目添加構建和運行一個 Apache Wink 服務所需的 JAR 文件。當您創建這個應用程序項目時,Maven 將 JAR 文件下載到本地資源庫,本地資源庫駐留在 %HOMEPATH%\.m2\repository(Windows)或 $HOME/.m2/repository(Linux)中。
要將 JAR 文件添加到這個項目,執行以下步驟:
- 在 Project Explorer 視圖中,導航到 Books/Web Content/WEB-INF。
- 右鍵單擊 lib,然后單擊 Import > General > File System,然后單擊 Next。
- 在 File System 窗口中,從 Maven 資源庫(已在導入應用程序 Apache Wink 模塊時由 m2eclipse 填充)導入 JAR 文件 jsr311-api-1.0.jar,方法是導航到包含這個 JAR 文件的目錄,然后單擊 OK。在 File System 窗口中,選中這個 JAR 文件,然后單擊 Finish。
- 重復步驟 2 到步驟 3,分別導入 JAR 文件 wink-server-1.0-incubating.jar、 wink-common-1.0-incubating.jar、slf4j-api-1.5.8.jar 和 slf4j-simple-1.5.8.jar。
所有庫都導入后,lib 目錄將包含如 圖 9 所示的 JAR 文件。
圖 9. 一個 Apache Wink 服務所需的庫
您還可以通過從下面的 下載 部分中提供的代碼樣例中導入 Book 服務來創建這個 Eclipse 項目。為此,下載并解壓文件,然后在 Eclipse 中單擊 File > Import > Existing Project Into Workspace。在 Import Projects Wizard 中,單擊 Browse, 導航到 Books 文件夾,單擊 OK,然后單擊 Finish。
將服務部署到 Tomcat
在部署描述符文件 web.xml(如 清單 10 所示)中,您將帶有相對根路徑 /* 的 URIs 映射到 Wink servletorg.apache.wink.server.internal.servlet.RestServlet
。RestServlet
被傳遞為 init-param
,這是 Books 服務提供的Application
子類的名稱。
清單 10. BookService 部署服務描述符 web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>Book Web Application</display-name> <servlet> <servlet-name>restSdkService</servlet-name> <servlet-class>org.apache.wink.server.internal.servlet.RestServlet</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>com.ibm.devworks.ws.rest.books.BookWebApp</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>restSdkService</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app> |
部署描述符設置好后,就可以將這個 Books 服務部署到 Tomcat 了。為了進行測試,將這個 Books 服務部署到一個由 Eclipse 托管的 Tomcat 實例中并運行。為此,執行以下步驟:
- 在 Project Explorer 視圖中,右鍵單擊 Books,然后單擊 Run As > Run on Server。
- 在 Run on Server 窗口中,單擊 Finish,這將把這個 Books 服務部署到創建這個 Books 項目時配置的 Tomcat 運行時中并啟動 Tomcat。
測試完成后,您將這個 Books 服務打包到一個 WAR 文件中,以備部署到生產環境中。為此,在 Project Explorer 視圖中,右鍵單擊Books,然后單擊 Export > WAR file。在 WAR Export Wizard 中,單擊 Browse,選擇創建 WAR 文件的文件夾,然后單擊 Save 和Finish。
回頁首
調用 REST Web 服務
可以使用一個支持 HTTP 操作 GET
、POST
、PUT
和 DELETE
的 HTTP 客戶機來調用這個 Books 服務。 清單 11 展示了如何使用 Curl 來調用這個服務。首先,您將得到所有圖書的表示(最初沒有圖書);然后,您使用 jaxrs.xml 和 rest.xml 兩個表示來創建兩本圖書;最后,您得到所有圖書的表示和 id=2
的圖書的表示。
清單 11. 調用 Books 服務
$ curl -X GET http://localhost:8080/Books/books <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <books/> $ more Books\xml\jaxrs.xml <?xml version="1.0" encoding="UTF-8"?> <book> <titleRESTful Java with JAX-RS</title> <isbn>978-0-596-15804-0</isbn> </book> $ more Books\xml\rest.xml <?xml version="1.0" encoding="UTF-8"?> <book> <title>RESTful Web Services</title> <isbn>978-0-596-52926-0</isbn> </book> $ curl -H "Content-Type: application/xml" -T Books\xml\jaxrs.xml \ -X POST http://localhost:8080/Books/books $ curl -H "Content-Type: application/xml" -T Books\xml\rest.xml \ -X POST http://localhost:8080/Books/books $ curl -X GET http://localhost:8080/Books/books <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <books> <book id="2"> <title>RESTful Web Services</title> <isbn>978-0-596-52926-0</isbn> <link rel="self" href="http://localhost:8080/Books/books/2"/> </book> <book id="1"> <title>RESTful Java with JAX-RS</title> <isbn>978-0-596-15804-0</isbn> <link rel="self" href="http://localhost:8080/Books/books/1"/> </book> </books> $ curl -X GET http://localhost:8080/Books/books/2 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <book id="2"> <title>RESTful Web Services</title> <isbn>978-0-596-52926-0</isbn> <link rel="self" href="http://localhost:8080/Books/books/2"/> </book> |
回頁首
結束語
本文展示了如何聯合使用幾種技術來支持 Apache Wink REST Web 服務的開發、構建和部署。Java 注釋的威力簡化了開發工作。
REST Web 服務支持應用程序交換鏈接數據。Tim Berners-Lee 先生預言,鏈接數據將改變 Web 的面貌。Bill Burke 在他撰寫的圖書 RESTful Java with JAX-RS 中指出,通過將服務交互的復雜性限制為數據表示,REST Web 服務將服務組合性和重用提高到一個新的水平。
本文僅僅涉及 Apache Wink 服務開發的皮毛,Apache Wink 的其他重要特性包括鏈接構建器、自定義消息體閱讀器以及針對不受支持的數據格式的編寫器。要深入了解 Apache Wink 框架,一定要看一看 Apache Wink 中包含的其他示例。
回頁首
下載
描述 | 名字 | 大小 | 下載方法 |
---|
本文源代碼 | wink_code.zip | 645KB | HTTP |
關于下載方法的信息
參考資料
學習