使用 Apache Wink、Eclipse 和 Maven 开发 RESTful Web 服务
2011-04-27 14:15
681 查看
Apache Wink
是一个促进创建和使用
REST Web
服务的
Apache
孵化器项目。通过
REST
Web
服务,客户机和服务之间的交互局限于一组预定义的操作,客户机和服务器之间的交互的复杂性限制为客户机和服务之间交换的资源表示。这种方法支持构建可互操
作、可伸缩、可靠的、基于
REST
的分布式超媒体系统。
本文介绍如何使用 Apache Wink
、Eclipse IDE
以及 Maven
项目管理工具开发、部署和运行 RESTful Web
服务。
Web
服务的 REST
方法
设计 Web
服务的 REST
方法将客户机和服务之间的交互限制到一组创建、读取、更新和删除(CRUD
)操作。这些操作直接映射到 HTTP
方法 —
具体而言,映射到
、
、
和
。尽管 RESTful
样式没有绑定到 HTTP
协议,本文假设 HTTP
用于客户机和服务之间的通信。
REST Web
服务在资源上执行 CRUD
操作。客户机使用资源状态的 REST
服务表示进行交换。这些表示使用的数据格式在 HTTP
请求或响应的头部中指定 — XML
和 JSON
是广泛使用的格式。数据格式可能在不同操作之间发生变化;例如,创建资源的数据格式与用于读取资源的数据格式不同。REST
服务保持资源的状态,但 —
与
servlets
不同的是 —
不保持客户机会话信息。
REST
方法支持构建可互操作、可伸缩和可靠的基于 REST
的分布式系统。例如,
、
和
方法是等幂的,即多次执行它们与执行一次的结果相同。由于
操作不会更改资源的状态,因此
请求的结果可以缓存起来以加快 “
请求-
响应”
循环。
JAX-RS
为基于 HTTP
协议的 RESTful Java Web
服务定义了一个 API
。JAX-RS
实现包括 Apache Wink
、Sun Jersey
和 JBoss RESTEasy
。本文将使用 Apache Wink
。
JAX-RS
利用 Java
注释的威力,使用注释来执行诸如以下的操作:
将 HTTP
方法和 URIs
绑定到 Java
类的方法
将来自 URI
或 HTTP
头部的元素作为方法参数注入
在 HTTP
消息体和 Java
类型之间来回转换
将 URI
模式绑定到 Java
类和方法 —
@Path
注释
将 HTTP
操作绑定到 Java
方法 —
@GET、
@POST、
@PUT和
@DELETE注释
JAX-RS
还提供了一个框架来构建新功能。例如,对于自定义数据格式,程序员可以开发消息阅读器并将 Java
对象编组到 HTTP
消息并从 HTTP
消息解组它们。
在本文中,您将使用 Eclipse
和 Maven
下载
Apache Wink
,运行 Apache Wink
中包含的
HelloWorld
示例,然后将您自己的 REST Web
服务创建为一个 Eclipse
项目。
通过 Eclipse
获取 Apache Wink
在这个小节中,您将使用 Eclipse
以及 Maven Integration for Eclipse
(称为 m2eclipse
)和 Subclipse
插件来安装 Apache Wink
。(M2eclipse
提供从 Eclipse
对 Maven
的访问;Subclipse
提供对 Subversion
资源库的访问。)您还可以将 Eclipse
用作一个平台,从这个平台构建并运行 Web
服务。
先决条件
在获取 Apache Wink
之前,要先下载并安装以下软件包(参见
参
考资料
获取下载 URLs
):
Java Software
Development Kit (JDK) version 6
。
设 置 JAVA_HOME
环境变量并添加到路径
%JAVA_HOME%/bin
(在 Windows®
中)或 $JAVA_HOME/bin
(在 Linux®
中)。
Apache Tomcat
version 6.0
。
设置 CATALINA_HOME
环境变量以指向安装目录。
Eclipse IDE
for Java™ Platform, Enterprise Edition (Java EE) developers
。
本文撰写之时的当前版本为 Eclipse Galileo
。
安装 Subclipse
要使用 Eclipse
管理具有 Maven
感知的项目,要安装 Eclipse
插件 Subclipse
和 m2eclipse
。要安装 Subclipse
插件,执行以下步骤:
启动 Eclipse
。
单击菜单栏中的 Help
,然后选择
Install new software
。
在 Available
Software
窗口中,单击 Add
。
在 Add
Site
窗口中,输入:
5.
·
6.
7.
然后单击 OK
。
8.
·
在 Available Software
窗口中,选择 Subclipse
下的 Subclipse
(Required)
和 SVNKit
Client Adapter (Not required)
复选框(如
图 1
所示),然后单击 Next
。
9.
·
图 1.
安装
Subclipse
插件
10.
·
在 Install Details
窗口中,单击
Next
。
11.
·
在 Review Licenses
窗口中,检查许可,接受许可协议条款,然后单击
Finish
。
12.
·
单击 Yes
重新启动 Eclipse
。
安装 m2eclipse
m2eclipse
插件的安装步骤与安装 Subclipse
插件类似,但有以下几点例外:
在 Add
Site
窗口中输入:
然后单击 OK
。
在 Available
Software
窗口中,选择 Maven
Integration for Eclipse (Required)
和 Maven SCM handler for Subclipse (Optional)
复选框(如
图 2
所示),然后单击 Next
。
图 2.
安装
m2eclipse
插件
获取 Apache Wink
现在,您可以使用 Eclipse
从资源库检查 Apache Wink
示例,将必要的 Java
归档(JAR
)文件(包括
Apache Wink JAR
文件)下载到一个本地资源库,构建并运行 Apache Wink
HelloWorld
示例。为此,执行以下步骤:
在 Eclipse
中,选择
File > Import
启动 Import Wizard
。
在 Select
向导页面的 Select and import source
文本框中输入
maven
。
在 Maven
下,选择 Materialize Maven Projects
并单击 Next
。
在 Select
Maven artifacts
向导页面上单击 Add
。
在 Add
Dependency
页面上的 Enter
groupId, artifactId
文本框中输入
org.apache.wink.example
。
注意:
Artifact
(工件) 是一个用于 Maven
的术语,指的是设置了版本并存储在资源库中的软件包的层级结构。
在 Search
Results
区域中,选择 org.apache.wink.example
apps
(如
图 3
所示)并单击 OK
。
图 3. org.apache.wink.example
组中的应用程序工件
在 Select
Maven artifacts
向导页面上,单击 Next
, 然后单击 Finish
。
在 Maven
Projects
向导页面上,只选择 /pom.xml
复选框,然后单击 Finish
。
Maven
处理一个工件的所有依赖项的方式是从远程资源库下载它们并构建一个本地资源库。Maven
的优势之一是能够处理临时依赖项;因此,在 Maven Project Object Model (POM)
文件中,只需声明工件的传递依赖项(transitive dependencies
),Maven
将为您处理高阶依赖项(higher-order dependencies
)。
步骤 8
完成后,将创建一个 Eclipse
项目,它包含 Apache Wink
示例的
apps
模块中的代码。在 Eclipse
的 Project
Explorer
中浏览项目文件。
Apache Wink HelloWorld
服务
我们来检查一下
apps
模块中的
HelloWorld
Java
类。在 Project Explorer
视图中,单击 apps
> HelloWorld > src > main
, 然后打开文件
HelloWorld.java
,该文件的结构如
清
单
1
所示。
清单 1.
HelloWorld.java
文件
HelloWorld
是一个 JAX-RS
资源(或服务),正如其类定义前面的
@Path("/world")
注释所示。字符串
"/world"
是该资源的相对根 URI
。JAX-RS
将匹配相对 URI
"/world"
的 HTTP
请求路由到
HelloWorld
类的方法。
HelloWorld
类的惟一方法 —
getGreeting
—
拥有一个
@GET注释,表示它将服务于 HTTP
GET请求。
@Produces(MediaType.APPLICATION_ATOM_XML)
注释表明 HTTP
响应的媒体类型 —
即,HTTP
响应头部中的
Content-Type
字段的值。
与相对 URI
"/world"
关联的绝对 URI
由部署描述符
web.xml
中的设置决定,这个部署描述符驻留在 HelloWorld/src/main/webapp/WEB-INF
中,如
图 4
所示。
图 4. HelloWorld
应用程序的部署描述符
注意,URI
模式
/rest/*
被绑定到
restSdkService
servlet
,这个 servlet
的 context path
是
HelloWorld
, 由 HelloWorld/pom.xml
文件中的
<finalName>
元素定义。这样,
HelloWorld
资源的绝对 URI
是:
图 4
中的 servlet
名称
restSdkService
引用
org.apache.wink.server.internal.servlet.RestServlet
Apache Wink
类,如图中的
<servlet>
元素所示。
RestServlet
类使用初始参数
applicationConfigLocation
传递
HelloWorld
类的名称,这个初始参数反过来指向位于 HelloWorld/src/main/webapp/WEB-INF
文件夹中的 web.xml
旁边的 application
文件。这个 application
文件只有一行,即
HelloWorld
资源的限定名:
RestServlet
servlet
可以在 “
无 JAX-RS
感知”
的 servlet
容器中运行,从而支持将 JAX-RS
服务轻松部署到 “
无
JAX-RS
感知”
的容器中。
我们现在开始构建 HelloWorld
服务,然后将其部署到 Tomcat 6.0 servlet
容器中并运行。
构建 HelloWorld
在
Eclipse
中,可以使用 m2eclipse
插件来构建、部署和运行 HelloWorld
。首先,编译源代码并为 HelloWorld
服务构建 Web
归档 (WAR)
文件。要构建这个服务,指示 m2eclipse
执行安装
生 命周期阶段。(执行一个 Maven
生命周期阶段将触发项目生命周期中的此前阶段的执行。)要执行安装阶段,在 Project Explorer
视图中右键单击 HelloWorld
,然后单击
Run As > Maven install
,如
图 5
所示。
图 5.
执行 Maven
安装阶段
Maven
(从中央资源库 http://repo1.maven.org/maven2
或从镜像资源库)下载所有依赖项,并在 Windows®
中的
%HOMEPATH%/.m2/repository
或 Linux®
中的 $HOME/.m2/repository
下构建本地资源库。Maven
执行的动作记录在 Eclipse
窗口的 Console
视图中。
如果安装阶段成功结束,那么 WAR
文件 HelloWorld.war
就构建在目标目录下并部署到本地资源库中,Console
视图将显示消息 “Build successful”
。
将 HelloWorld
部署到 Tomcat
您将使用 Maven
的 Tomcat
插件。(与 Eclipse
一样,Maven
通过插件提供大量功能。)您必须将 Tomcat
插件的位置告知 Maven
,方法是指定插件的
groupId
和
artifactId
,如
图 6
所示(pom.xml
中的 45-46
行)。
图 6. Tomcat Maven
插件
您还需要告知 Maven
用于访问 Tomcat manager
应用程序的用户名和密码。Maven
使用 manager
应用程序来指导 Tomcat
部署或取消部署一个 Web
应用程序。按照以下步骤告知 Maven
身份验证信息:
声明
tomcat-maven-plugin
工件的一个
Tomcat
服务器配置 —
称为
tomcat-localhost
, 如
图 6
所示(pom.xml
中的 47-49
行)
在 Maven
设置文件 settings.xml
(位于 Windows
的 %HOMEPATH%/.m2/
或 Linux
的 $HOME/.m2
下)中定义这个配置,如
清
单 2
所示。
清单 2. Maven
settings.xml
文件
现在可以将这个服务部署到 Tomcat
了,方法是执行 Tomcat
插件的 redeploy
目标。(一个
Maven
目标(goal
) 被自身执行,这与生命周期阶段不同,后者的执行由生命周期中的此前阶段自动推进。)要执行 redeploy
目标,执行以下步骤:
在 Tomcat
配置文件 conf/tomcat-users.xml
(位于 CATALINA_HOME
下)中插入身份验证信息(如
图 7
所示),但要使用一个密码,而不是 admin
。
图 7. Tomcat
身份验证配置
通过运行以下命令启动
Tomcat
:
执行
maven tomcat:redeploy
,这条命令使用 Tomcat manager
应用程序将
HelloWorld.war
部署到 Tomcat
。为此,执行以下步骤:
在 Project
Explorer
视图中,右键单击 HelloWorld
,然后单击 Run As > Run configurations
。
在 Create,
manage, and run configurations
窗口中,选择 Maven Build > New_configuration
,然后单击 Main
选项卡(参见
图 8
)。
图 8.
运行
tomcat:redeploy
目标
单击 Browse
workspace
,然后选择 apps > HelloWorld
,然后单击
OK
。
在 Goals
文本框中,输入
tomcat:redeploy
, 然后单击 Run
。
如果 redeploy
目标成功执行,Console
视图将显示消息 “Build successful”
。
现在,您可以使用一个 HTTP
客户机(比如 Curl
)调用
HelloWorld
服务,如
清
单
3
所示。
清单 3.
在 Curl
中调用 HelloWorld
服务
$ curl -X GET http://localhost:8080/HelloWorld/rest/world
<?xml version="1.0"
encoding="UTF-8" standalone="yes"?>
<entry
xmlns="http://www.w3.org/2005/Atom"
xmlns:ns2="http://a9.com/-/spec/opensearch/1.1/"
xmlns:ns3="http://www.w3.org/1999/xhtml">
<id>helloworld:1</id>
<updated>2010-01-06T13:26:43.924+01:00</updated>
<title
type="text">Hello World!</title>
</entry>
开发一个 REST Web
服务
在这个小节中,您将从头开始创建一个 REST Web
服务来管理一个图书资源集合。这个 REST
服务的源代码可以从下面的
下
载
表中获取。
开发这样一个服务的关键步骤是:
定义资源的 URIs
,用于操作资源的方法,以及每个方法的数据格式。
定义表示图书资源的
Java
对象,提供 Java
代码或注释来编组和解组 Java
对象。
定义将 URIs
和 HTTP
方法绑定到 Java
方法的 Java
服务。
提供
javax.ws.rs.core.Application
抽象类的一个具体子类。
下面我们就执行这些步骤。
将路径和 HTTP
方法绑定到 Java
方法
这个服务支持
GET,
POST、
PUT和
DELETEHTTP
方法,并按如下方式将 HTTP
请求映射到 Java
方法:
将
POST /books
请求映射到带有
createBook(@Context
UriInfo, Book)
签名的 Java
方法。(
@Context
注释将在
JAX-RS Web
服务
小节中介绍。)用于创建一个图书资源的数据格式为:
将
GET /books
请求映射到
Java
方法
getBook()
。用 于获取图书资源的数据格式为:
将
GET /books/{id}
请求映射到带有
getBook(@PathParam("id")
int)
签名的 Java
方法。(
@PathParam
注释将在
JAX-RS Web
服务
小节中介绍。)用于获取带有 URI
模式
/books/{id}
的图书资源的数据格式为:
将
PUT /books/{id}
请求映射到带有
updateBook(@PathParam("id")
int, Book)
签名的 Java
方法。用于更新带有 URI
模式
/books/{id}
的图书资源的数据格式为:
将
DELETE /books/{id}
请求映射到带有
deleteBook(@PathParam("id")
int)
签名的 Java
方法。用于删除带有 URI
模式
/books/{id}
的图书资源的数据格式为:
图书的对象模型
用于实现这个图书集合的 Java
对象模型有 3
个类:
Book
,如
清
单 4
所示。
BookList
,如
清
单 5
所示。
Link
,如
清
单 6
所示。
清单 4. Book
类
在
Book
类中,您使用 Java Architecture for XML
Binding (JAXB)
注释来执行 Java
对象的编组和解组。Apache Wink
自动编组和解组带有 JAXB
注释的 Java
对象,包括创建执行编组和解组工作的
Marshaller
和
Unmarshaller
实例。
您将使用
BookList
类来表示图书对象的集合,
BookList
类将这些对象以内部存储方式存储在
ArrayList
类型的一个字段中,
ArrayList
带有 JAXB
注释,以便转换为 XML
格式。
清单 5. BookList
类
您将使用
Link
类将链接元素插入到图书对象的 XML
表示中(参见
清
单
6
)。
清单 6. Link
类
JAX-RS Web
服务
现在,您已经定义了将 URIs
和 HTTP
方法绑定到
Java
方法的 Java
服务。您可以将这个服务定义为一个
Java
接口或一个类;对于前者,还需要定义实现接口的类。在接口中,您本地化 JAX-RS
注释并添加一个类来实现接口。
清
单
7
展示了
BookService
Java
接口。
@javax.ws.rs.Path
注释将这个接口指定为一个 JAX-RS
服务。注释的
/books
值定义这个服务的相对根 URI
。注释
@javax.ws.rs.POST、
@javax.ws.rs.GET、
@javax.ws.rs.PUT和
@javax.ws.rs.DELETE将 HTTP
POST、
GET、
PUT和
DELETE操作绑定到紧随其后的 Java
方法。
清单 7. BookService
接口
对于其 URI
与接口的
@PATH("/books")
注释指定的值不同的方法,您将一个特定的
@PATH
注释附加到那些方法。
@PATH
注释是可以累积的,即,一个路径表达式后面的另一个路径表达式将附加到前面的表达式。因此,绑定到
deleteBook
方法的路径模式为
/books/{id}
。
JAX-RS
提供了一种机制,用于从一个 HTTP
请求提取信息,将信息赋予一个 Java
对象,然后将该对象注入一个 Java
方法参数。这种机制称为注入(injection
)。注入使用 Java
注释指定。在
BookService
接口中,您将插入两个注入注释:
@Context
注释从 HTTP
请求提取 URI
信息,将其转换为
UriInfo
对象,然后将这个对象作为方法参数
uriInfo
注入。
@PathParam("id")
注释匹配前面的
@Path({"id"})
注释。这个注释从 URI
模式
/books/{id}
提取
{id}
,并将其注入
getBook
方法的
id
参数的值。
注意,
BookService
的方法将 Java
对象(比如
Book
)接收为参 数并返回 Java
对象;这是可能的,因为这些对象带有
JAXB
注释,因此 Apache Wink
能够对它们进行自动编组和解组。
清
单
8
展示了实现
BookService
的类的结构。
BookServiceImpl
是一个 singleton
类,使用一个内存映射图(in-memory map
)来维护图书对象集合。singleton
实例使用多线程服务并发请求,因此它必须是线程安全的(thread-safe
)。
清单 8. BookService
实现类
图书集合存储在一个映射图中。要提供对这个映射图的线程安全访问,您将使用一个
ConcurrentHashMap
。 要生成惟一的图书 IDs
,您将使用一个
AtomicInteger
,它能确保增量操作是原子级的(atomic
),从而确 保线程安全。
设置 Application
抽象类的子类
JAX-RS Web
应用程序包含一组资源(REST Web
服务),这些资源作为 JAX-RS
抽象类
javax.ws.rs.core.Application
的子类出现。
清
单
9
中显示的
BookWebApp
类扩展了
Application
类。
清单 9.
javax.ws.rs.core.Application
的具体子类
BookWebApp
的构造函数获取这个图书服务实现对象的 singleton
实例。
getSingletons
方法返回一个组,其惟一元素就是这个 singleton
。JAX-RS
在服务一个请求后并不删除这个 singleton
。
构建和部署 REST Web
服务
您将使用 Eclipse
来创建一个动态 Web
项目,这个项目包含上一小节介绍过的 Java
类和其他资源,比如 Web
应用程序部署描述符和必要的 JAR
文件。
注意:
创建一个 Eclipse
动态 Web
项目的另一种方法是从一个 archetype
(比如
maven-archetype-webapp
或
webapp-jee5
) 创建一个 Maven
项目(archetype
是一个 Maven
项目模板)。但是,在 Maven
当前版本中,生成 Eclipse
使用的项目元数据时会出现一些问题:要支持 IDE
中的自动代码构建,必须手动修改一些 Eclipse
项目文件。因此,本文使用 Eclipse
动态 Web
项目。
Web
服务的 Eclipse
项目
Eclipse
动态 Web
项目支持开发在一个 servlet
容器中运行的 Web
应用程序,因此它是用于开发 Apache Wink
服务的一个不错的项目模板。要为这个图书 REST
服务创建一个动态 Web
项目,执行以下步骤:
在 Eclipse
中,单击
File > New > Dynamic Web Project
。
在 Dynamic
Web Project Wizard
中,在 Project name
文本框中输入
Books
。
单击 Target
runtime
方框旁边的 New
创建一个 Tomcat
运行时。
在 New
Server Runtime Environment
向导页面上,单击 Apache > Apache Tomcat v6.0
,然后单击 Next
。
在 Tomcat
Server
向导页面上,单击 Browse
,
然后导航到
先
决条件
小节中定义的 CATALINA_HOME
目录。
单击 OK
,然后单击
Finish
。
在 Dynamic
Web Project
页面上,单击 Finish
。
将上一小节中介绍的 Java
类添加到刚才创建的 Books
项目中。为此,执行以下步骤:
在 Project
Explorer
视图中,打开 Books
文件夹。右键单击 Java Resources:src
,然后单击 New >
Package
。
在 Java
Package
窗口中的 Name
文本框中,输入包名称 —
com.ibm.devworks.ws.rest.books
—
并单击 Finish
。
将 Java
类添加到
com.ibm.devworks.ws.rest.books
包:
在 Project
Explorer
视图中,右键单击上述包,然后单击 New > Class
。
在 Name
文本框中,输入类名称(比如为
Book.java
输入
Book
),然后单击 Finish
。
使用 Eclipse
Java
编辑器来创建类。
然后,向项目添加构建和运行一个 Apache Wink
服务所需的 JAR
文件。当您创建这个应用程序项目时,Maven
将 JAR
文件下载到本地资源库,本地资源库驻留在 %HOMEPATH%/.m2/repository
(Windows
)或 $HOME/.m2/repository
(Linux
)中。
要将 JAR
文件添加到这个项目,执行以下步骤:
在 Project
Explorer
视图中,导航到 Books/Web Content/WEB-INF
。
右键单击 lib
,然后单击
Import > General > File System
,然后单击 Next
。
在 File
System
窗口中,从 Maven
资源库(已在导入应用程序 Apache Wink
模块时由 m2eclipse
填充)导入 JAR
文件 jsr311-api-1.0.jar
,方法是导航到包含这个 JAR
文件的目录,然后单击 OK
。在 File System
窗口中,选中这个 JAR
文件,然后单击 Finish
。
重复步骤 2
到步骤 3
,分别导入 JAR
文件
wink-server-1.0-incubating.jar
、 wink-common-1.0-incubating.jar
、slf4j-api-1.5.8.jar
和
slf4j-simple-1.5.8.jar
。
所有库都导入后,lib
目录将包含如
图 9
所示的 JAR
文件。
图 9.
一个
Apache Wink
服务所需的库
您还可以通过从下面的
下
载
部分中提供的代码样例中导入
Book
服务来创建这个 Eclipse
项目。为此,下载并解压文件,然后在 Eclipse
中单击 File > Import >
Existing Project Into Workspace
。在 Import Projects
Wizard
中,单击 Browse
,
导航到 Books
文件夹,单击 OK
,然后单击 Finish
。
将服务部署到 Tomcat
在部署描述符文件 web.xml
(如
清
单
10
所示)中,您将带有相对根路径 /*
的 URIs
映射到 Wink servlet
org.apache.wink.server.internal.servlet.RestServlet
。
RestServlet
被传递为
init-param
,这是 Books
服务提供的
Application
子类的名称。
清单 10.
BookService
部署服务描述符 web.xml
部署描述符设置好后,就可以将这个 Books
服务部署到 Tomcat
了。为了进行测试,将这个 Books
服务部署到一个由 Eclipse
托管的 Tomcat
实例中并运行。为此,执行以下步骤:
在 Project
Explorer
视图中,右键单击 Books
,然后单击 Run As > Run on Server
。
在 Run on
Server
窗口中,单击 Finish
,
这将把这个 Books
服务部署到创建这个 Books
项目时配置的 Tomcat
运行时中并启动 Tomcat
。
测试完成后,您将这个 Books
服务打包到一个 WAR
文件中,以备部署到生产环境中。为此,在 Project Explorer
视图中,右键单击 Books
,然后单击
Export > WAR file
。 在 WAR
Export Wizard
中,单击 Browse
,选择创建 WAR
文件的文件夹,然后单击 Save
和 Finish
。
调用 REST Web
服务
可以使用一个支持 HTTP
操作
、
、
和
的 HTTP
客户机来调用这个
Books
服务。 清
单 11
展示了如何使用 Curl
来调用这个服务。首先,您将得到所有图书的表示(最初没有图书);然后,您使用
jaxrs.xml
和 rest.xml
两个表示来创建两本图书;最后,您得到所有图书的表示和
的图书的表示。
清单 11.
调用 Books
服务
结束语
本文展示了如何联合使用几种技术来支持 Apache Wink REST Web
服务的开发、构建和部署。Java
注释的威力简化了开发工作。
REST Web
服务支持应用程序交换链接数据。Tim
Berners-Lee
先生预言,链接数据将改变 Web
的面貌。Bill Burke
在他撰写的图书 RESTful Java with JAX-RS
中指出,通过将服务交互的复杂性限制为数据表示,REST Web
服务将服务组合性和重用提高到一个新的水平。
本文仅仅涉及 Apache Wink
服务开发的皮毛,Apache
Wink
的其他重要特性包括链接构建器、自定义消息体阅读器以及针对不受支持的数据格式的编写器。要深入了解
Apache Wink
框架,一定要看一看 Apache Wink
中包含的其他示例。
是一个促进创建和使用
REST Web
服务的
Apache
孵化器项目。通过
REST
Web
服务,客户机和服务之间的交互局限于一组预定义的操作,客户机和服务器之间的交互的复杂性限制为客户机和服务之间交换的资源表示。这种方法支持构建可互操
作、可伸缩、可靠的、基于
REST
的分布式超媒体系统。
本文介绍如何使用 Apache Wink
、Eclipse IDE
以及 Maven
项目管理工具开发、部署和运行 RESTful Web
服务。
Web
服务的 REST
方法
设计 Web
服务的 REST
方法将客户机和服务之间的交互限制到一组创建、读取、更新和删除(CRUD
)操作。这些操作直接映射到 HTTP
方法 —
具体而言,映射到
POST
、
GET
、
PUT
和
DELETE
。尽管 RESTful
样式没有绑定到 HTTP
协议,本文假设 HTTP
用于客户机和服务之间的通信。
REST Web
服务在资源上执行 CRUD
操作。客户机使用资源状态的 REST
服务表示进行交换。这些表示使用的数据格式在 HTTP
请求或响应的头部中指定 — XML
和 JSON
是广泛使用的格式。数据格式可能在不同操作之间发生变化;例如,创建资源的数据格式与用于读取资源的数据格式不同。REST
服务保持资源的状态,但 —
与
servlets
不同的是 —
不保持客户机会话信息。
REST
方法支持构建可互操作、可伸缩和可靠的基于 REST
的分布式系统。例如,
GET
、
POST
和
DELETE
方法是等幂的,即多次执行它们与执行一次的结果相同。由于
GET
操作不会更改资源的状态,因此
GET
请求的结果可以缓存起来以加快 “
请求-
响应”
循环。
JAX-RS
为基于 HTTP
协议的 RESTful Java Web
服务定义了一个 API
。JAX-RS
实现包括 Apache Wink
、Sun Jersey
和 JBoss RESTEasy
。本文将使用 Apache Wink
。
JAX-RS
利用 Java
注释的威力,使用注释来执行诸如以下的操作:
将 HTTP
方法和 URIs
绑定到 Java
类的方法
将来自 URI
或 HTTP
头部的元素作为方法参数注入
在 HTTP
消息体和 Java
类型之间来回转换
将 URI
模式绑定到 Java
类和方法 —
@Path
注释
将 HTTP
操作绑定到 Java
方法 —
@GET、
@POST、
@PUT和
@DELETE注释
JAX-RS
还提供了一个框架来构建新功能。例如,对于自定义数据格式,程序员可以开发消息阅读器并将 Java
对象编组到 HTTP
消息并从 HTTP
消息解组它们。
在本文中,您将使用 Eclipse
和 Maven
下载
Apache Wink
,运行 Apache Wink
中包含的
HelloWorld
示例,然后将您自己的 REST Web
服务创建为一个 Eclipse
项目。
通过 Eclipse
获取 Apache Wink
在这个小节中,您将使用 Eclipse
以及 Maven Integration for Eclipse
(称为 m2eclipse
)和 Subclipse
插件来安装 Apache Wink
。(M2eclipse
提供从 Eclipse
对 Maven
的访问;Subclipse
提供对 Subversion
资源库的访问。)您还可以将 Eclipse
用作一个平台,从这个平台构建并运行 Web
服务。
先决条件
在获取 Apache Wink
之前,要先下载并安装以下软件包(参见
参
考资料
获取下载 URLs
):
Java Software
Development Kit (JDK) version 6
。
设 置 JAVA_HOME
环境变量并添加到路径
%JAVA_HOME%/bin
(在 Windows®
中)或 $JAVA_HOME/bin
(在 Linux®
中)。
Apache Tomcat
version 6.0
。
设置 CATALINA_HOME
环境变量以指向安装目录。
Eclipse IDE
for Java™ Platform, Enterprise Edition (Java EE) developers
。
本文撰写之时的当前版本为 Eclipse Galileo
。
安装 Subclipse
要使用 Eclipse
管理具有 Maven
感知的项目,要安装 Eclipse
插件 Subclipse
和 m2eclipse
。要安装 Subclipse
插件,执行以下步骤:
启动 Eclipse
。
单击菜单栏中的 Help
,然后选择
Install new software
。
在 Available
Software
窗口中,单击 Add
。
在 Add
Site
窗口中,输入:
5.
·
Name: Subclipse Location: http://subclipse.tigris.org/update_1.6.x/ |
7.
然后单击 OK
。
8.
·
在 Available Software
窗口中,选择 Subclipse
下的 Subclipse
(Required)
和 SVNKit
Client Adapter (Not required)
复选框(如
图 1
所示),然后单击 Next
。
9.
·
图 1.
安装
Subclipse
插件
10.
·
在 Install Details
窗口中,单击
Next
。
11.
·
在 Review Licenses
窗口中,检查许可,接受许可协议条款,然后单击
Finish
。
12.
·
单击 Yes
重新启动 Eclipse
。
安装 m2eclipse
m2eclipse
插件的安装步骤与安装 Subclipse
插件类似,但有以下几点例外:
在 Add
Site
窗口中输入:
Name: Maven Integration for Eclipse Location: http://m2eclipse.sonatype.org/update/ |
。
在 Available
Software
窗口中,选择 Maven
Integration for Eclipse (Required)
和 Maven SCM handler for Subclipse (Optional)
复选框(如
图 2
所示),然后单击 Next
。
图 2.
安装
m2eclipse
插件
获取 Apache Wink
现在,您可以使用 Eclipse
从资源库检查 Apache Wink
示例,将必要的 Java
归档(JAR
)文件(包括
Apache Wink JAR
文件)下载到一个本地资源库,构建并运行 Apache Wink
HelloWorld
示例。为此,执行以下步骤:
在 Eclipse
中,选择
File > Import
启动 Import Wizard
。
在 Select
向导页面的 Select and import source
文本框中输入
maven
。
在 Maven
下,选择 Materialize Maven Projects
并单击 Next
。
在 Select
Maven artifacts
向导页面上单击 Add
。
在 Add
Dependency
页面上的 Enter
groupId, artifactId
文本框中输入
org.apache.wink.example
。
注意:
Artifact
(工件) 是一个用于 Maven
的术语,指的是设置了版本并存储在资源库中的软件包的层级结构。
在 Search
Results
区域中,选择 org.apache.wink.example
apps
(如
图 3
所示)并单击 OK
。
图 3. org.apache.wink.example
组中的应用程序工件
在 Select
Maven artifacts
向导页面上,单击 Next
, 然后单击 Finish
。
在 Maven
Projects
向导页面上,只选择 /pom.xml
复选框,然后单击 Finish
。
Maven
处理一个工件的所有依赖项的方式是从远程资源库下载它们并构建一个本地资源库。Maven
的优势之一是能够处理临时依赖项;因此,在 Maven Project Object Model (POM)
文件中,只需声明工件的传递依赖项(transitive dependencies
),Maven
将为您处理高阶依赖项(higher-order dependencies
)。
步骤 8
完成后,将创建一个 Eclipse
项目,它包含 Apache Wink
示例的
apps
模块中的代码。在 Eclipse
的 Project
Explorer
中浏览项目文件。
Apache Wink HelloWorld
服务
我们来检查一下
apps
模块中的
HelloWorld
Java
类。在 Project Explorer
视图中,单击 apps
> HelloWorld > src > main
, 然后打开文件
HelloWorld.java
,该文件的结构如
清
单
1
所示。
清单 1.
HelloWorld.java
文件
package org.apache.wink.example.helloworld; ... @Path("/world") public class HelloWorld { public static final String ID = "helloworld:1"; @GET@Produces(MediaType.APPLICATION_ATOM_XML) public SyndEntry getGreeting() { SyndEntry synd = new SyndEntry(new SyndText("Hello World!"), ID, new Date()); return synd; } } |
是一个 JAX-RS
资源(或服务),正如其类定义前面的
@Path("/world")
注释所示。字符串
"/world"
是该资源的相对根 URI
。JAX-RS
将匹配相对 URI
"/world"
的 HTTP
请求路由到
HelloWorld
类的方法。
HelloWorld
类的惟一方法 —
getGreeting
—
拥有一个
@GET注释,表示它将服务于 HTTP
GET请求。
@Produces(MediaType.APPLICATION_ATOM_XML)
注释表明 HTTP
响应的媒体类型 —
即,HTTP
响应头部中的
Content-Type
字段的值。
与相对 URI
"/world"
关联的绝对 URI
由部署描述符
web.xml
中的设置决定,这个部署描述符驻留在 HelloWorld/src/main/webapp/WEB-INF
中,如
图 4
所示。
图 4. HelloWorld
应用程序的部署描述符
注意,URI
模式
/rest/*
被绑定到
restSdkService
servlet
,这个 servlet
的 context path
是
HelloWorld
, 由 HelloWorld/pom.xml
文件中的
<finalName>
元素定义。这样,
HelloWorld
资源的绝对 URI
是:
http://host:port/HelloWorld/rest/world |
中的 servlet
名称
restSdkService
引用
org.apache.wink.server.internal.servlet.RestServlet
Apache Wink
类,如图中的
<servlet>
元素所示。
RestServlet
类使用初始参数
applicationConfigLocation
传递
HelloWorld
类的名称,这个初始参数反过来指向位于 HelloWorld/src/main/webapp/WEB-INF
文件夹中的 web.xml
旁边的 application
文件。这个 application
文件只有一行,即
HelloWorld
资源的限定名:
org.apache.wink.example.helloworld.HelloWorld |
servlet
可以在 “
无 JAX-RS
感知”
的 servlet
容器中运行,从而支持将 JAX-RS
服务轻松部署到 “
无
JAX-RS
感知”
的容器中。
我们现在开始构建 HelloWorld
服务,然后将其部署到 Tomcat 6.0 servlet
容器中并运行。
构建 HelloWorld
在
Eclipse
中,可以使用 m2eclipse
插件来构建、部署和运行 HelloWorld
。首先,编译源代码并为 HelloWorld
服务构建 Web
归档 (WAR)
文件。要构建这个服务,指示 m2eclipse
执行安装
生 命周期阶段。(执行一个 Maven
生命周期阶段将触发项目生命周期中的此前阶段的执行。)要执行安装阶段,在 Project Explorer
视图中右键单击 HelloWorld
,然后单击
Run As > Maven install
,如
图 5
所示。
图 5.
执行 Maven
安装阶段
Maven
(从中央资源库 http://repo1.maven.org/maven2
或从镜像资源库)下载所有依赖项,并在 Windows®
中的
%HOMEPATH%/.m2/repository
或 Linux®
中的 $HOME/.m2/repository
下构建本地资源库。Maven
执行的动作记录在 Eclipse
窗口的 Console
视图中。
如果安装阶段成功结束,那么 WAR
文件 HelloWorld.war
就构建在目标目录下并部署到本地资源库中,Console
视图将显示消息 “Build successful”
。
将 HelloWorld
部署到 Tomcat
您将使用 Maven
的 Tomcat
插件。(与 Eclipse
一样,Maven
通过插件提供大量功能。)您必须将 Tomcat
插件的位置告知 Maven
,方法是指定插件的
groupId
和
artifactId
,如
图 6
所示(pom.xml
中的 45-46
行)。
图 6. Tomcat Maven
插件
您还需要告知 Maven
用于访问 Tomcat manager
应用程序的用户名和密码。Maven
使用 manager
应用程序来指导 Tomcat
部署或取消部署一个 Web
应用程序。按照以下步骤告知 Maven
身份验证信息:
声明
tomcat-maven-plugin
工件的一个
Tomcat
服务器配置 —
称为
tomcat-localhost
, 如
图 6
所示(pom.xml
中的 47-49
行)
在 Maven
设置文件 settings.xml
(位于 Windows
的 %HOMEPATH%/.m2/
或 Linux
的 $HOME/.m2
下)中定义这个配置,如
清
单 2
所示。
清单 2. Maven
settings.xml
文件
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <servers> <server> <id>tomcat-localhost</id> <username>admin</username> <password>admin</password> </server> </servers> </settings> |
了,方法是执行 Tomcat
插件的 redeploy
目标。(一个
Maven
目标(goal
) 被自身执行,这与生命周期阶段不同,后者的执行由生命周期中的此前阶段自动推进。)要执行 redeploy
目标,执行以下步骤:
在 Tomcat
配置文件 conf/tomcat-users.xml
(位于 CATALINA_HOME
下)中插入身份验证信息(如
图 7
所示),但要使用一个密码,而不是 admin
。
图 7. Tomcat
身份验证配置
通过运行以下命令启动
Tomcat
:
In Windows: %CATALINA_HOME%/bin/catalina.bat start In Linux: $CATALINA_HOME/bin/catalina.sh start |
maven tomcat:redeploy
,这条命令使用 Tomcat manager
应用程序将
HelloWorld.war
部署到 Tomcat
。为此,执行以下步骤:
在 Project
Explorer
视图中,右键单击 HelloWorld
,然后单击 Run As > Run configurations
。
在 Create,
manage, and run configurations
窗口中,选择 Maven Build > New_configuration
,然后单击 Main
选项卡(参见
图 8
)。
图 8.
运行
tomcat:redeploy
目标
单击 Browse
workspace
,然后选择 apps > HelloWorld
,然后单击
OK
。
在 Goals
文本框中,输入
tomcat:redeploy
, 然后单击 Run
。
如果 redeploy
目标成功执行,Console
视图将显示消息 “Build successful”
。
现在,您可以使用一个 HTTP
客户机(比如 Curl
)调用
HelloWorld
服务,如
清
单
3
所示。
清单 3.
在 Curl
中调用 HelloWorld
服务
$ curl -X GET http://localhost:8080/HelloWorld/rest/world
<?xml version="1.0"
encoding="UTF-8" standalone="yes"?>
<entry
xmlns="http://www.w3.org/2005/Atom"
xmlns:ns2="http://a9.com/-/spec/opensearch/1.1/"
xmlns:ns3="http://www.w3.org/1999/xhtml">
<id>helloworld:1</id>
<updated>2010-01-06T13:26:43.924+01:00</updated>
<title
type="text">Hello World!</title>
</entry>
开发一个 REST Web
服务
在这个小节中,您将从头开始创建一个 REST Web
服务来管理一个图书资源集合。这个 REST
服务的源代码可以从下面的
下
载
表中获取。
开发这样一个服务的关键步骤是:
定义资源的 URIs
,用于操作资源的方法,以及每个方法的数据格式。
定义表示图书资源的
Java
对象,提供 Java
代码或注释来编组和解组 Java
对象。
定义将 URIs
和 HTTP
方法绑定到 Java
方法的 Java
服务。
提供
javax.ws.rs.core.Application
抽象类的一个具体子类。
下面我们就执行这些步骤。
将路径和 HTTP
方法绑定到 Java
方法
这个服务支持
GET,
POST、
PUT和
DELETEHTTP
方法,并按如下方式将 HTTP
请求映射到 Java
方法:
将
POST /books
请求映射到带有
createBook(@Context
UriInfo, Book)
签名的 Java
方法。(
@Context
注释将在
JAX-RS Web
服务
小节中介绍。)用于创建一个图书资源的数据格式为:
POST /books HTTP/1.1 Content-Type: application/xml <book> <title> ... </title> <isbn> .... </isbn> </book> |
GET /books
请求映射到
Java
方法
getBook()
。用 于获取图书资源的数据格式为:
GET /books HTTP/1.1 Content-Type: application/xml |
GET /books/{id}
请求映射到带有
getBook(@PathParam("id")
int)
签名的 Java
方法。(
@PathParam
注释将在
JAX-RS Web
服务
小节中介绍。)用于获取带有 URI
模式
/books/{id}
的图书资源的数据格式为:
GET/books/{id} HTTP/1.1 Content-Type: application/xml |
PUT /books/{id}
请求映射到带有
updateBook(@PathParam("id")
int, Book)
签名的 Java
方法。用于更新带有 URI
模式
/books/{id}
的图书资源的数据格式为:
PUT/books/{id} HTTP/1.1 Content-Type: application/xml <book> <title> ... </title> <isbn> .... </isbn> </book> |
DELETE /books/{id}
请求映射到带有
deleteBook(@PathParam("id")
int)
签名的 Java
方法。用于删除带有 URI
模式
/books/{id}
的图书资源的数据格式为:
DELETE/books/{id} HTTP/1.1 Content-Type: application/xml |
用于实现这个图书集合的 Java
对象模型有 3
个类:
Book
,如
清
单 4
所示。
BookList
,如
清
单 5
所示。
Link
,如
清
单 6
所示。
清单 4. Book
类
package com.ibm.devworks.ws.rest.books; import javax.xml.bind.annotation.*; @XmlRootElement(name="book") @XmlAccessorType(XmlAccessType.FIELD) public class Book { @XmlAttribute(name="id") private int id; @XmlElement(name="title") private String title; @XmlElement(name="isbn") private String ISBN; @XmlElement(name = "link") private Link link; public Book() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getISBN() { return ISBN; } public void setISBN(String ISBN) { this.ISBN = ISBN; } public Link getLink() { return link; } public void setLink(String uri) { this.link = new Link(uri); } } |
Book
类中,您使用 Java Architecture for XML
Binding (JAXB)
注释来执行 Java
对象的编组和解组。Apache Wink
自动编组和解组带有 JAXB
注释的 Java
对象,包括创建执行编组和解组工作的
Marshaller
和
Unmarshaller
实例。
您将使用
BookList
类来表示图书对象的集合,
BookList
类将这些对象以内部存储方式存储在
ArrayList
类型的一个字段中,
ArrayList
带有 JAXB
注释,以便转换为 XML
格式。
清单 5. BookList
类
package com.ibm.devworks.ws.rest.books; import java.util.ArrayList; import java.util.Map; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlElementRef; @XmlRootElement(name="books") public class BookList { @XmlElementRef ArrayList<Book> books; public BookList() { } public BookList( Map<Integer, Book> bookMap ) { books = new ArrayList<Book>( bookMap.values() ); } } |
Link
类将链接元素插入到图书对象的 XML
表示中(参见
清
单
6
)。
清单 6. Link
类
package com.ibm.devworks.ws.rest.books; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @XmlRootElement(name="link") @XmlAccessorType(XmlAccessType.FIELD) public class Link { @XmlAttribute String href = null; @XmlAttribute String rel = "self"; public Link() { } public Link( String uri) { this.href = uri; } public Link( String href, String rel) { this.href = href; this.rel = rel; } } |
服务
现在,您已经定义了将 URIs
和 HTTP
方法绑定到
Java
方法的 Java
服务。您可以将这个服务定义为一个
Java
接口或一个类;对于前者,还需要定义实现接口的类。在接口中,您本地化 JAX-RS
注释并添加一个类来实现接口。
清
单
7
展示了
BookService
Java
接口。
@javax.ws.rs.Path
注释将这个接口指定为一个 JAX-RS
服务。注释的
/books
值定义这个服务的相对根 URI
。注释
@javax.ws.rs.POST、
@javax.ws.rs.GET、
@javax.ws.rs.PUT和
@javax.ws.rs.DELETE将 HTTP
POST、
GET、
PUT和
DELETE操作绑定到紧随其后的 Java
方法。
清单 7. BookService
接口
package com.ibm.devworks.ws.rest.books; import javax.ws.rs.*; import javax.ws.rs.core.*; @Path("/books") public interface BookService { @POST@Consumes(MediaType.APPLICATION_XML) @Produces(MediaType.APPLICATION_XML) public Response createBook(@Context UriInfo uriInfo, Book book); @GET@Produces(MediaType.APPLICATION_XML) public BookList getBook(); @Path("{id}") @GET@Produces(MediaType.APPLICATION_XML) public Book getBook(@PathParam("id") int id); @Path("{id}") @PUT@Consumes(MediaType.APPLICATION_XML) public void updateBook(@PathParam("id") int id, Book book_updated); @Path("{id}") @DELETEpublic void deleteBook(@PathParam("id") int id); } |
与接口的
@PATH("/books")
注释指定的值不同的方法,您将一个特定的
@PATH
注释附加到那些方法。
@PATH
注释是可以累积的,即,一个路径表达式后面的另一个路径表达式将附加到前面的表达式。因此,绑定到
deleteBook
方法的路径模式为
/books/{id}
。
JAX-RS
提供了一种机制,用于从一个 HTTP
请求提取信息,将信息赋予一个 Java
对象,然后将该对象注入一个 Java
方法参数。这种机制称为注入(injection
)。注入使用 Java
注释指定。在
BookService
接口中,您将插入两个注入注释:
@Context
注释从 HTTP
请求提取 URI
信息,将其转换为
UriInfo
对象,然后将这个对象作为方法参数
uriInfo
注入。
@PathParam("id")
注释匹配前面的
@Path({"id"})
注释。这个注释从 URI
模式
/books/{id}
提取
{id}
,并将其注入
getBook
方法的
id
参数的值。
注意,
BookService
的方法将 Java
对象(比如
Book
)接收为参 数并返回 Java
对象;这是可能的,因为这些对象带有
JAXB
注释,因此 Apache Wink
能够对它们进行自动编组和解组。
清
单
8
展示了实现
BookService
的类的结构。
BookServiceImpl
是一个 singleton
类,使用一个内存映射图(in-memory map
)来维护图书对象集合。singleton
实例使用多线程服务并发请求,因此它必须是线程安全的(thread-safe
)。
清单 8. BookService
实现类
package com.ibm.devworks.ws.rest.books; import javax.ws.rs.*; import java.net.URI; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; @Path("/books") public class BookServiceImpl implements BookService { private static BookServiceImpl instance = null; private BookServiceImpl() { } public synchronized static BookServiceImpl getInstance() { if(instance == null) { instance = new BookServiceImpl(); } return instance; } private Map <Integer, Book> bookMap = new ConcurrentHashMap <Integer, Book>(); private AtomicInteger seqNumber = new AtomicInteger(); public Response createBook(@Context UriInfo uriInfo, Book book) throws WebApplicationException { ... } public BookList getBook() { ... } public Book getBook(@PathParam("id") int id) throws WebApplicationException { ... } public void updateBook(@PathParam("id") int id, Book book_updated) throws WebApplicationException { ... } public void deleteBook(@PathParam("id") int id) throws WebApplicationException { ... } } |
ConcurrentHashMap
。 要生成惟一的图书 IDs
,您将使用一个
AtomicInteger
,它能确保增量操作是原子级的(atomic
),从而确 保线程安全。
设置 Application
抽象类的子类
JAX-RS Web
应用程序包含一组资源(REST Web
服务),这些资源作为 JAX-RS
抽象类
javax.ws.rs.core.Application
的子类出现。
清
单
9
中显示的
BookWebApp
类扩展了
Application
类。
清单 9.
javax.ws.rs.core.Application
的具体子类
package com.ibm.devworks.ws.rest.books; import java.util.HashSet; import java.util.Set; import javax.ws.rs.core.Application; public class BookWebApp extends Application { private Set<Object> svc_singletons = new HashSet<Object>(); private Set<Class<?>> svc_classes = new HashSet<Class<?>>(); public BookWebApp() { svc_singletons.add(BookServiceImpl.getInstance()); } @Override public Set<Object> getSingletons() { return svc_singletons; } @Override public Set<Class<?>> getClasses() { return svc_classes; } } |
的构造函数获取这个图书服务实现对象的 singleton
实例。
getSingletons
方法返回一个组,其惟一元素就是这个 singleton
。JAX-RS
在服务一个请求后并不删除这个 singleton
。
构建和部署 REST Web
服务
您将使用 Eclipse
来创建一个动态 Web
项目,这个项目包含上一小节介绍过的 Java
类和其他资源,比如 Web
应用程序部署描述符和必要的 JAR
文件。
注意:
创建一个 Eclipse
动态 Web
项目的另一种方法是从一个 archetype
(比如
maven-archetype-webapp
或
webapp-jee5
) 创建一个 Maven
项目(archetype
是一个 Maven
项目模板)。但是,在 Maven
当前版本中,生成 Eclipse
使用的项目元数据时会出现一些问题:要支持 IDE
中的自动代码构建,必须手动修改一些 Eclipse
项目文件。因此,本文使用 Eclipse
动态 Web
项目。
Web
服务的 Eclipse
项目
Eclipse
动态 Web
项目支持开发在一个 servlet
容器中运行的 Web
应用程序,因此它是用于开发 Apache Wink
服务的一个不错的项目模板。要为这个图书 REST
服务创建一个动态 Web
项目,执行以下步骤:
在 Eclipse
中,单击
File > New > Dynamic Web Project
。
在 Dynamic
Web Project Wizard
中,在 Project name
文本框中输入
Books
。
单击 Target
runtime
方框旁边的 New
创建一个 Tomcat
运行时。
在 New
Server Runtime Environment
向导页面上,单击 Apache > Apache Tomcat v6.0
,然后单击 Next
。
在 Tomcat
Server
向导页面上,单击 Browse
,
然后导航到
先
决条件
小节中定义的 CATALINA_HOME
目录。
单击 OK
,然后单击
Finish
。
在 Dynamic
Web Project
页面上,单击 Finish
。
将上一小节中介绍的 Java
类添加到刚才创建的 Books
项目中。为此,执行以下步骤:
在 Project
Explorer
视图中,打开 Books
文件夹。右键单击 Java Resources:src
,然后单击 New >
Package
。
在 Java
Package
窗口中的 Name
文本框中,输入包名称 —
com.ibm.devworks.ws.rest.books
—
并单击 Finish
。
将 Java
类添加到
com.ibm.devworks.ws.rest.books
包:
在 Project
Explorer
视图中,右键单击上述包,然后单击 New > Class
。
在 Name
文本框中,输入类名称(比如为
Book.java
输入
Book
),然后单击 Finish
。
使用 Eclipse
Java
编辑器来创建类。
然后,向项目添加构建和运行一个 Apache Wink
服务所需的 JAR
文件。当您创建这个应用程序项目时,Maven
将 JAR
文件下载到本地资源库,本地资源库驻留在 %HOMEPATH%/.m2/repository
(Windows
)或 $HOME/.m2/repository
(Linux
)中。
要将 JAR
文件添加到这个项目,执行以下步骤:
在 Project
Explorer
视图中,导航到 Books/Web Content/WEB-INF
。
右键单击 lib
,然后单击
Import > General > File System
,然后单击 Next
。
在 File
System
窗口中,从 Maven
资源库(已在导入应用程序 Apache Wink
模块时由 m2eclipse
填充)导入 JAR
文件 jsr311-api-1.0.jar
,方法是导航到包含这个 JAR
文件的目录,然后单击 OK
。在 File System
窗口中,选中这个 JAR
文件,然后单击 Finish
。
重复步骤 2
到步骤 3
,分别导入 JAR
文件
wink-server-1.0-incubating.jar
、 wink-common-1.0-incubating.jar
、slf4j-api-1.5.8.jar
和
slf4j-simple-1.5.8.jar
。
所有库都导入后,lib
目录将包含如
图 9
所示的 JAR
文件。
图 9.
一个
Apache Wink
服务所需的库
您还可以通过从下面的
下
载
部分中提供的代码样例中导入
Book
服务来创建这个 Eclipse
项目。为此,下载并解压文件,然后在 Eclipse
中单击 File > Import >
Existing Project Into Workspace
。在 Import Projects
Wizard
中,单击 Browse
,
导航到 Books
文件夹,单击 OK
,然后单击 Finish
。
将服务部署到 Tomcat
在部署描述符文件 web.xml
(如
清
单
10
所示)中,您将带有相对根路径 /*
的 URIs
映射到 Wink servlet
org.apache.wink.server.internal.servlet.RestServlet
。
RestServlet
被传递为
init-param
,这是 Books
服务提供的
Application
子类的名称。
清单 10.
BookService
部署服务描述符 web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>Book Web Application</display-name> <servlet> <servlet-name>restSdkService</servlet-name> <servlet-class>org.apache.wink.server.internal.servlet.RestServlet</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>com.ibm.devworks.ws.rest.books.BookWebApp</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>restSdkService</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app> |
服务部署到 Tomcat
了。为了进行测试,将这个 Books
服务部署到一个由 Eclipse
托管的 Tomcat
实例中并运行。为此,执行以下步骤:
在 Project
Explorer
视图中,右键单击 Books
,然后单击 Run As > Run on Server
。
在 Run on
Server
窗口中,单击 Finish
,
这将把这个 Books
服务部署到创建这个 Books
项目时配置的 Tomcat
运行时中并启动 Tomcat
。
测试完成后,您将这个 Books
服务打包到一个 WAR
文件中,以备部署到生产环境中。为此,在 Project Explorer
视图中,右键单击 Books
,然后单击
Export > WAR file
。 在 WAR
Export Wizard
中,单击 Browse
,选择创建 WAR
文件的文件夹,然后单击 Save
和 Finish
。
调用 REST Web
服务
可以使用一个支持 HTTP
操作
GET
、
POST
、
PUT
和
DELETE
的 HTTP
客户机来调用这个
Books
服务。 清
单 11
展示了如何使用 Curl
来调用这个服务。首先,您将得到所有图书的表示(最初没有图书);然后,您使用
jaxrs.xml
和 rest.xml
两个表示来创建两本图书;最后,您得到所有图书的表示和
id=2
的图书的表示。
清单 11.
调用 Books
服务
$ curl -X GET http://localhost:8080/Books/books <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <books/> $ more Books/xml/jaxrs.xml <?xml version="1.0" encoding="UTF-8"?> <book> <titleRESTful Java with JAX-RS</title> <isbn>978-0-596-15804-0</isbn> </book> $ more Books/xml/rest.xml <?xml version="1.0" encoding="UTF-8"?> <book> <title>RESTful Web Services</title> <isbn>978-0-596-52926-0</isbn> </book> $ curl -H "Content-Type: application/xml" -T Books/xml/jaxrs.xml / -X POST http://localhost:8080/Books/books $ curl -H "Content-Type: application/xml" -T Books/xml/rest.xml / -X POST http://localhost:8080/Books/books $ curl -X GET http://localhost:8080/Books/books <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <books> <book id="2"> <title>RESTful Web Services</title> <isbn>978-0-596-52926-0</isbn> <link rel="self" href="http://localhost:8080/Books/books/2"/> </book> <book id="1"> <title>RESTful Java with JAX-RS</title> <isbn>978-0-596-15804-0</isbn> <link rel="self" href="http://localhost:8080/Books/books/1"/> </book> </books> $ curl -X GET http://localhost:8080/Books/books/2 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <book id="2"> <title>RESTful Web Services</title> <isbn>978-0-596-52926-0</isbn> <link rel="self" href="http://localhost:8080/Books/books/2"/> </book>
结束语
本文展示了如何联合使用几种技术来支持 Apache Wink REST Web
服务的开发、构建和部署。Java
注释的威力简化了开发工作。
REST Web
服务支持应用程序交换链接数据。Tim
Berners-Lee
先生预言,链接数据将改变 Web
的面貌。Bill Burke
在他撰写的图书 RESTful Java with JAX-RS
中指出,通过将服务交互的复杂性限制为数据表示,REST Web
服务将服务组合性和重用提高到一个新的水平。
本文仅仅涉及 Apache Wink
服务开发的皮毛,Apache
Wink
的其他重要特性包括链接构建器、自定义消息体阅读器以及针对不受支持的数据格式的编写器。要深入了解
Apache Wink
框架,一定要看一看 Apache Wink
中包含的其他示例。
相关文章推荐
- 使用 Apache Wink、Eclipse 和 Maven 开发 RESTful Web 服务
- 使用 Apache Wink、Eclipse 和 Maven 开发 RESTful Web 服务
- 使用 Apache Wink、Eclipse 和 Maven 开发 RESTful Web 服务
- 使用 Apache Wink、Eclipse 和 Maven 开发 RESTful Web 服务
- Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-webap
- 使用maven,Apache ServiceMix开发OSGI web例子
- 使用MAVEN和Eclipse开发Web项目依赖库的问题
- 使用 Eclipse 在 Google App Engine 上创建 mashup,第 3 部分: 使用 RESTful Web 服务
- Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-webap
- Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-webap
- Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-weba
- Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-webap
- Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-webap
- eclipse安装maven插件开发WEB项目,解决错误:Failure to transfer org.apache.maven.plugins:maven-resources-plugin:pom
- Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-weba
- 2、Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-web
- Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-webap
- Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-w...
- Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-webap
- Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-webap