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

gww3 9年前發布 | 172K 次閱讀 RESTful WEB服務/RPC/SOA

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

RESTful Web 服務簡介

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

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

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

    </li>

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

    </li>

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

    </li> </ul>

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

     1. RESTful Web 服務示例

    方法/資源

    </td>

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

    </td>

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

    </td> </tr>

    GET

    </td>

    列出資源集合的所有成員。

    </td>

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

    </td> </tr>

    PUT

    </td>

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

    </td>

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

    </td> </tr>

    POST

    </td>

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

    </td>

    在下面創建一個子資源。

    </td> </tr>

    DELETE

    </td>

    刪除整個資源集合。

    </td>

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

    </td> </tr> </tbody> </table>


    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 服務。

      </li>

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

      </li>

    • 集成(Integration):Jersey 還提供可以輕松集成 Spring、Guice、Apache Abdera 的庫。

      </li> </ul>

       

      構建 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

        </li>

      • Java SE5 或更高版本

        </li>

      • Web 容器:Apache Tomcat 6.0(Jetty 和其他也可以)

        </li>

      • Jersey 庫:Jersey 1.0.3 歸檔,包含所有必需的庫

        </li> </ul>

         

        置 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

          </li>

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

          </li>

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

          </li>

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

          </li> </ul>

          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),可以實現任何接口。這增加了許多好處,比如可重用性和簡單。

            </li>

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

            </li>

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

          • @GET:這意味著以下方法可以響應 HTTP GET 方法。

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

          • </ul>

            部署到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 方法(如GET、POST、PUT 和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 類型。

            • </ul>

              您也許還注意到了,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。

                </li>

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

                </li> </ul>

                 

                方法

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

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

                  </li>

                • HTTP POST:新建資源。

                  </li>

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

                  </li>

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

                  </li> </ul>

                  因為我已經介紹過 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> 訪問新聯系人。

                  • </ul>

                     

                    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 對象。您將在下一節中找到客戶端代碼。

                      </li>

                    • 空響應帶有不同的狀態碼:PUT 請求的響應沒有任何內容,但是有不同的狀態碼。如果數據存儲庫中存在聯系人,我將更新該聯系人并返回 204/no content。如果沒有新聯系人,我將創建一個并返回 201/created。

                      </li> </ul>

                       

                      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:純文本。

                        </li>

                      • Response:一般 HTTP 響應,包含帶有不同響應代碼的定制內容。

                        </li>

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

                        </li>

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

                        </li>

                      • POJO:使用 @XmlRootElement 注釋的 JavaBean,這讓它成為一個 JAXB bean,可以綁定到 XML。

                        </li>

                      • POJO 集合:JAXB bean 集合。

                        </li> </ul>

                        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>  

                          </li>

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

                          </li> </ol>

                          一個通過 “foo” 識別的新聯系人將添加到聯系人存儲庫。您可以使用 URI /contacts 或 /contacts/foo 驗證聯系人集合或單個聯系人。

                           

                          使用 RestClient 與 REST 服務通訊

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

                          獲取所有聯系人列表,并返回XML格式(默認格式)。

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

                          獲取所有聯系人列表,并返回JSON格式。

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

                           

                           

                          使用 Jersey Client 與 REST 服務通訊

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

                          客戶端的核心類是 WebResource 類。您可以使用該類根據根 URI 構建一個請求 URL,然后發送請求并獲取響應。清單 10 展示了如何創建 WebResource 實例。注意 WebResource 是一個大對象,因此只創建一次。


                          單 10. 創建 WebResource 實例

                          [java] view plaincopy

                          1.                   

                            </li>

                          2. Client c = Client.create();  

                            </li>

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

                            </li> </ol>

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

                            單 11. GET 所有聯系人并打印響應

                            [java] view plaincopy

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

                              </li>

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

                              </li>

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

                              </li>

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

                              </li>

                            5. System.out.println(entity);  

                              </li> </ol>


                               

                              清單 12 展示了另一個創建通過 “foo” 識別的新聯系人的示例。


                              單 12. 創建一個聯系人

                              [java] view plaincopy

                              1. Address[] addrs = {  

                                </li>

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

                                </li>

                              3. };  

                                </li>

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

                                </li>

                              5.   

                                </li>

                              6. ClientResponse response = r  

                                </li>

                              7.     .path(c.getId())  

                                </li>

                              8.     .accept(MediaType.APPLICATION_XML)  

                                </li>

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

                                </li>

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

                                </li> </ol>

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

                                清單 13 展示了檢索通過 “foo” 識別的聯系人(已上一個示例中創建)的最后一個示例然后刪除該聯系人。


                                單 13. 檢索 “foo” 聯系人并刪除

                                [java] view plaincopy

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

                                  </li>

                                2. JAXBElement<Contact> jaxbContact = r  

                                  </li>

                                3.     .path("foo")  

                                  </li>

                                4.     .type(MediaType.APPLICATION_XML)  

                                  </li>

                                5.     .get(generic);  

                                  </li>

                                6. Contact contact = jaxbContact.getValue();  

                                  </li>

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

                                  </li>

                                8.   

                                  </li>

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

                                  </li>

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

                                  </li> </ol>


                                   

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


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

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

                                  </div>

                                   本文由用戶 gww3 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
                                   轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
                                   本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!
sesese色