长沙御溪国际租房:使用 RESTlet 框架开发符合 JSR311 规范标准的 REST Web Service

来源:百度文库 编辑:九乡新闻网 时间:2024/04/29 01:55:18
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 服务"来获取这方面的相关知识。
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 的 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 容器中。
回页首
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> getClasses() { Set> rrcs = new HashSet>(); 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"); } }
新建 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 容器中。
RESTlet Jax-RS extension Example org.restlet.application com.developerworks.jaxrs.resltet.example.JaxRsExtensionApplication RestletServlet com.noelios.restlet.ext.servlet.ServerServlet RestletJaxRsExtensionServlet /*
在实际的开发环境中,日志是一项非常重要的功能,好的日志对程序开发者快速定位问题的好帮手。RESTlet 架构中使用了 JDK 中自带的日志功能,用户额可以使用已经熟悉的方式配置日志,读写日志。有关日志的具体介绍可参见 java.util.logging。
基于 RESTlet JAX-RS Extension 的 Web Service 两种部署方式有着很高的相似性,从用户使用角度来看,几乎没有区别。本节中将以部署为单独的 Java 应用来示例运行结果。

在 JaxRsExtensionResource 资源类中,getUser() 方法被调用,返回对用户概念的说明。

在 JaxRsExtensionResource 资源类中,findUser() 方法被调用。该方法通过解析 URI 模板中的 ID 参数,获得用户想获得的用户信息。图 2 演示被请求的用户存在时,Web Service 返回该用户的信息。

在 JaxRsExtensionResource 资源类中,findUser() 方法被调用。该方法通过解析 URI 模板中的 ID 参数,获得用户想获得的用户信息。图 3 演示被请求的用户不存在时,Web Service 返回相应的不存在警告信息。

在 JaxRsExtensionResource 资源类中,getUserGroup() 方法被调用,返回对用户组概念的说明。

在 JaxRsExtensionResource 资源类中,findUserGroup() 方法被调用。该方法通过解析 URI 模板中的 ID 参数,获得用户想获得的用户组信息。图 5 演示被请求的用户组存在时,Web Service 返回该用户组的信息。

在 JaxRsExtensionResource 资源类中,findUserGroup() 方法被调用。该方法通过解析 URI 模板中的 ID 参数,获得用户想获得的用户组信息。图 6 演示被请求的用户组不存在时,Web Service 返回相应的不存在警告信息。
回页首
本文主要讨论了 JAX-RS 与 RESTlet 在架构方面的区别,以及 RESTlet 如何通过扩展实现对 JAX-RS 的兼容。在此基础之上,本文也以一个实例的方式,介绍了如何有效得使用 JAX-RS Extension 进行开发。无论是对于 RESTlet 的开发人员,或是对于习惯 POJO 方式的 REST 开发人员,都可以很方便的使用这一个技术。
回页首
描述名字大小下载方法
本文示例代码JAX-RSExample.zip10KBHTTP
关于下载方法的信息
学习
阅读 developerWorks 文章:“构建 RESTful Web 服务”。
阅读 developerWorks 文章:“使用 JAX-RS 简化 REST 应用开发”。
技术书店:浏览关于这些和其他技术主题的图书。
developerWorks Java 技术专区:数百篇关于 Java 编程各个方面的文章。
讨论
加入 My developerWorks 中文社区。
查看 developerWorks 博客 的最新信息。
周鹏,IBM 中国软件开发中心软件工程师,从事过三年 Mainframe 上系统软件的开发,一年 Director 6.1 在 IBM pSeries 的测试工作以及测试环境的维护工作。目前负责 Director 6.1 与其他产品,如 IBM Tivoli, HP OVO, CA NSM 等的集成开发工作。目前从事 Director 代理程序 REST 服务的设计和实现。
鲁宏勇,IBM 中国软件开发中心软件工程师,从事过两年 IBM System Director 上的测试工作。目前负责 Director 6.1 与其他产品,如 IBM Tivoli, HP OVO, CA NSM 等的集成开发工作。从事用以与 Director Server 通讯的 REST 客户端的设计和实现。