RESTful Web 服务和 Apache Wink,第 1 部分: 构建 Apache Wink REST 服务

RESTful 服务开发的具体细节

本文是三篇系列文章的第一篇,讨论 Apache Wink 1.0 的基本知识,这种新的 Java™ 框架用于实现和消费基于 REST 的 Web 服务。

Vishnu Vettrivel, 首席顾问, PunditLabs Inc.

http://www.ibm.com/developerworks/i/p-vvettrivel.jpgVishnu Vettrivel 是 PunditLabs 的主要顾问,致力于企业咨询和技术,他在构建、设计和开发任务关键性企业应用程序方面有多年的工作经验。他与《财富》50 强客户有广泛的工作接触,并针对许多新兴技术帮助员工制订战略技术规划。



2010 年 5 月 13 日

本文讨论 Apache Wink 1.0 框架的架构,解释一个示例 Apache Wink RESTful 服务的设计、实现和部署。本文还帮助您了解 REST 范型的基本知识,解释新的 JAX-RS 1.0 标准,从而帮助 Java 开发人员使用注释实现 RESTful Web 服务。

常用缩写词

  • API:应用程序编程接口(Application programming interface)
  • CSV:逗号分隔值(Comma-separated values)
  • HTML:超文本标记语言(Hypertext Markup Language)
  • HTTP:超文本传输协议(Hypertext Transfer Protocol)
  • JSON:JavaScript™ Object Notation
  • OOP:面向对象编程(Object-oriented programming)
  • REST:具象状态传输(Representational State Transfer)
  • RSS:真正简单的聚合(Really Simple Syndication)
  • URI:统一资源标识符(Uniform Resource Identifier)
  • WAR:Web archive
  • WSDL:Web 服务描述语言(Web Services Description Language)
  • XML:可扩展标记语言(Extensible Markup Language)

REST 概述

首先简要介绍一下 REST。REST 代表 Representational State Transfer,它是 World Wide Web 所依赖的一套架构原则。Roy Fielding 在他的博士论文 “Architectural Styles and the Design of Network-based Software Architectures” 中首次提出了这个概念。在他的论文中,Fielding 明确指出 REST 和 World Wide Web 的五个架构原则:

  • 可寻址性(Addressability)。REST 中的所有东西都基于资源 的概念。资源与 OOP 中的对象或其他名词不同,它是一种抽象,必须可以通过 URI 寻址或访问。
  • 接口一致性(Interface uniformity)。与 SOAP 或其他标准不同,REST 要求用来操纵资源的方法或动词不是任意的。这意味着 RESTful 服务的开发人员只能使用 HTTP 支持的方法,比如 GETPUTPOSTDELETE 等等。因此不需要使用 WSDL 等服务描述语言。
  • 无状态(Statelessness)。为了增强可伸缩性,服务器端不存储客户机的状态信息。这使服务器不与特定的客户机相绑定,负载平衡变得简单多了。这还让服务器更容易监视、更可靠。
  • 具象(Representational)。客户机总是与资源的某种具象交互,绝不会直接与资源本身交互。同一资源还可以有多个具象。理论上说,持有资源的具象的任何客户机应该有操纵底层资源的足够信息。
  • 连通性(Connectedness)。任何基于 REST 的系统都应该预见到客户机需要访问相关的资源,应该在返回的资源具象中包含这些资源。例如,可以以超链接的形式包含特定 RESTful 服务的操作序列中的相关步骤,让客户机可以根据需要访问它们。

JAX-RS

Web 上的 REST

以下站点当前正在使用 REST:

  • Atom Publishing Protocol。Atom 是 REST 协议最正规的实现之一,广泛用于博客发布领域。
  • Sun 的 Cloud API。这是 Sun 的 RESTful API,用于管理和创建计算、连网和存储元素等云资源。
  • Digg 的 API。Digg 是一个流行的社交网站,它使用 RESTful API 让用户和合作伙伴能够以编程方式与站点和数据交互。
  • Netflix API。Netflix 是一个 DVD 出租网站,它使用 RESTful API 提供对影片目录的细粒度访问,以及以编程方式调整用户队列和获取影片推荐。
  • Flickr API。Flickr 是一个照片上传网站,用户可以使用它提供的 RESTful API 上传、更换和搜索照片和像册。

为什么需要另一个 Java 标准?定义 JAX-RS 这个新规范是为了简化基于 REST 的 Java 开发。它主要关注使用 Java 注释和普通旧式 Java 对象 (POJO) 实现 RESTful 服务。尽管总是可以使用 servlet 实现 RESTful 服务,但是以这种方式实现业务逻辑需要太多 HTTP GET 请求。

JAX-RS 隐藏所有 HTTP 并把 servlet 绑定到 Java 类中的各个方法。注释还可以动态地提取 HTTP 请求中的信息,以及把应用程序生成的异常映射到 HTTP 响应码。由于这些原因,JAX-RS 是一种实现 RESTful Java Web 服务的有效方法。


Apache Wink 和 REST

我已经介绍了 REST 和 JAX-RS,现在开始讨论 Apache Wink。Apache Wink 1.0 是一个从头设计的完全兼容的 JAX-RS 1.0 规范实现。它很容易使用和应用于生产环境,它提供的特性可以增强核心 JAX-RS 规范。

Apache Wink 运行时架构是 JAX-RS 1.0 规范的简单实现。Apache Wink 部署在 Java Platform, Enterprise Edition (Java EE) 环境中,由以下三个组件组成:

  • Apache Wink RestServletRestServlet 在 Web 应用程序的 Java EE web.xml 描述符文件中配置。这个 servlet 作为所有 HTTP Web 服务请求的主入口点,它把请求和响应对象实例分派给请求处理器进行进一步处理。
  • 请求处理器。RequestProcessor 是核心 Apache Wink 引擎,它由 Apache Wink RestServlet 初始化。请求处理器使用请求 URI 寻找、匹配和调用相应的资源类和方法。在请求处理期间发生的任何异常都会导致 RequestProcessor 调用 Error Handler Chain 以处理异常。
  • 资源。在 REST 中,代表 Web 服务的任何组件或对象都被称为资源。资源允许通过它的许多具象之一获取和操纵数据。实现资源的 POJO 被称为资源类。资源类进一步实现资源方法,资源方法实际处理底层业务逻辑。

整个请求周期被称为 Apache Wink 逻辑流,见 图 1

图 1. Apache Wink 逻辑流
显示逻辑流的图。数据在请求处理器、Apache Wink 运行时、Apache Wink REST servlet、HTTP 客户机以及资源和应用程序代码之间流动

Apache Wink 不但帮助实现 RESTful Web 服务,而且提供一个强大的客户机库,可以使用它轻松地消费 RESTful 服务。最后,Apache Wink 附带一组内置的提供者,它们帮助开发人员支持多种行业标准的数据格式:XML、Atom、RSS、JSON、CSV 和 HTML。


RESTful 设计

现在该实践一下了。为了保持趣味性,我们要在 Apache Wink 1.0 上设计、实现和部署一个不太简单的 RESTful 服务。这个服务是 PayPal Payflow 支付网关服务的 RESTful 包装器,它可以通过 Internet 进行信用卡处理。但是,对于这个示例,我们只关注它的交易查询功能。只要提供一个属于经过身份验证的用户的惟一 ID,这个功能可以查询任何交易的状态。


资源/URI 设计

首先定义服务的接口模型并给它分配 URI,这使服务成为 REST 中的资源。因为这个服务的功能是提供交易状态,可以公开 清单 1 所示的 URI。

清单 1. 交易服务的 URI 模式
/transactions
/transactions{id}

/transactions URI 表示系统中的所有交易。使用 /transactions{id} 查询某一交易的状态。{id} 代表对应于交易模型的交易 ID 的惟一字母数字值。另外,使用 清单 2 中的模式验证用户的身份,其中的 UNAMEVNAMEPNAMEPWD 是在注册时分配给商人的 Payflow 网关登录凭证的组成部分。

清单 2. 在查询字符串中包含用户凭证的 URI 模式
/transactions{id}?user=UNAME&vendor=VNAME&partner=PNAME&pwd=PWD

数据设计

每个 RESTful 接口必须决定支持它的客户机使用哪种具象。Apache Wink 1.0 可以支持 XML、JSON、HTML 和 Atom 等,这个示例使用 JSON,因为这是一种流行的格式,而且 Ajax 应用程序很容易使用 JavaScript 代码。清单 3 是一个采用 JSON 格式的交易状态示例。

清单 3. JSON 字符串形式的交易状态响应
{
 "RESULT":19,"PNREF":"V19A2A1A7CC5",
 "RESPMSG":"Original transaction ID not found: V19A2A192BE9",
 "AUTHCODE":null,"CVV2MATCH":null,"AVSADDR":null,
 "AVSZIP":null,"IAVS":null,"CARDSECURE":null
}

HTTP 方法设计

最后,必须决定使用哪些 HTTP 方法操作资源及其功能。一定要坚持这些 HTTP 方法的正规用法,不要偏离规范。例如,GET 应该是安全的只读幂等(idempotent)调用,它不应该以任何方式更改资源的状态。违反这条原则会增加复杂性,给客户机带来混乱。在这个示例中,因为希望对单一交易的状态执行只读查询,显然应该使用 GET 方法,使用的 URI 模式见 清单 4

清单 4. 交易服务示例 URI 模式
/transactions{id}

每个 GET 调用返回一个 JSON 格式的字符串,这是查询的交易的状态数据,见 清单 5

清单 5. 包含交易 ID 的 GET 请求
GET /transactions/V19A2A192BE9 HTTP/1.1

但是,这种查询交易状态的模型有一个问题:服务无法验证查询交易的用户是否确实是交易的所有者。为了解决这个问题,允许客户机在 URI 中作为查询参数传递登录凭证,见 清单 6

清单 6. 在查询字符串中包含安全凭证的 GET 请求
GET /transactions/V19A2A192BE9?user=winktest&vendor=winktest
    &partner=PayPal&pwd=wink123
HTTP/1.1

Apache Wink 服务实现

Apache Wink 服务实现为 POJO(即普通的 Java 类),它使用 JAX-RS 注释把 HTTP 请求映射到 Java 方法。在默认情况下,服务可以是单实例的,也可以为每个请求创建服务实例。在这个示例中,通过创建 TransactionResource 类实现 Apache Wink RESTful 服务。它解析状态查询请求,验证用户凭证,调用 Payflow 网关服务,然后以 JSON 对象的形式返回交易的状态。清单 7 给出 TransactionResource 类的代码片段。

清单 7. Apache Wink 服务 Java 类片段
package org.openengine.wink.example.payflow;
	import ...;
	
	@Path("/transactions")
	public class TransactionResource {   
	
	@GET
	@Path("{pnref}")
	@Produces(MediaType.APPLICATION_JSON)
	public JSONObject doInquiry(@PathParam("pnref") String pnref,  
				@QueryParam("user") String userName, 
				@QueryParam("vendor") String vendorName, 
				@QueryParam("partner") String partnerName,
				@QueryParam("pwd") String password) {
		try {
			return getTxnStatus(pnref, 
		userName, vendorName, 
		partnerName, password);
	
		} catch (JSONException e) {
		throw new WebApplicationException
		(Response.Status.INTERNAL_SERVER_ERROR);
		}
	} 
	....

@javax.ws.rs.Path 注释指出这个类是 JAX-RS 服务。所有 JAX-RS 服务都需要这个注释。@Path 注释的值 /transactions 指出交易服务的 URI 的相对路径。

@GET 注释指出这个方法本身映射到的 HTTP 动词。方法级 @Path 注释的值相对于主 URI 指定子根。方法级 @Path@PathParam 中的 {pnref} 表示交易的惟一 ID。例如,如果 URI 是 /transactions/V19A2A192BE9V19A2A192BE9 字符串会被注入 getTxnStatus 方法的 {pnref} 参数中。

@javax.ws.rs.QueryParam 注释与 @PathParam 相似,但是它把各个 URI 查询参数注入 Java 参数中,见 清单 8

清单 8. 包含查询参数的 URI
/transactions/V19A2A192BE9?user=winktest&vendor=winktest&partner=PayPal&pwd=wink123

Apache Wink 服务配置

Apache Wink 应用程序通常打包为 WAR 文件,部署在 Apache Tomcat 等 servlet 容器中。与其他 Web 应用程序一样,Apache Wink 服务也需要一个 web.xml 文件。清单 9 给出示例 Apache Wink 服务的 web.xml 文件的内容。

清单 9. web.xml Web 配置文件
<web-app>
	<display-name>Wink demo</display-name>
	<description>Demonstration of SDK features</description>

	<!-- Wink SDK servlet configuration. 
		This servlet handles HTTP requests
		of SDK web service on application server.-->
				
	<servlet>
		<servlet-name>restSdkService</servlet-name>
		<servlet-class>
			org.apache.wink.server.internal.servlet.RestServlet
		</servlet-class>
		<init-param>
			<param-name>applicationConfigLocation</param-name>
			<param-value>/WEB-INF/application</param-value>
		</init-param>
	</servlet>

	<servlet-mapping>
		<servlet-name>restSdkService</servlet-name>
		<url-pattern>/rest/*</url-pattern>
	</servlet-mapping>
</web-app>

可以看到 web.xml 文件中定义了 Apache Wink RestServlet 和它的 url-pattern。还有 RestServlet 的初始化参数,它指向 /WEB-INF/application 目录中的一个文件。这个文件包含 JAX-RS 应该部署的所有类和对象的列表。您不需要这个配置文件,可以让应用程序类以编程方式列出服务实现的资源,但是这个示例使用应用程序配置文件的方式,见 清单 10

清单 10. 应用程序配置文件
org.openengine.wink.example.payflow.TransactionResource

运行 Apache Wink 服务

要想运行这个服务,首先必须在 Tomcat 上构建和部署应用程序。执行以下步骤:

  1. 下载 部分下载 PayFlow 示例项目。
  2. 把 PayFlow 项目的内容解压到 C 驱动器上的一个文件夹。C:\PayFlow 目录应该像 图 2 这样。
    图 2. PayFlow 示例项目的目录结构
    窗口显示 dist、lib 和 source 目录以及 build.xml 文件
  3. 把 JAVA_HOME 和 ANT_HOME 变量设置为自己的 Java 和 Apache Ant 安装目录。
  4. 在系统变量 PATH 中添加 JAVA_HOME/bin 和 ANT_HOME/bin。
  5. 从 C:\PayFlow 目录运行 Ant,从而对 PayFlow 项目执行 Ant 构建。

    这个步骤应该会构建 PayFlow 项目并创建文件 PayFlow.war,见 图 3

    图 3. Ant 脚本构建的输出
    命令提示显示 Ant 脚本构建代码。显示成功地构建了 payflow.war 文件
  6. 把 PayFlow.war 文件复制到 TOMCAT 主目录下的 webapps 目录中,见 图 4
    图 4. 在 Tomcat 服务器上部署 PayFlow 项目
    窗口显示 webapps 目录下的 docs、examples、host-manager 和 root 子目录以及 payflow.war 文件
  7. 通过运行 TOMCAT_HOME\bin 文件夹中的 startup.bat 文件启动 Tomcat Web 服务器。
  8. 启动您喜欢的浏览器,访问 URI http://localhost:8080/PayFlow/rest/transactions/V19A2A192BE9?user=winktest&vendor=winktest&partner=PayPal&pwd=wink123>(假设 Tomcat Web 服务器配置为监听端口 8080)。

    浏览器应该会提示您保存文件 V19A2A192BE9,其中包含 JSON 格式的交易状态,见 图 5

    图 5. 浏览器保存文件窗口,保存包含交易状态的 JSON 文件
    窗口显示保存 application/json 文件,选择了 save file 单选按钮

结束语

本文简要介绍了 REST 架构和 JAX-RS Java 标准(这个标准用于简化 RESTful 服务实现)的基本知识。然后讨论了新的 Apache Wink 1.0 框架,这是一个完全兼容的容易使用的 JAX-RS 1.0 规范实现。介绍了 Apache Wink 的底层架构,然后设计和实现了一个新的示例 Apache Wink Web 服务,讨论了部署和运行它所需的步骤。关于 REST、JAX-RS 和 Apache Wink 1.0 框架的更多信息,请参见本文的 参考资料 部分。


下载

描述名字大小
Apache Wink 服务实现PayFlow.zip2.51MB

参考资料

学习

获得产品和技术

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development
ArticleID=489538
ArticleTitle=RESTful Web 服务和 Apache Wink,第 1 部分: 构建 Apache Wink REST 服务
publish-date=05132010