在Eclipse中使用Jersey和Tomcat構建RESTful WebService及其調用

在Eclipse中使用Jersey和Tomcat構建RESTful WebService及其調用html

RESTful Web 服務簡介java

REST 在 2000 年由 Roy Fielding 在博士論文中提出,他是 HTTP 規範 1.0 和 1.1 版的首席做者之一。web

REST 中最重要的概念是資源(resources),使用全球 ID(一般使用 URI)標識。客戶端應用程序使用 HTTP 方法(GET/ POST/ PUT/ DELETE)操做資源或資源集。RESTful Web 服務是使用 HTTP 和 REST 原理實現的 Web 服務。一般,RESTful Web 服務應該定義如下方面:json

  • Web 服務的基/根 URI,好比 http://host/<appcontext>/resources。api

  • 支持 MIME 類型的響應數據,包括 JSON/XML/ATOM 等等。瀏覽器

  • 服務支持的操做集合(例如 POST、GET、PUT 或 DELETE)。tomcat

表 1 演示了典型 RESTful Web 服務中使用的資源 URI 和 HTTP 方法。服務器

 1. RESTful Web 服務示例app

方法/資源框架

資源集合, URI 如:
http://host/<appctx>/resources

成員資源,URI 如:
http://host/<appctx>/resources/1234

GET

列出資源集合的全部成員。

檢索標識爲 1234 的資源的表示形式。

PUT

使用一個集合更新(替換)另外一個集合。

更新標記爲 1234 的數字資源。

POST

在集合中建立數字資源,其 ID 是自動分配的。

在下面建立一個子資源。

DELETE

刪除整個資源集合。

刪除標記爲 1234 的數字資源。


JSR 311 (JAX-RS)和 Jersey

JSR 311 或 JAX-RS(用於 RESTful Web Services 的 Java API)的提議開始於 2007 年,1.0 版本到 2008 年 10 月定稿。目前,JSR 311 版本 1.1 還處於草案階段。該 JSR 的目的是提供一組 API 以簡化 REST 樣式的 Web 服務的開發。

在 JAX-RS 規範以前,已經有 Restlet 和 RestEasy 之類的框架,能夠幫助您實現 RESTful Web 服務,可是它們不夠直觀。Jersey 是 JAX-RS 的參考實現,它包含三個主要部分。

  • 核心服務器(Core Server):經過提供 JSR 311 中標準化的註釋和 API 標準化,您能夠用直觀的方式開發 RESTful Web 服務。

  • 核心客戶端(Core Client):Jersey 客戶端 API 幫助您與 REST 服務輕鬆通訊。

  • 集成(Integration):Jersey 還提供能夠輕鬆集成 Spring、Guice、Apache Abdera 的庫。

 

構建 RESTful Web 服

我將從能夠集成到 Tomcat 的 「hello world」用程序開始。該應用程序將帶領您完成境的程,並涉及 Jersey 和 JAX-RS 的基

而後,我將介更加復用程序,深刻探 JAX-RS 的本和特性,好比多個 MIME 型表示形式支持、JAXB 支持等。

 

Hello World:第一個 Jersey Web 項目

要設置開發環境:

  • IDE:Eclipse IDE for JEE (v3.4+) 或 IBM Rational Application Developer 7.5

  • Java SE5 或更高版本

  • Web 容器:Apache Tomcat 6.0(Jetty 和其餘也能夠)

  • Jersey 庫:Jersey 1.0.3 歸檔,包含全部必需的庫

 

置 Jersey 的環境

首先,爲 Eclipse 上的 Tomcat 6.0 建立服務器運行時。這是用於 RESTful Web 應用程序的 Web 容器。而後建立一個名爲 「Jersey」 應用程序,並將目標運行時指定爲 Tomcat 6.0。

最後,從 Jersey 開發包中將如下庫複製到 WEB-INF 下的庫目錄:

  • 核心服務器:jersey-core.jar,jersey-server.jar,jsr311-api.jar,asm.jar, jersey-bundle.jar

  • 核心客戶端:(用於測試)jersey-client.jar

  • JAXB 支持:(在高級樣例中使用)jaxb-impl.jar,jaxb-api.jar,activation.jar,stax-api.jar,wstx-asl.jar

  • JSON 支持:(在高級樣例中使用)jersey-json.jar

Jersey庫文件的下載地址:http://jersey.java.net/nonav/documentation/latest/chapter_deps.html

須要下載的庫文件以下:

activation-1.1.1.jar

asm-3.3.1.jar

jackson-core-asl-1.9.2.jar

jackson-jaxrs-1.9.2.jar

jackson-mapper-asl-1.9.2.jar

jaxb-api-2.2.4.jar

jaxb-impl-2.2.4-1.jar

jersey-bundle-1.12.jar

jersey-client-1.12.jar

jersey-core-1.12.jar

jersey-json-1.12.jar

jersey-server-1.12.jar

jettison-1.1.jar

stax-api-1.0-2.jar

 

發 REST 服務

如今,您已經設置好了開發第一個 REST 服務的環境,該服務對客戶端發出 「Hello」。

要作到這一點,您須要將全部的 REST 請求發送到 Jersey 容器 —— 在應用程序的 web.xml 文件中定義 servlet 調度程序(參見清單 1)。除了聲明 Jersey servlet 外,它還定義一個初始化參數,指示包含資源的 Java 包。

 

單 1. 在 web.xml 文件中定義 Jersey servlet 調度程度

<servlet>  
  <servlet-name>Jersey REST Service</servlet-name>  
<servlet-class>  
  com.sun.jersey.spi.container.servlet.ServletContainer  
</servlet-class>  
  <init-param>  
    <param-name>com.sun.jersey.config.property.packages</param-name>  
    <param-value>sample.hello.resources</param-value>  
  </init-param>  
  <load-on-startup>1</load-on-startup>  
</servlet>  
<servlet-mapping>  
  <servlet-name>Jersey REST Service</servlet-name>  
  <url-pattern>/rest/*</url-pattern>  
</servlet-mapping>

如今您將編寫一個名爲 HelloResource 的資源,它接受 HTTP GET 並響應 「Hello Jersey」。


單 2. sample.hello.resources 包中的 HelloResource

@Path("/hello")  
public class HelloResource {  
    @GET  
    @Produces(MediaType.TEXT_PLAIN)  
    public String sayHello() {  
        return "Hello Jersey";  
    }  
}

該代碼中有幾個地方須要強調:

  • 資源類(Resource Class):注意,資源類是一個簡單的 Java 對象 (POJO),能夠實現任何接口。這增長了許多好處,好比可重用性和簡單。

  • 註釋(Annotation):在 javax.ws.rs.* 中定義,是 JAX-RS (JSR 311) 規範的一部分。

  • @Path:定義資源基 URI。由上下文根和主機名組成,資源標識符相似於 http://localhost:8080/Jersey/rest/hello。

  • @GET:這意味着如下方法能夠響應 HTTP GET 方法。

  • @Produces:以純文本方式定義響應內容 MIME 類型。

部署到Tomcat容器

在Jersey項目上點擊右鍵,Export---WAR file,生成Jersey.war文件,複製該文件到Tomcat安裝目錄下的webapps目錄下,從新啓動tomcat,Jersey.war文件將被自動解壓。

 

 

測試 Hello 應用程序

要測試應用程序,能夠打開您的瀏覽器並輸入 URL http://<host>:<port>/<appctx>/rest/hello。您將看到響應 「Hello Jersey」。這很是簡單,使用註釋處理請求、響應和方法。

如下部分將涉及 JAX-RS 規範的必要部分,使用 Contacts 示例應用程序中的代碼片斷進行介紹。您能夠在源代碼包中找到這個高級樣例的全部代碼。

 

源是成 RESTful Web 服的關部分。您可使用 HTTP 方法(如GETPOSTPUT 和DELETE)操做源。用程序中的全部內容都是源:工、系人、組織等。在 JAX-RX 中,源通 POJO實現,使用@Path  注釋組成其標識符源能夠有子源。在種狀況下,父源是源集合,子源是成員資源。

例 Contacts用程序中,您將操做我的系人和系人集合。ContactsResource 是 /contacts URI 成的集合源,ContactResource 是 /contacts/{contactId} URI成的成員資源。下劃 JavaBean 是一個簡單的 Contact,使用 id、名稱和地址做字段。參 3 和清 4 瞭解情。

單 3. ContactsResource

@Path("/contacts")  
public class ContactsResource {  
    @Context  
    UriInfo uriInfo;  
    @Context  
    Request request;  
  
    @GET  
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})  
    public List<Contact> getContacts() {  
        List<Contact> contacts = >new ArrayList<Contact>();  
        contacts.addAll( ContactStore.getStore().values() );  
        return contacts;  
    }  
  
@Path("{contact}")  
    public ContactResource getContact(  
            @PathParam("contact") String contact) {  
        return new ContactResource(uriInfo, request, contact);  
    }  
}

有幾個有趣的地方須要注意。

  • @Context: 使用該註釋注入上下文對象,好比 Request、Response、UriInfo、ServletContext 等。

  • @Path("{contact}"):這是 @Path 註釋,與根路徑 「/contacts」 結合造成子資源的 URI。

  • @PathParam("contact"):該註釋將參數注入方法參數的路徑,在本例中就是聯繫人 id。其餘可用的註釋有 @FormParam、@QueryParam 等。

  • @Produces:響應支持多個 MIME 類型。在本例和上一個示例中,APPLICATION/XML 將是默認的 MIME 類型。

您也許還注意到了,GET 方法返回定製 Java 對象而不是 String(純文本),正如上一個 Hello World 示例所示。 JAX-RS 規範要求實現支持多個表示形式類型,好比 InputStream、byte[]、JAXB 元素、JAXB 元素集合等等,以及將其序列化爲 XML、JSON 或純文本做爲響應的能力。下文我將提供更多有關表示形式技術的信息,尤爲是 JAXB 元素表示形式。


單 4. ContactResource

public class ContactResource {  
    @Context  
    UriInfo uriInfo;  
    @Context  
    Request request;  
    String contact;  
      
    public ContactResource(UriInfo uriInfo, Request request,   
            String contact) {  
        this.uriInfo = uriInfo;  
        this.request = request;  
        this.contact = contact;  
    }  
      
    @GET  
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})  
    public Contact getContact() {  
        Contact cont = ContactStore.getStore().get(contact);  
        if(cont==null)  
            throw new NotFoundException("No such Contact.");  
        return cont;  
    }  
}

ContactResource 的代碼簡單明瞭。注意如下內容:

  • Representation Type Contact:Contact 是一個簡單的 JavaBean,由 @XmlRootElement 註釋,這使它能夠表示爲 XML 或 JSON。

  • ContactStore:這是基於 HashMap 的內存數據存儲庫,其實現對於本文不重要。

 

方法

HTTP 方法映射到資源的 CRUD(建立、讀取、更新和刪除) 操做。儘管您能夠作一些小修改,好比讓 PUT 方法變成建立或更新,但基本的模式以下:

  • HTTP GET:獲取/列出/檢索單個資源或資源集合。

  • HTTP POST:新建資源。

  • HTTP PUT:更新現有資源或資源集合。

  • HTTP DELETE:刪除資源或資源集合。

由於我已經介紹過 GET 方法,我將從 POST 開始說明。就像其餘方法同樣,我仍然使用 Contact 示例進行說明。

 

POST

一般經過填寫表單建立新聯繫人。也就是說,HTML 表單將 POST 到服務器,服務器建立並維護新建立的聯繫人。清單 5 演示了該操做的服務器端邏輯。


單 5. 接受表單提交(POST)並新建一個聯繫人

@POST  
@Produces(MediaType.TEXT_HTML)  
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)  
public void newContact(  
        @FormParam("id") String id,  
        @FormParam("name") String name,  
        @Context HttpServletResponse servletResponse  
) throws IOException {  
    Contact c = new Contact(id,name,new ArrayList<Address>());  
    ContactStore.getStore().put(id, c);  
          
    URI uri = uriInfo.getAbsolutePathBuilder().path(id).build();  
    Response.created(uri).build();  
          
    servletResponse.sendRedirect("../pages/new_contact.html");  
}

注意該示例的如下部分:

  • @Consumes:聲明該方法使用 HTML FORM。

  • @FormParam:注入該方法的 HTML 屬性肯定的表單輸入。

  • @Response.created(uri).build(): 構建新的 URI 用於新建立的聯繫人(/contacts/{id})並設置響應代碼(201/created)。您可使用 http://localhost:8080/Jersey/rest/contacts/<id> 訪問新聯繫人。

 

PUT

我使用 PUT 方法更新現有資源。可是,也能夠經過更新實現,或者像清單 6 中的代碼片斷展現的那樣建立一個資源。


單 6. 接受 PUT 請求並建立或更新聯繫人

@PUT  
@Consumes(MediaType.APPLICATION_XML)  
public Response putContact(JAXBElement<Contact> jaxbContact) {  
    Contact c = jaxbContact.getValue();  
    return putAndGetResponse(c);  
}  
  
private Response putAndGetResponse(Contact c) {  
    Response res;  
    if(ContactStore.getStore().containsKey(c.getId())) {  
        res = Response.noContent().build();  
    } else {  
        res = Response.created(uriInfo.getAbsolutePath()).build();  
    }  
    ContactStore.getStore().put(c.getId(), c);  
    return res;  
}

我還在本示例中包含了許多不一樣的概念,重點強調如下概念:

  • Consume XML:putContact() 方法接受 APPLICATION/XML 請求類型,而這種輸入 XML 將使用 JAXB 綁定到 Contact 對象。您將在下一節中找到客戶端代碼。

  • 空響應帶有不一樣的狀態碼:PUT 請求的響應沒有任何內容,可是有不一樣的狀態碼。若是數據存儲庫中存在聯繫人,我將更新該聯繫人並返回 204/no content。若是沒有新聯繫人,我將建立一個並返回 201/created。

 

DELETE

實現 DELETE 方法很是簡單。示例請查看清單 7。

單 7. 刪除其 ID 肯定的聯繫人

@DELETE  
public void deleteContact() {  
    Contact c = ContactStore.getStore().remove(contact);  
    if(c==null)  
        throw new NotFoundException("No such Contact.");  
}

表示形式

在上一節中,我介紹了幾個表示形式類型。如今我將簡要瀏覽一遍並深刻探討 JAXB 表示形式。其餘受支持的表示形式有 byte[]、InputStream、File 等。

  • String:純文本。

  • Response:通常 HTTP 響應,包含帶有不一樣響應代碼的定製內容。

  • Void:帶有 204/no content 狀態碼的空響應。

  • Resource Class:將流程委託給該資源類。

  • POJO:使用 @XmlRootElement 註釋的 JavaBean,這讓它成爲一個 JAXB bean,能夠綁定到 XML。

  • POJO 集合:JAXB bean 集合。

JAX-RS 支持使用 JAXB (Java API for XML Binding) 將 JavaBean 綁定到 XML 或 JSON,反之亦然。JavaBean 必須使用 @XmlRootElement 註釋。清單 8 使用 Contact bean 做爲示例。沒有明確 @XmlElement 註釋的字段將包含一個名稱與之相同的 XML 元素。清單 9 顯示了用於一個 Contact bean 的序列化 XML 和 JSON 表示形式。聯繫人集合的表示形式與此相同,默認使用 <Contacts> 做爲包裝器元素。


單 8. Contact bean

@XmlRootElement  
public class Contact {  
    private String id;  
    private String name;  
    private List<Address> addresses;  
      
    public Contact() {}  
      
    public Contact(String id, String name, List<Address> addresses) {  
        this.id = id;  
        this.name = name;  
        this.addresses = addresses;  
    }  
  
    @XmlElement(name="address")  
    public List<Address> getAddresses() {  
        return addresses;  
    }  
  
    public void setAddresses(List<Address> addresses) {  
        this.addresses = addresses;  
    }  
    // Omit other getters and setters  
}

單 9. 一個 Contact 的表示形式

XML representation:

<contact>  
  <address>  
    <city>Shanghai</city>  
    <street>Long Hua Street</street>  
  </address>  
  <address>  
    <city>Shanghai</city>  
    <street>Dong Quan Street</street>  
  </address>  
  <id>huangyim</id>  
    <name>Huang Yi Ming</name>  
</contact>

JSON representation:

{"contact":[{"address":[{"city":"Shanghai","street":"Long  
            Hua Street"},{"city":"Shanghai","street":"Dong Quan  
            Street"}],"id":"huangyim","name":"Huang Yi Ming"}]}

 REST 服務通信的客戶端

在目前爲止的示例中,我開發了一個支持 CRUD 的 RESTful Web 服務。如今我開始解釋如何使用 curl,RestClient 和 Jersey 客戶端 API 與該 REST 服務通信。這樣一來,我能夠測試服務器端代碼,並介紹更多有關客戶端技術的信息。

 

使用 curl 與 REST 服務通信

Curl 是一個流行的命令行工具,能夠向使用 HTTP 和 HTTPS 協議的服務器發送請求。這是一個與 RESTful Web 服務通信的好工具,由於它能夠經過任何 HTTP 方法發送內容。Curl 已經在 Linux 和 Mac 中自帶了,而且有一個實用工具,能夠在 Windows® 平臺上進行安裝。

如今,咱們初始化獲取全部聯繫人的第一個 curl 命令。您能夠參考 清單 3 獲取服務器端代碼。

curl http://localhost:8080/Jersey/rest/contacts

響應將使用 XML 幷包含全部聯繫人。

注意,getContacts() 方法還生成一個 application/json MIME 類型響應。您還能夠請求該類型的內容。

curl –HAccept:application/json http://localhost:8080/Jersey/rest/contacts

響應將是一個包含全部聯繫人的 JSON 字符串。

如今,我將 PUT 一個新的聯繫人。注意,清單 6 中的 putContact() 方法接受 XML 並使用 JAXB 將 XML 綁定到 Contact 對象。

[html] view plaincopy

  1. curl -X PUT -HContent-type:application/xml --data "<contact><id>foo</id>  

  2.                 <name>bar</name></contact>" http://localhost:8080/Jersey/rest/contacts/foo  

一個經過 「foo」 識別的新聯繫人將添加到聯繫人存儲庫。您可使用 URI /contacts 或 /contacts/foo 驗證聯繫人集合或單個聯繫人。

 

使用 RestClient 與 REST 服務通信

RESTClient是一個用於測試RESTful Web services的Java客戶端,該工具的安裝請參考文章http://blog.csdn.net/zztfj/article/details/7588330

獲取全部聯繫人列表,並返回XML格式(默認格式)。



獲取全部聯繫人列表,並返回JSON格式。


 

 

使用 Jersey Client 與 REST 服務通信

Jersey 還提供了一個客戶端庫,幫助您與服務器通信並對 RESTful 服務進行單元測試。該庫是一個通常實現,能夠整合任何 HTTP/HTTPS-based Web 服務。

客戶端的核心類是 WebResource 類。您可使用該類根據根 URI 構建一個請求 URL,而後發送請求並獲取響應。清單 10 展現瞭如何建立 WebResource 實例。注意 WebResource 是一個大對象,所以只建立一次。


單 10. 建立 WebResource 實例

[java] view plaincopy

  1.                   

  2. Client c = Client.create();  

  3. WebResource r=c.resource("http://localhost:8080/Jersey/rest/contacts");  

第一個 Jersey 客戶端示例將發送 GET 請求獲取全部聯繫人並打印響應狀態碼和響應內容,參見清單 11。

單 11. GET 全部聯繫人並打印響應

[java] view plaincopy

  1. ClientResponse response = r.get(ClientResponse.class);  

  2. System.out.println( response.getStatus() );  

  3. System.out.println( response.getHeaders().get("Content-Type") );  

  4. String entity = response.getEntity(String.class);  

  5. System.out.println(entity);  


 

清單 12 展現了另外一個建立經過 「foo」 識別的新聯繫人的示例。


單 12. 建立一個聯繫人

[java] view plaincopy

  1. Address[] addrs = {  

  2.     new Address("Shanghai""Ke Yuan Street")  

  3. };  

  4. Contact c = new Contact("foo""Foo Bar", Arrays.asList(addrs));  

  5.   

  6. ClientResponse response = r  

  7.     .path(c.getId())  

  8.     .accept(MediaType.APPLICATION_XML)  

  9.     .put(ClientResponse.class, c);  

  10. System.out.println(response.getStatus());           

注意 WebResource 實例的 API。它構建 URI,設置請求頭,並在一行代碼中調用請求。內容(Contact 對象)將自動綁定到 XML。

清單 13 展現了檢索經過 「foo」 識別的聯繫人(已上一個示例中建立)的最後一個示例而後刪除該聯繫人。


單 13. 檢索 「foo」 聯繫人並刪除

[java] view plaincopy

  1. GenericType<JAXBElement<Contact>> generic = new GenericType<JAXBElement<Contact>>() {};  

  2. JAXBElement<Contact> jaxbContact = r  

  3.     .path("foo")  

  4.     .type(MediaType.APPLICATION_XML)  

  5.     .get(generic);  

  6. Contact contact = jaxbContact.getValue();  

  7. System.out.println(contact.getId() + ": " + contact.getName());  

  8.   

  9. ClientResponse response = r.path("foo").delete(ClientResponse.class);  

  10. System.out.println(response.getStatus());    


 

注意,當您想獲取 JAXB bean 響應時,您須要使用 Java 2 Platform, Standard Edition (J2SE) 中引入的範型特性。



Jersey jar庫文件的下載地址:http://download.csdn.net/detail/zztfj/4334371

本文的源代碼下載:http://download.csdn.net/detail/zztfj/4334425

相關文章
相關標籤/搜索