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 服务"来获取这方面的相关知识。
Neolies RESTlet 设计风格上尽量遵循 Roy Fielding 博士论文中所阐述的 REST 的目标。从实现层面上,Neolies RESTlet 可以分为三个部分:
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 框架,包括:
RESTlet JAX-RS Extension 实现了 JAX-RS。主要的技术要点包括:
配置基于 RESTlet JAX-RS Extension 的 Web Service 也就是部署该架构下的 Web Service。RESTlet 架构提供两种部署 Web Service 的方式。两种方式都方便简单,用户可以根据自己的需求选择任意一种部署方式。
两种方式都方便简单,用户可以根据自己的需求选择任意一种部署方式。
将 Web Service 部署成一个单独运行的 Java 应用非常的简单,只需要完成以下几个步骤。
将基于 RESTlet Jax-Rs Extension 的 Web Service 部署到 Servelet Container 中的过程和部署一个基本的 Servelet 极其相似。不同的是,部署过程中,用户需要注意添加需要的 Jar 包。以下 Jar 是该部署方式所需要的。
为了成功将基于 RESTlet Jax-Rs Extension 的 Web Service 部署为 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 实现。
对需求分析结束后,我们将开始实现该过程主要可以分为三个步骤。
首先需要创建一个 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"); } } |
新建 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 中自带的日志功能,用户额可以使用已经熟悉的方式配置日志,读写日志。有关日志的具体介绍可参见 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.zip | 10KB | HTTP |
学习
讨论
联系客服