`
true_cp
  • 浏览: 14178 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
社区版块
存档分类

在Java上实现RESTful Web Services

    博客分类:
  • Java
阅读更多

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):

 

Resource
URI Path
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 类拥有两个方法,getUsergetUsersAsJsonArray。现上让我们暂时忘记 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

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

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 中或使用命令行创建并部署这个示例。无论哪种情况,需要具备:

  1. 如果你还没有 GlassFish V2 ,下载并安装它。
  2. Jersey 下载页面 下载最新版本的 Jersey 快照并解压缩。

(以下这几段不翻了)

 

Building and Deploying the Sample Code in NetBeans

  1. If you haven't already done so, download and install the NetBeans 5.5.1 IDE .
  2. 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.
  3. Open the Bookmark project as follows:
    • Select Open Project from the File menu.
    • Browse to the Bookmark subdirectory.
    • Click the Open Project Folder button.
  4. 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

  1. 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.
  2. 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.

  1. If you haven't already done so, download Curl .
  2. 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, an HTTP GET request is dispatched to the getUser method in the UsersResource class, which instantiates a new UserResource object. The request is further dispatched to the putUser 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
  3. 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 the getUsersListAsJson method of the UsersResource 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"]
  4. 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.

评论
1 楼 Jekey 2008-10-24  
 

相关推荐

    三步轻松实现java restful web services

    RESTEasy是一个流行的JAX-RS(Java API for RESTful Web Services)实现,它允许开发者用注解来轻松地声明服务接口。例如,我们可以使用`@Path`注解来定义服务路径,`@GET`、`@POST`等注解来指定HTTP方法,以及`@...

    RESTful WebServices中文版 完整清晰版

    如Amazon的简单存储服务与Atom发布协议等 ·探讨各种流行编程语言的Web services客户端 ·展示如何用三种流行框架实现RESTful services —— Ruby on Rails、Restlet(基于Java)和Django(基于Python) ·关注实际...

    RESTful Java Web Services

    在《RESTful Java Web Services》一书中,作者Jose Sandoval深入探讨了如何利用Java开发RESTful Web服务。 #### 二、核心REST概念 1. **无状态性**:客户端与服务器之间的交互是无状态的,即每个请求都包含处理该...

    building restful web services with spring 5 2e

    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 ...

    restful web services中英文版以及书上源码

    5. 安全性:讨论如何在RESTful服务中实现身份验证和授权,例如OAuth、JWT(JSON Web Tokens)等。 6. HATEOAS(Hypermedia as the Engine of Application State):理解这一RESTful服务的核心原则,它强调服务应...

    RESTful Java Web Services (2009).pdf

    - **Jersey's JAX-RS**:基于Java API for RESTful Web Services (JAX-RS) 的开源实现,提供了丰富的API来构建RESTful服务。 - **Restlet's Lightweight REST**:一个轻量级的REST客户端和服务端框架,适用于构建...

    RESTFUL_JAVA_WEB_SERVICES_THIRD_EDITION.pdf

    2. **Java与REST**:讨论了Java如何支持RESTful服务的实现,包括使用JAX-RS(Java API for RESTful Web Services)规范,如Jersey、RESTEasy和JAX-RS 2.0等框架。 3. **URI设计**:讨论了如何设计清晰、有意义的URI...

    RESTful Web Services with Dropwizard

    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 RESTful Web Service实战.pdf

    在Java中,我们常用JAX-RS(Java API for RESTful Web Services)来实现RESTful服务。JAX-RS为创建RESTful服务提供了便利的API,例如使用`@Path`注解定义资源路径,`@GET`、`@POST`等注解指定HTTP方法,以及`@...

    Java+restful+Web+Service实战

    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中文高清版PDF

    RESTful Web Services在JavaWeb开发中广泛应用,Java的JAX-RS(Java API for RESTful Web Services)规范提供了一系列API来支持RESTful服务的创建。例如,使用`@Path`注解定义资源路径,`@GET`、`@POST`等注解指定...

    使用-Spring-3-来创建-RESTful-Web-Services

    1. 轻松地创建 RESTful Web Services:使用 Spring 3,可以轻松地创建 Java 实现的服务器端 RESTful Web Services。 2. 无缝整合到 Spring 框架:Spring 3 的 REST 支持被无缝整合到 MVC 层中,可以很容易地应用到...

    RESTful webservices – Client API in Java - Jersey

    ### RESTful Web Services – 客户端API在Java中的应用:Jersey #### 一、RESTful Web Services 概念及特点 **REST**(Representational State Transfer)是一种用于设计网络应用程序的架构风格,其核心原则之一是...

    RESTful_Web_Services中文版.pdf

    《RESTful Web Services中文版》一书深入探讨了REST架构风格在现代Web服务设计中的核心作用,由Leonard Richardson撰写,他不仅是《Ruby Cookbook》的作者,还是包括Beautiful Soup在内的多个开源库的开发者。...

Global site tag (gtag.js) - Google Analytics