JSR311 作為 Java 實現(xiàn) REST Web Service 的規(guī)范標準,盡管從出生起就備受爭議,但從事實上,已經(jīng)普遍被大多數(shù) REST 實現(xiàn)框架的接受。這中間,既有 Sun 公司原產(chǎn)的 Jersey, 也有其他的開源項目,如 Jboss 的 RESTEasy, Apache 的 CXF 等。當然,還有發(fā)展時間最長,相當成熟的 RESTlet 框架。
RESTlet 的主體核心是按照 Roy Thomas Fielding 的著作"Architectural Styles and the Design of Network-based Software Architectures"。結(jié)構(gòu)清晰,穩(wěn)定性強。但是該框架下的資源定義是有別于 JSR311 的那種 JAX-WS 風(fēng)格的 annotation。這對于鐘愛 RESTlet 的 Web Service 開發(fā)人員,就面臨著選擇陣營的風(fēng)險。所幸的是,RESTlet 的領(lǐng)導(dǎo)開發(fā)人員 J é rome Louve 也是 JSR311 的參與者 , 這反映在 RESTlet 1.1 提供了一個 Extension 來幫助 RESTlet 的開發(fā)人員編寫符合 JSR311 的 Web Service。某些企業(yè)級產(chǎn)品,如 IBM Systems Director 6.1.2, 已經(jīng)在產(chǎn)品中使用這種技術(shù)。本文重點介紹 JAX-RS extension 的基本實現(xiàn)結(jié)構(gòu)以及如何利用該插件進行 JSR311 規(guī)范標準的 REST Service。
本文以 Neolies RESTlet 1.1.8 作為討論的基礎(chǔ),并且假定讀者已經(jīng)對 REST,JAX-RS 以及 RESTlet 有一定的理解。因此不會詳細討論相關(guān)的基本知識,讀者也可以通過閱讀"構(gòu)建 RESTful Web 服務(wù)"來獲取這方面的相關(guān)知識。
Neolies RESTlet 設(shè)計風(fēng)格上盡量遵循 Roy Fielding 博士論文中所闡述的 REST 的目標。從實現(xiàn)層面上,Neolies RESTlet 可以分為三個部分:
JAX-RS 與 RESTlet API 的不同之處在于,在 RESTlet 下,REST 資源是結(jié)構(gòu)化組織起來的,如 Component 可以包含多個 Application,Application 又可以包含多個 REST 資源,Component 到 Application,Application 到 REST 資源以 Route 來連接。這樣,從 URI 到 REST 資源的定位就自上而下進行查找。JSR311 下,REST 資源是 POJO 并且非結(jié)構(gòu)化的,資源對應(yīng)的 URI 通過 Annotation 直接在 POJO 類里加以描述(這里不討論 subresource 資源的定位)。相對來說,JAX-RS 描述能力簡單,開發(fā)起來更加方便。JAX-RS 所定義的 REST 框架,包括:
RESTlet JAX-RS Extension 實現(xiàn)了 JAX-RS。主要的技術(shù)要點包括:
配置基于 RESTlet JAX-RS Extension 的 Web Service 也就是部署該架構(gòu)下的 Web Service。RESTlet 架構(gòu)提供兩種部署 Web Service 的方式。兩種方式都方便簡單,用戶可以根據(jù)自己的需求選擇任意一種部署方式。
兩種方式都方便簡單,用戶可以根據(jù)自己的需求選擇任意一種部署方式。
將 Web Service 部署成一個單獨運行的 Java 應(yīng)用非常的簡單,只需要完成以下幾個步驟。
將基于 RESTlet Jax-Rs Extension 的 Web Service 部署到 Servelet Container 中的過程和部署一個基本的 Servelet 極其相似。不同的是,部署過程中,用戶需要注意添加需要的 Jar 包。以下 Jar 是該部署方式所需要的。
為了成功將基于 RESTlet Jax-Rs Extension 的 Web Service 部署為 Servelet,用戶需要完成以下動作。
在 RESTlet 架構(gòu)下實現(xiàn) JAX-RS Web Service 示例
JAX-RS Extension 是在 RESTlet 架構(gòu)下的對 JAX-RS:Java API for RESTful Web Services 的實現(xiàn)。本段將通過實例說明如何使用 JAX-RS 提供的接口實現(xiàn) RESTlet 架構(gòu)下的 Web Service。 在正式介紹實例之前,先對實例的應(yīng)用環(huán)境進行簡單的分析。本文以一個簡單的用戶管理功能為基礎(chǔ)介紹如何在 RESTlet 架構(gòu)下實現(xiàn) JAX-RS Web Service。實例中的用戶管理功能主要包括用戶組和用戶兩個對象,使用者可以通過調(diào)用 PUT 操作添加新的用戶組和用戶,GET 操作則可以用來獲取已存在用戶組和用戶的信息,用戶組和用戶的刪除則通過 Delete 操作來實現(xiàn)。為了簡單起見,本實例僅提供 GET 操作的實現(xiàn),POST 操作和 Delete 操作只需要按照 REST 架構(gòu)類似的實現(xiàn)就可以。本例相關(guān)的 URI 實現(xiàn)。
對需求分析結(jié)束后,我們將開始實現(xiàn)該過程主要可以分為三個步驟。
首先需要創(chuàng)建一個 JAVA 類命名為 JaxRsExtensionResource,通過 @GET 的使用,將不同的 HTTP GET 請求映射到資源類方法中。@Path 的使用將 URI 與相應(yīng)的資源類以及資源方法相結(jié)合。例如, @Path("users") 將 URI /users/ 和 ExampleResource 類相關(guān)聯(lián),Path("user/{id}") 將 URI /users/user/{id} 與 ExampleResource 的 findUser(...) 方法相關(guān)聯(lián)。User 類是對用戶的抽象,UserGroup 是對用戶組的抽象。UserManager 類負責(zé) User 實例的管理,相應(yīng) UserGroupManager 類負責(zé) 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 架構(gòu)中的應(yīng)用類主要用來初始化 Web Service 的運行環(huán)境。Restlet 為了方便使用者,提供了很多可以方便使用的基本功能, 用戶通過自己定義的應(yīng)用類來選擇使用需要的功能。這些基本功能包括為客戶端和服務(wù)器端提供必要的鏈接,編碼解碼功能,元數(shù)據(jù),狀態(tài)包裝等。本例不涉及到這些功能,所有有關(guān)這些功能的說明及使用方法,請參閱 RESTlet 手冊。在本例中,我們只需將上節(jié)定義的資源類加入即可。
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 架構(gòu)為了更好的支持 JAX-RS 規(guī)范,定了 JaxRsApplication 類來初始化基于 JAX-RS 的 Web Service 運行環(huán)境。JaxRSApplication 類使用起來非常的方便,只需要將原本基于 RESTlet 架構(gòu)的應(yīng)用類加入到用戶自己實現(xiàn)的 JaxRsApplication 子類中即可。如果需要認證功能的話,使用 JaxRsApplication 的 setGuard(...) 或者 setAuthentication(...) 方法即可。本例中不設(shè)置到認證功能,所以只需要將 ExampleApplication 類加入到本例實現(xiàn) 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"); } } |
新建 Java 類,命名為 JaxRsExtensionServer, 在該類中創(chuàng)建一個新的 Http Server,并為該 Http Server 添加監(jiān)聽端口,本例使用 8182 端口。將上面創(chuàng)建的 Web Service 運行環(huán)境配置類 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 包。然后,創(chuàng)建 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> |
在實際的開發(fā)環(huán)境中,日志是一項非常重要的功能,好的日志對程序開發(fā)者快速定位問題的好幫手。RESTlet 架構(gòu)中使用了 JDK 中自帶的日志功能,用戶額可以使用已經(jīng)熟悉的方式配置日志,讀寫日志。有關(guān)日志的具體介紹可參見 java.util.logging。
基于 RESTlet JAX-RS Extension 的 Web Service 兩種部署方式有著很高的相似性,從用戶使用角度來看,幾乎沒有區(qū)別。本節(jié)中將以部署為單獨的 Java 應(yīng)用來示例運行結(jié)果。
在 JaxRsExtensionResource 資源類中,getUser() 方法被調(diào)用,返回對用戶概念的說明。
在 JaxRsExtensionResource 資源類中,findUser() 方法被調(diào)用。該方法通過解析 URI 模板中的 ID 參數(shù),獲得用戶想獲得的用戶信息。圖 2 演示被請求的用戶存在時,Web Service 返回該用戶的信息。
在 JaxRsExtensionResource 資源類中,findUser() 方法被調(diào)用。該方法通過解析 URI 模板中的 ID 參數(shù),獲得用戶想獲得的用戶信息。圖 3 演示被請求的用戶不存在時,Web Service 返回相應(yīng)的不存在警告信息。
在 JaxRsExtensionResource 資源類中,getUserGroup() 方法被調(diào)用,返回對用戶組概念的說明。
在 JaxRsExtensionResource 資源類中,findUserGroup() 方法被調(diào)用。該方法通過解析 URI 模板中的 ID 參數(shù),獲得用戶想獲得的用戶組信息。圖 5 演示被請求的用戶組存在時,Web Service 返回該用戶組的信息。
在 JaxRsExtensionResource 資源類中,findUserGroup() 方法被調(diào)用。該方法通過解析 URI 模板中的 ID 參數(shù),獲得用戶想獲得的用戶組信息。圖 6 演示被請求的用戶組不存在時,Web Service 返回相應(yīng)的不存在警告信息。
本文主要討論了 JAX-RS 與 RESTlet 在架構(gòu)方面的區(qū)別,以及 RESTlet 如何通過擴展實現(xiàn)對 JAX-RS 的兼容。在此基礎(chǔ)之上,本文也以一個實例的方式,介紹了如何有效得使用 JAX-RS Extension 進行開發(fā)。無論是對于 RESTlet 的開發(fā)人員,或是對于習(xí)慣 POJO 方式的 REST 開發(fā)人員,都可以很方便的使用這一個技術(shù)。
描述 | 名字 | 大小 | 下載方法 |
---|---|---|---|
本文示例代碼 | JAX-RSExample.zip | 10KB | HTTP |
學(xué)習(xí)
討論