- 浏览: 14319 次
- 性别:
- 来自: 广州
By Jakub Podlesak and Paul Sandoz 翻译 CP
这篇技术文章将为你展示如何在 Java 上使用 JAX-RS: Java API for RESTful Web Services (JSR-311) 和它的参考实现 - Jersey 来编写 RESTful 风格的 Web Services。你可以学习到一些 Representational State Transfer (REST) 的设计原则和 JAX-RS与 Jersey 的入门知识。
这篇文章使用了一个简单的示例程序来演示一些 JAX-RS 的概念和技术。你可以从 Jersey 下载页面 下载最新版本的 Jersey 快照来得到这些示例。这篇文章所使用的示例源代码可以在示例程序中找到(下载包包含了示例程序)。
RESTful Web Services 简介
Representational State Transfer (REST) 与万维网 (World Wide Web) 类似,是一种分布式系统的软件架构方式。这个名词是Roy Fielding在他2000年的博士论文中提出的,现如今已经在互联网社区广为人知。REST的一个重要概念是对资源(resources)的扩展,如可以用一个全局的定位符来引用,即所谓的URI。为了维护这些资源,网络组件之间、服务器端与客户端之间通过一种标准接口(如HTTP)来交流和交换这些资源的表现(representations)。
RESTful web services 即使用RESTful架构风格构建的服务。由于其轻量的特性和在HTTP上直接传输数据的能力,在互联网服务部署技术的选择上,使用RESTful风格构建服务正在逐渐成为基于SOAP技术的有力挑战者。
RESTful Web Service 原则
一个 RESTful web service 是符合以下原则的:
- 资源与表现。与以往仅仅为每个 web service 定义一个端点(endpoint)并且由该端点来执行相应的操作不同,你必须提供的是资源的访问方式。一个资源意味着可由客户端访问的web程序的一部分。因为不可能在网络上直接进行的资源的传输,所以我们实际上提供的是资源的表现。
- 可定位性与互连接性。资源具备表现,同时也必须具备一个用于定位的地址。在 REST 中,每个资源至少必须拥有一个地址,即 URI。只须指定 URI 便可定位到资源,这便是所谓的“可定位性”。在发布Web程序的时候,我们同时发布许多不同互相连接在一起的URI。因为互连接性,我们只须提供给客户端一个“引导 URI”便可以访问所有的 URI。
- 同样形式的接口。除了资源的表现和URI之外,我们还需要一个连接协议来为服务建立连接。在REST架构中,所有资源都使用同一套方法进行链接,即无论你访问哪一个 URI,都必须使用同一套连接接口。以实际应用为例,无论你访问任何一个万维网地址,你的网络浏览器总是使用 HTTP GET 方法来返回和显示相应的 web 页面。
- 无状态性。无状态性意味着一个 REST 的 web 程序不会为客户端保留任何信息。REST 不应使用 HTTP 会话(sessions)。每个客户端负责保存自己的状态(如果有需要的话)。服务端只维护资源和向客户端提供统一形式的接口。
JAX-RS 与 Jersey
JAX-RS为 在 Java 上构建 RESTful 风格的 web services 提供了一组标准 API。这组API基本上由一组注解(annotations)和相关的类和接口组成的。我们可以通过为 POJO 添加注解来发布 web services。目前这组 API 还尚未完成,最终的完成版本会成为 Java EE 6 的一部分。可以在这里 找到更多关于 JAX-RS 的信息。
Jersey 是 JAX-RS 的参考实现。你可以从 Jersey 的下载页面 找到它的分发包。如果你下载了最新版本的 Jersey 快照并解压缩,你会看到 Jersey 的实现与一些示例程序。我们可以从这些示例程序学习如何使用 Jersey。下面让我们开始看看其中一个示例。
JAX-RS 示例: The Bookmark Application
Bookmark 程序是随着 Jersey 发布的其中一个示例。我们可以在 examples/Bookmark
目录下找到它。这个示例程序演示了如何使用 JAX-RS API 来维护用户保存的书签信息。如果我们运行这个程序并且指定一个用户,便宜得到如下的返回信息:
{sdesc":"test desc","userid":"testuserid","uri":
"http://java.sun.com","ldesc":"long test description"}
这里使用了 JavaScript Object Notation (JSON) 数据封装格式.
浏览 examples\Bookmark\src\java\com\sun\ws\rest\samples\bookmark\resources 目录,会发现以下这些资源:
UsersResource
: 表现了用户列表UserResource
: 表现了一个特定的用户BookmarksResource
: 表现一个特定用户的书签列表BookmarkResource
: 表现了一个特定的书签
前面提到了我们可以通过指定URI来定位资源。然而,要访问一个资源,我们还需要指定连接协议,如 HTTP。下面是 Bookmark 程序中资源对应的 URI 和 HTTP 方法(methods):
UsersResource
|
/users
|
GET
|
UserResource
|
/users/{userid}
|
GET, PUT, DELETE
|
BookmarksResource
|
/users/{userid}/bookmarks
|
GET, POST
|
BookmarkResource
|
/users/{userid}/bookmarks/{bmid}
|
GET, PUT, DELETE
|
为了了解 JAX-RS 的基础知识,首先让我们来关注其中两个资源: UsersResource
and UserResource
.
UsersResource
这是 UsersResource
类的代码片断:
@UriTemplate("/users/") public class UsersResource { @HttpContext UriInfo uriInfo; @PersistenceUnit(unitName = "BookmarkPU") EntityManagerFactory emf; /** Creates a new instance of Users */ public UsersResource() { } public List<UserEntity> getUsers() { return emf.createEntityManager().createQuery( "SELECT u from UserEntity u").getResultList(); } @UriTemplate("{userid}/") public UserResource getUser(@UriParam("userid") String userid) { return new UserResource( uriInfo, emf.createEntityManager(), userid); } @HttpMethod("GET") @ProduceMime("application/json") public JSONArray getUsersAsJsonArray() { JSONArray uriArray = new JSONArray(); UriBuilder ub = null; for (UserEntity userEntity : getUsers()) { ub = (ub == null) ? uriInfo.getBuilder() : ub.clone(); URI userUri = ub. path(userEntity.getUserid()). build(); uriArray.put(userUri.toString()); } return uriArray; } }
在上面这段代码中,UsersResource
类使用了 @UriTemplate("/users/")
注解。@UriTemplate 注解定义资源的URI路径。在上面的例子里定义了URI路径为
/users/:
@UriTemplate("/users/")
Annotating the class with a @UriTemplate
annotation makes the class a "Root resource class." It also means that for client requests that access the /users/
URI path, this resource is responsible for providing appropriate responses. Note too that the /users/
URI path is the bootstrap URI path for the entire Bookmark web application.
标注 @UriTemplate 注解使得该类成为“根资源类”。这意味着该类负责响应客户端对访问
/users/
URI 路径的请求。要注意到 /users/
URI 路径同时也是整个 Bookmark 程序的“引导 URI”。
另一个在 UsersResource
用到的 JSR-311 注解是 @HttpContext。
@HttpContext UriInfo uriInfo;
这个注解把信息注入给类的属性和方法的参数。在 UsersResource
类中,@HttpContext
注解把有关URI的信息注入到 uriInfo
变量中。
UsersResource
类中的方法
UsersResource
类拥有两个方法,getUser
和 getUsersAsJsonArray。现上让我们暂时忘记
getUser
而先来关注一下 getUsersAsJsonArray。
getUsersAsJsonArray
方法返回所有用户资源的 URI 列表。这个方法使用了两个 JSR 311 注解:@HttpMethod
和 @ProduceMime
。@HttpMethod 注解指定了被注解的方法应使用HTTP requests方式来处理和响应。在这个例子中,指定了
getUsersAsJsonArray
方法响应
(serves,在这里不是很确定这个词怎么翻) HTTP GET 请求。
@HttpMethod("GET")
像这样的响应 REST 请求的方法我们称之为“资源方法”(Resource methods)。
@ProduceMime
注解一个方法的返回
(produce,同样翻得很心虚-_-!)指定了 MIME 类型。在上面上例子里,指定了 getUsersAsJsonArray
方法返回一个 JSON 数组对象,其中的内容是所有存在的用户资源。
@ProduceMime("application/json")
Get Users Resources
这个方法返回的 JSON 数组对象看起来应该是这样:
["http://localhost:8080/Bookmark/resources/users/joe",
"http://localhost:8080/Bookmark/resources/users/mary"]
这个 JSON 数组对象包含了一组 URI, 或者说链接,它们是 joe 和 mary 这两个用户资源。
getUser
方法可以取得一个指定的用户资源。例如,如果客户端需要取得用户 joe 的信息,那么客户端可以访问以下 URI:http://localhost:8080/Bookmark/resources/users/joe
。在上面我们已经提到过 UsersResource
类会响应
所有以 /users/ 开头的 URI 路径,包括了 joe 的 URI 路径,亦即
/users/joe。
这里很重要的一点是 getUser
方法使用了 @UriTemplate("{userid}/")
这样的注解,使这个方法成了一个“子资源定位器”(Sub-resource locator)。同时 getUser
也使用了 @UriParam,这使得当
getUser
方法被调用时,当前请求 URI 路径中是 userid 的值将被注入到 userid 参数。
必须注意到
@HttpMethod
注解没有被关联到 getUser
方法。因此,可以认为这个方法输出的是一个资源类的对象。这意味着对该请求的处理会被代理到一个资源类和相应的被 @HttpMethod
注解的方法。因为 getUser
方法返回一个 UserResource
对象 (注意User后少了一个s):
public UserResource getUser(@UriParam("userid") String userid) { return new UserResource(...)
UserResource
类中的相应的方法将被调用。
Get User Resources
UserResource
如前文所述,在 UsersResource
类中对 getUser
方法的请求会被代理到一个新的 UserResource
实例中相应的方法。下面是 UserResource
类中 getUser
方法的代码片断。
@HttpMethod("GET") @ProduceMime("application/json") public JSONObject getUser() throws JSONException { if (null == userEntity) { throw new NotFoundException( "userid " + userid + "does not exist!"); } return new JSONObject() .put("userid", userEntity.getUserid()) .put("username", userEntity.getUsername()) .put("email", userEntity.getEmail()) .put("password", userEntity.getPassword()) .put("bookmarks", uriInfo.getBuilder().path("bookmarks").build()); }
可以注意到这个方法被使用了 @HttpMethod("GET")
和 @ProduceMime("application/json") 注解。在这里
getUsers
方法响应
了 HTTP GET 请求并且返回一个 JSONObject
对象。这个 JSONObject
对象包含了具体用户资源的表现,具体来说,即 userid 为 joe 的用户资源的表现。
你还可以继续观察 UserResource
类余下的源代码。你会发现其它 JSR 311 注解,比如用于定义方法可以接受的 MIME 类型的 @ConsumeMime
注解。
创建与部署示例代码
这段示例代码已经配置为一个 NetBeans 工程. 你可以在 NetBesns IDE 中或使用命令行创建并部署这个示例。无论哪种情况,需要具备:
- 如果你还没有 GlassFish V2 ,下载并安装它。
- 从 Jersey 下载页面 下载最新版本的 Jersey 快照并解压缩。
(以下这几段不翻了)
Building and Deploying the Sample Code in NetBeans
- If you haven't already done so, download and install the NetBeans 5.5.1 IDE .
- Start the NetBeans IDE. If you haven't already done so, register GlassFish V2 in NetBeans as follows:
- Right click on Servers node in the Runtime window.
- Select Add Server.
- Leave the Server as Sun Java System Application Server.
- Click the Next button.
- Click the Browse button and browse to the location that you installed GlassFish V2.
- Click the Choose button.
- Click the Next button.
- Set the Admin Password to the default, adminadmin, unless you chose a different password for GlassFish.
- Click the Finish button.
- Open the Bookmark project as follows:
- Select Open Project from the File menu.
- Browse to the Bookmark subdirectory.
- Click the Open Project Folder button.
- Build and deploy the Bookmark project as follows:
- Right click the Bookmark project node in the Projects window.
- Select Deploy Project or press F6 (Run Main Project).
Building and Deploying the Sample Code From the Command Line
- Set the
AS_HOME
environment variable to the GlassFish v2 installation directory, for example, (here shown in bash syntax):
export AS_HOME= <GF_install_dir>
where<GF_install_dir>
is the directory where you installed GlassFish v2. - Navigate below the
<sample_install_dir>/jersey
directory to the/examples/Bookmark
directory. Build the Bookmark application by entering the following command on the command line (here shown in bash syntax):
AS_HOME/lib/ant/bin/ant run-on-glassfish
Running the Sample Code
You can run the deployed Bookmark application as follows using Curl, a command line HTTP tool.
- If you haven't already done so, download Curl .
- Add a new user by entering the following command on the command line (note that the commands in this and subsequent steps are shown on multiple lines for formatting purposes):
curl -i --data "{\"userid\":\"techtip\",\"username\":
\"TechTip User\",\"email\":\"techtip@example.com\",
\"password\":\"TEST\"}" -H Content-type:application/json
-X PUT
http://localhost:8080/Bookmark/resources/users/techtip/
In response, anHTTP GET
request is dispatched to thegetUser
method in theUsersResource
class, which instantiates a newUserResource
object. The request is further dispatched to theputUser
method.
You should see output similar to the following:
HTTP/1.1 204 No Content
X-Powered-By: Servlet/2.5
Server: Sun Java System Application Server 9.1_01
Date: Thu, 01 Nov 2007 14:31:53 GMT
- Get a list of users by entering the following command on the command line:
curl -i -X GET
http://localhost:8080/Bookmark/resources/users/
This invokes thegetUsersListAsJson
method of theUsersResource
class.
You should see output similar to the following:
HTTP/1.1 200 OK
X-Powered-By: Servlet/2.5
Server: Sun Java System Application Server 9.1_01
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 01 Nov 2007 14:34:07 GMT
["http:\/\/localhost:8080\/Bookmark\/resources\/users\
/techtip"]
- Get the representation of a user by entering the following command on the command line :
curl -i -X GET
http://localhost:8080/Bookmark/resources/users/techtip/
The resulting actions here are similar to those for step 2.
You should see output similar to the following:
HTTP/1.1 200 OK
X-Powered-By: Servlet/2.5
Server: Sun Java System Application Server 9.1_01
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 01 Nov 2007 14:35:38 GMT
{"userid":"techtip","username":"TechTip User",
"email":"techtip@example.com","password":"TEST",
"bookmarks":"http:\/\/localhost:8080\/Bookmark\/resources
\/users\/techtip\/bookmarks"}
总结
这篇文章演示了如何在 Java 中使用编写符合 JAX-RS (JSR-311) 规范的 RESTful 风格的 web services。你可以从 jsr311 project 学习更多有关 JAX-RS 的内容,也可以从 Jersey project ,一个 JAX-RS 的参考实现,学习更多有关 Jersey 的内容。
About the Authors
Jakub Podlesak is a member of the Jersey project team. Previously, he participated in the development of Metro, the GlassFish v2 web services stack, as a member of the WS-Policy team.
Paul Sandoz is the co-spec lead and implementation lead for JSR 311: Java API for RESTful Web Services. He has participated in the W3C, ISO, and ITU-T standards organizations and contributed various performance-related technologies and improvements to the GlassFish web services stack, particularly in standardization, implementation, integration, and interoperability of Fast Infoset.
相关推荐
RESTEasy是一个流行的JAX-RS(Java API for RESTful Web Services)实现,它允许开发者用注解来轻松地声明服务接口。例如,我们可以使用`@Path`注解来定义服务路径,`@GET`、`@POST`等注解来指定HTTP方法,以及`@...
在《RESTful Java Web Services》一书中,作者Jose Sandoval深入探讨了如何利用Java开发RESTful Web服务。 #### 二、核心REST概念 1. **无状态性**:客户端与服务器之间的交互是无状态的,即每个请求都包含处理该...
如Amazon的简单存储服务与Atom发布协议等 ·探讨各种流行编程语言的Web services客户端 ·展示如何用三种流行框架实现RESTful services —— Ruby on Rails、Restlet(基于Java)和Django(基于Python) ·关注实际...
5. 安全性:讨论如何在RESTful服务中实现身份验证和授权,例如OAuth、JWT(JSON Web Tokens)等。 6. HATEOAS(Hypermedia as the Engine of Application State):理解这一RESTful服务的核心原则,它强调服务应...
Building RESTful Web Services with Spring 5 – Second Edition: Leverage the power of Spring 5.0, Java SE 9, and Spring Boot 2.0 Find out how to implement the REST architecture to build resilient ...
- **Jersey's JAX-RS**:基于Java API for RESTful Web Services (JAX-RS) 的开源实现,提供了丰富的API来构建RESTful服务。 - **Restlet's Lightweight REST**:一个轻量级的REST客户端和服务端框架,适用于构建...
2. **Java与REST**:讨论了Java如何支持RESTful服务的实现,包括使用JAX-RS(Java API for RESTful Web Services)规范,如Jersey、RESTEasy和JAX-RS 2.0等框架。 3. **URI设计**:讨论了如何设计清晰、有意义的URI...
Dropwizard is a Java development framework for RESTful Web Services. It was initially built by Yammer to be used as the base of their backend systems. Dropwizard is production-ready; it encapsulates ...
在Java中,我们常用JAX-RS(Java API for RESTful Web Services)来实现RESTful服务。JAX-RS为创建RESTful服务提供了便利的API,例如使用`@Path`注解定义资源路径,`@GET`、`@POST`等注解指定HTTP方法,以及`@...
3. **JAX-RS规范**:Java API for RESTful Web Services(JAX-RS)是Java中实现RESTful服务的标准API。学习使用JAX-RS提供的注解,如`@Path`、`@GET`、`@POST`、`@PathParam`等,来创建RESTful服务。 4. **jersey...
RESTful Web Services在JavaWeb开发中广泛应用,Java的JAX-RS(Java API for RESTful Web Services)规范提供了一系列API来支持RESTful服务的创建。例如,使用`@Path`注解定义资源路径,`@GET`、`@POST`等注解指定...
1. 轻松地创建 RESTful Web Services:使用 Spring 3,可以轻松地创建 Java 实现的服务器端 RESTful Web Services。 2. 无缝整合到 Spring 框架:Spring 3 的 REST 支持被无缝整合到 MVC 层中,可以很容易地应用到...
### RESTful Web Services – 客户端API在Java中的应用:Jersey #### 一、RESTful Web Services 概念及特点 **REST**(Representational State Transfer)是一种用于设计网络应用程序的架构风格,其核心原则之一是...
《RESTful Web Services中文版》一书深入探讨了REST架构风格在现代Web服务设计中的核心作用,由Leonard Richardson撰写,他不仅是《Ruby Cookbook》的作者,还是包括Beautiful Soup在内的多个开源库的开发者。...
1. JAX-RS(Java API for RESTful Web Services):Java EE 8中的JAX-RS 2.1是实现RESTful服务的基础,它定义了一套API,使得开发者能够轻松地创建和消费RESTful服务。通过使用`@Path`注解定义资源路径,`@GET`, `@...