程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用RESTlet框架開發符合JSR311規范標准的REST Web Service

使用RESTlet框架開發符合JSR311規范標准的REST Web Service

編輯:關於JAVA

JSR311 作為 Java 實現 REST Web Service 的規范標准,盡管從出生起就備受爭議,但從事實上,已 經普遍被大多數 REST 實現框架的接受。這中間,既有 Sun 公司原產的 Jersey, 也有其他的開源項目, 如 Jboss 的 RESTEasy, Apache 的 CXF 等。當然,還有發展時間最長,相當成熟的 RESTlet 框架。

RESTlet 的主體核心是按照 Roy Thomas Fielding 的著作"Architectural Styles and the Design of Network-based Software Architectures"。結構清晰,穩定性強。但是該框架下的資源定義是有別於 JSR311 的那種 JAX-WS 風格的 annotation。這對於鐘愛 RESTlet 的 Web Service 開發人員,就面臨著 選擇陣營的風險。所幸的是,RESTlet 的領導開發人員 J é rome Louve 也是 JSR311 的參與者 , 這反 映在 RESTlet 1.1 提供了一個 Extension 來幫助 RESTlet 的開發人員編寫符合 JSR311 的 Web Service。某些企業級產品,如 IBM Systems Director 6.1.2, 已經在產品中使用這種技術。本文重點介 紹 JAX-RS extension 的基本實現結構以及如何利用該插件進行 JSR311 規范標准的 REST Service。

本文以 Neolies RESTlet 1.1.8 作為討論的基礎,並且假定讀者已經對 REST,JAX-RS 以及 RESTlet 有一定的理解。因此不會詳細討論相關的基本知識,讀者也可以通過閱讀"構建 RESTful Web 服務"來獲 取這方面的相關知識。

RESTlet 和 JSR-311

JAX-RS Annotation 簡介

@Path: 用來映射 URI,為資源類以及資源類中包含的方法提供訪問路徑。

@GET: 表示處理 HTTP GET 請求的資源類方法。當 Web Service 獲得客戶端發出的對與某個網絡資源 的 HTTP GET 操作時,服務器會調用被 @GET 注解後的方法來處理 GET 請求。當然,被調用的資源類方 法首先得滿足 URI。

@POST: 表示處理 HTTP POST 請求的資源類方法。和 @GET 相類似,只不過對應的是 HTTP POST 操作 。

@PUT: 表示處理 HTTP PUT 請求的資源類方法。該 Annotation 通常用於更新網絡對象的方法。和 @GET,@POST 處理流程相類似。

@DELETE: 表示處理 HTTP DELETE 請求的資源類方法。使用該 Annotation 後的方法通常是刪去每個 網絡對象的實例。處理流程和 @GET,@POST,@PUT 相類似。

@HEAD: 表示處理 HTTP HEAD 請求的資源類方法。通常情況下,根據 JAX-RS 規范的設定,在沒有實 現 @HEAD 的資源類方法時,RESTlet JAX-RS extension 會自動處理 HTTP HEAD 請求,@GET 注解的資源 類方法會自動被調用。和處理普通的 HTTP GET 請求的區別是沒有實例被返回。@HEAD 注解的資源類方法 通常用來獲取 Web Services 能夠接受的數據格式。

@Produces: 用來表示資源類方法能夠返回的 MIME 的媒體類型。

@Consumes: 用來表示資源類方法能夠處理的 MIME 的媒體類型。

Neolies RESTlet 設計風格上盡量遵循 Roy Fielding 博士論文中所闡述的 REST 的目標。從實現層 面上,Neolies RESTlet 可以分為三個部分:

RESTlet API: 這個部分設計了 RESTlet 的框架,包括在經典 REST 結構中所包括的 Application, Component,Route,Connector,VirtualHost, Resource 等,都在這個部分被詳細定義。

NRE(Noelios Restlet Engine):這個部分是對 RESTlet API 的參考實現,RESTlet API 通過代理模 式 (Delegation) 將具體的工作轉交到 NRE 中執行,如 RESTlet API 中的 Application 在 NRE 中的代 理就是 ApplicationHelper。

Extensions:這個部分是對 RESTlet API 的擴展(不依賴於 NRE)。包括 JAX-RS Extension,還有對 JSON 或是對 JAXB 的 Extensions。

JAX-RS 與 RESTlet API 的不同之處在於,在 RESTlet 下,REST 資源是結構化組織起來的,如 Component 可以包含多個 Application,Application 又可以包含多個 REST 資源,Component 到 Application,Application 到 REST 資源以 Route 來連接。這樣,從 URI 到 REST 資源的定位就自上 而下進行查找。JSR311 下,REST 資源是 POJO 並且非結構化的,資源對應的 URI 通過 Annotation 直 接在 POJO 類裡加以描述(這裡不討論 subresource 資源的定位)。相對來說,JAX-RS 描述能力簡單, 開發起來更加方便。JAX-RS 所定義的 REST 框架,包括:

Annotation:比如說在 HttpMethod 支持 @PUT,@POST,@DELETE,@GET 等等,或是 @QueryParam 可以 表示 GET 操作的查詢參數等等。這些 Annotation 在 REST 資源所在的 POJO 類裡被使用。

Application:JAX-RS 沒有定義 Component 或是 VirtualHost,只是用 Application 來存放所有的 REST 資源。

HTTP 協議基礎類:包括 CacheControl, Cookie 等等,這些類處理 HTTP 協議層的相關字段,這些類 的具體實現是以代理模式 (Delegation),通過 RuntimeDelegate 類來連接到具體實現的。

MessageBodyReader 和 MessageBodyWriter:這對接口的實現主要使用在 Provider。Provider 可以 用作 REST 相應體的序列化和反序列化。

RESTlet JAX-RS Extension 實現了 JAX-RS。主要的技術要點包括:

internal.Provider:JAX-RS Extension 通過 MessageBodyReader 和 MessageBodyWriter,實現了 InputStream,Jaxb,ByteArray 等 Provider 的序列化和反序列化。

internal.spi:JAX-RS Extension 實現了 HTTP 協議基礎類。

internal.exceptions:定義了 JAX-RS 拋出的異常。

JaxRsApplication:實現了 JAX-RS 的 Application 接口,並且包含 JaxRsRestlet。具體的工作是 在 JaxRsRestlet 中處理的。

JaxRsRestlet:包含了所有的 REST POJO 資源,在初始化時分析 REST 資源的 Annotation, 得到 REST 資源所對應的 URI,對應的接口以及其他相關信息。JaxRsRestlet 還包含了所有 Provider 的引用 和所有異常的引用。運行過程中,所有的 REST 請求被路由到 JaxRsRestlet,由該對象來選擇合適的 REST 資源及方法來進行處理。

RESTlet JAX-RS Extension 的配置

配置基於 RESTlet JAX-RS Extension 的 Web Service 也就是部署該架構下的 Web Service。 RESTlet 架構提供兩種部署 Web Service 的方式。兩種方式都方便簡單,用戶可以根據自己的需求選擇 任意一種部署方式。

將 Web Service 當做單獨的 Java 程序進行部署

將 Web Service 部署到 Servelet Container 中

兩種方式都方便簡單,用戶可以根據自己的需求選擇任意一種部署方式。

將 Web Service 部署成一個單獨運行的 Java 應用非常的簡單,只需要完成以下幾個步驟。

導入需要的 JAR 包,org.restlet.jar,以及 org.restlet.ext.jaxrs_1.0.jar。

為 HTTP Server 創建相應 Java 類。在新建的 Java 類中依次完成以下工作,引入 org.restlet.jar 包中需要的類,新建 HTTP Server,定義該 Server 監聽的端口,將 Web Service 的配置類加入到 HTTP 服務器中。

編譯運行 HTTP Server。

將基於 RESTlet Jax-Rs Extension 的 Web Service 部署到 Servelet Container 中的過程和部署一 個基本的 Servelet 極其相似。不同的是,部署過程中,用戶需要注意添加需要的 Jar 包。以下 Jar 是 該部署方式所需要的。

org.restlet.jar

org.restlet.ext.jaxrs_1.0.jar

com.noelios.restlet.jar

com.noelios.restlet.ext.servlet_2.5.jar

為了成功將基於 RESTlet Jax-Rs Extension 的 Web Service 部署為 Servelet,用戶需要完成以下 動作。

編譯基於 RESTlet Jax-Rs Extension 的 Web Service 包含的代碼。

將需要的 JAR 包存放於 /WEB-INF/lib 中。

創建 Servelet 的配置文件 web.xml。

將所有相關內容打包成 WAR 包,並部署到用戶選定的 Servelet 容器中。

在 RESTlet 架構下實現 JAX-RS Web Service 示例

JAX-RS Extension 是在 RESTlet 架構下的對 JAX-RS:Java API for RESTful Web Services 的實現 。本段將通過實例說明如何使用 JAX-RS 提供的接口實現 RESTlet 架構下的 Web Service。在正式介紹 實例之前,先對實例的應用環境進行簡單的分析。本文以一個簡單的用戶管理功能為基礎介紹如何在 RESTlet 架構下實現 JAX-RS Web Service。實例中的用戶管理功能主要包括用戶組和用戶兩個對象,使 用者可以通過調用 PUT 操作添加新的用戶組和用戶,GET 操作則可以用來獲取已存在用戶組和用戶的信 息,用戶組和用戶的刪除則通過 Delete 操作來實現。為了簡單起見,本實例僅提供 GET 操作的實現, POST 操作和 Delete 操作只需要按照 REST 架構類似的實現就可以。本例相關的 URI 實現。

/users/usergroup:請求用戶組的介紹。

/users/usergroup/{id}: 請求特定的用戶組信息。

/users/user: 請求用戶對象的相關介紹。

/users/user/{id}: 請求特定用戶對象的相關信息。

對需求分析結束後,我們將開始實現該過程主要可以分為三個步驟。

提供資源類,實現需要支持的操作

根據需求創建應用配置類

建立 JAX-RS 服務器,部署實例

創建資源類

首先需要創建一個 JAVA 類命名為 JaxRsExtensionResource,通過 @GET 的使用,將不同的 HTTP GET 請求映射到資源類方法中。@Path 的使用將 URI 與相應的資源類以及資源方法相結合。例如, @Path("users") 將 URI /users/ 和 ExampleResource 類相關聯,Path("user/{id}") 將 URI /users/user/{id} 與 ExampleResource 的 findUser(...) 方法相關聯。User 類是對用戶的抽象, UserGroup 是對用戶組的抽象。UserManager 類負責 User 實例的管理,相應 UserGroupManager 類負責 UserGroup 實例的管理。

package com.developerworks.jaxrs.resltet.example;

  import java.util.ArrayList;
  import java.util.List;

  import javax.ws.rs.*;

  @Path("users")
  public class JaxRsExtensionResource {

   @GET
   @Path("usergroup")
   public String getUserGroup() {
     return "Group are used to classify different kind of users!";
   }

   @GET
   @Path("user")
   public String getUser(){
   return "Users inlcudes the information of registered user!";
   }

   @GET
   @Path("user/{id}")
   public String findUser(@PathParam("id") String id){
    User temp = UserManager.get().getDetails(id);
    if(temp != null)
     return temp.toString();
    else
     return "The user you queried(ID:" + id + ") doesn't existed!";
   }

   @GET
   @Path("usergroup/{id}")
   public String findUserGroup(@PathParam("id") String id){
    UserGroup group = UserGroupManager.get().getDetails(id);
    if(group != null)
     return group.toString();
    else
     return "The group you queried(ID:" + id + ") doesn't existed!";
   }

  }

創建應用類

RESTlet 架構中的應用類主要用來初始化 Web Service 的運行環境。Restlet 為了方便使用者,提供 了很多可以方便使用的基本功能, 用戶通過自己定義的應用類來選擇使用需要的功能。這些基本功能包 括為客戶端和服務器端提供必要的鏈接,編碼解碼功能,元數據,狀態包裝等。本例不涉及到這些功能, 所有有關這些功能的說明及使用方法,請參閱 RESTlet 手冊。在本例中,我們只需將上節定義的資源類 加入即可。

package com.developerworks.jaxrs.resltet.example;

  import java.util.HashSet;
  import java.util.Set;
  import javax.ws.rs.core.*;

  public class ExampleApplication extends Application {

   public Set<Class<?>> getClasses() {
     Set<Class<?>> rrcs = new HashSet<Class<?>>();
     rrcs.add(JaxRsExtensionResource.class);
     return rrcs;
   }
  }

RESTlet 架構為了更好的支持 JAX-RS 規范,定了 JaxRsApplication 類來初始化基於 JAX-RS 的 Web Service 運行環境。JaxRSApplication 類使用起來非常的方便,只需要將原本基於 RESTlet 架構的 應用類加入到用戶自己實現的 JaxRsApplication 子類中即可。如果需要認證功能的話,使用 JaxRsApplication 的 setGuard(...) 或者 setAuthentication(...) 方法即可。本例中不設置到認證功 能,所以只需要將 ExampleApplication 類加入到本例實現 JaxRsApplication 子類中即可。

package com.developerworks.jaxrs.resltet.example;

  import org.restlet.Context;
  import org.restlet.ext.jaxrs.JaxRsApplication;

  public class JaxRsExtensionApplication extends JaxRsApplication {

   public JaxRsExtensionApplication(Context context) {
     super(context);
     this.add(new ExampleApplication());
   }

   public static void main(){
    System.out.println("Hello");
   }
  }

部署 Web Service

新建 Java 類,命名為 JaxRsExtensionServer, 在該類中創建一個新的 Http Server,並為該 Http Server 添加監聽端口,本例使用 8182 端口。將上面創建的 Web Service 運行環境配置類 JaxRsExtensionApplication 加入到 Http Server 中。

package com.developerworks.jaxrs.resltet.example;

  import org.restlet.Component;
  import org.restlet.data.Protocol;

  public class JaxRsExtensionServer {
    public static void main(String[] args){
      try{
        Component component = new Component();
        component.getServers().add(Protocol.HTTP, 8182);
        component.getDefaultHost().attach(new JaxRsExtensionApplication (null));
        component.start();
      }catch(Exception e){
        e.printStackTrace();
      }
    }
  }

將基於 RESTlet Jax-Rs Extension 的 Web Service 部署到 Servelet Container 中的過程和部署一 個基本的 Servelet 極其相似。不同的是,部署過程中,用戶需要注意添加需要的 Jar 包。然後,創建 Servelet 的配置文件 web.xml。下面是為本例所寫的配置文件。最後用戶需要將這些一起打包成 WAR 包 ,並部署到用戶選定的 Servelet 容器中。

<?xml version="1.0" encoding="UTF-8"?>
  <web-app id="WebApp_ID" version="2.4"
       xmlns="http://java.sun.com/xml/ns/j2ee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
          http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
   <display-name>RESTlet Jax-RS extension Example</display-name>
   <!-- Application class name -->
   <context-param>
    <param-name>org.restlet.application</param-name>
    <param-value>
      com.developerworks.jaxrs.resltet.example.JaxRsExtensionApplication
    </param-value>
   </context-param>

   <!-- Restlet adapter -->
   <servlet>
    <servlet-name>RestletServlet</servlet-name>
    <servlet-class>
      com.noelios.restlet.ext.servlet.ServerServlet
    </servlet-class>
   </servlet>

   <!-- Catch all requests -->
   <servlet-mapping>
    <servlet-name>RestletJaxRsExtensionServlet</servlet-name>
    <url-pattern>/*</url-pattern>
   </servlet-mapping>
  </web-app>

在實際的開發環境中,日志是一項非常重要的功能,好的日志對程序開發者快速定位問題的好幫手。 RESTlet 架構中使用了 JDK 中自帶的日志功能,用戶額可以使用已經熟悉的方式配置日志,讀寫日志。

運行結果

基於 RESTlet JAX-RS Extension 的 Web Service 兩種部署方式有著很高的相似性,從用戶使用角度 來看,幾乎沒有區別。本節中將以部署為單獨的 Java 應用來示例運行結果。

圖 1. 用戶在浏覽器中輸入 http://<ServerIP>:8182/users/user 後通過 HTTP GET 請求獲得 的結果

在 JaxRsExtensionResource 資源類中,getUser() 方法被調用,返回對用戶概念的說明。

圖 2. 用戶在浏覽器中輸入 http://<ServerIP>:8182/users/user/2 後通過 HTTP GET 請求獲 得的結果

在 JaxRsExtensionResource 資源類中,findUser() 方法被調用。該方法通過解析 URI 模板中的 ID 參數,獲得用戶想獲得的用戶信息。圖 2 演示被請求的用戶存在時,Web Service 返回該用戶的信息。

圖 3. 用戶在浏覽器中輸入 http://<ServerIP>:8182/users/user/3 後通過 HTTP GET 請求獲 得的結果

在 JaxRsExtensionResource 資源類中,findUser() 方法被調用。該方法通過解析 URI 模板中的 ID 參數,獲得用戶想獲得的用戶信息。圖 3 演示被請求的用戶不存在時,Web Service 返回相應的不存在 警告信息。

圖 4. 用戶在浏覽器中輸入 http://<ServerIP>:8182/users/usergroup 後通過 HTTP GET 請 求獲得的結果

在 JaxRsExtensionResource 資源類中,getUserGroup() 方法被調用,返回對用戶組概念的說明。

圖 5. 用戶在浏覽器中輸入 http://<ServerIP>:8182/users/usergroup/1 後通過 HTTP GET 請求獲得的結果

在 JaxRsExtensionResource 資源類中,findUserGroup() 方法被調用。該方法通過解析 URI 模板中 的 ID 參數,獲得用戶想獲得的用戶組信息。圖 5 演示被請求的用戶組存在時,Web Service 返回該用 戶組的信息。

圖 6. 用戶在浏覽器中輸入 http://<ServerIP>:8182/users/usergroup/2 後通過 HTTP GET 請求獲得的結果

在 JaxRsExtensionResource 資源類中,findUserGroup() 方法被調用。該方法通過解析 URI 模板中 的 ID 參數,獲得用戶想獲得的用戶組信息。圖 6 演示被請求的用戶組不存在時,Web Service 返回相 應的不存在警告信息。

結論

本文主要討論了 JAX-RS 與 RESTlet 在架構方面的區別,以及 RESTlet 如何通過擴展實現對 JAX-RS 的兼容。在此基礎之上,本文也以一個實例的方式,介紹了如何有效得使用 JAX-RS Extension 進行開發 。無論是對於 RESTlet 的開發人員,或是對於習慣 POJO 方式的 REST 開發人員,都可以很方便的使用 這一個技術。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved