`

使用 Apache Wink、Eclipse 和 Maven 开发 RESTful Web 服务

    博客分类:
  • REST
阅读更多

http://www.ibm.com/developerworks/cn/web/wa-useapachewink/

 

 

 

Apache Wink 是一个促进创建和使用 REST Web 服务的 Apache 孵化器项目。通过 REST Web 服务,客户机和服务之间的交互局限于一组预定义的操作,客户机和服务器之间的交互的复杂性限制为客户机和服务之间交换的资源表示。这种方法支持构建可互操 作、可伸缩、可靠的、基于 REST 的分布式超媒体系统。

常用缩略词

  • API: 应用程序编程接口
  • HTTP: 超文本传输协议
  • IDE: 集成开发环境
  • JSON: JavaScript 对象符号
  • REST: 具象状态传输
  • URI: 统一资源标识符
  • XML: 可扩展标记语言

本文介绍如何使用 Apache Wink、Eclipse IDE 以及 Maven 项目管理工具开发、部署和运行 RESTful Web 服务。

Web 服务的 REST 方法

设计 Web 服务的 REST 方法将客户机和服务之间的交互限制到一组创建、读取、更新和删除(CRUD)操作。这些操作直接映射到 HTTP 方法 — 具体而言,映射到 POSTGETPUTDELETE 。尽管 RESTful 样式没有绑定到 HTTP 协议,本文假设 HTTP 用于客户机和服务之间的通信。

REST Web 服务在资源上执行 CRUD 操作。客户机使用资源状态的 REST 服务表示进行交换。这些表示使用的数据格式在 HTTP 请求或响应的头部中指定 — XML 和 JSON 是广泛使用的格式。数据格式可能在不同操作之间发生变化;例如,创建资源的数据格式与用于读取资源的数据格式不同。REST 服务保持资源的状态,但 — 与 servlets 不同的是 — 不保持客户机会话信息。

REST 方法支持构建可互操作、可伸缩和可靠的基于 REST 的分布式系统。例如,GETPOSTDELETE 方法是等幂的,即多次执行它们与执行一次的结果相同。由于 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 插件,执行以下步骤:

  1. 启动 Eclipse。
  2. 单击菜单栏中的 Help ,然后选择 Install new software
  3. Available Software 窗口中,单击 Add
  4. Add Site 窗口中,输入:

         Name:     Subclipse 
         Location: http://subclipse.tigris.org/update_1.6.x/
    

    然后单击 OK

  5. Available Software 窗口中,选择 Subclipse 下的 Subclipse (Required)SVNKit Client Adapter (Not required) 复选框(如 图 1 所示),然后单击 Next

    图 1. 安装 Subclipse 插件
    安装屏幕快照,显示可用软件。“Subclipse” 和 “SVNKit Client Adapter” 被选中。

  6. Install Details 窗口中,单击 Next
  7. Review Licenses 窗口中,检查许可,接受许可协议条款,然后单击 Finish
  8. 单击 Yes 重新启动 Eclipse。

安装 m2eclipse

m2eclipse 插件的安装步骤与安装 Subclipse 插件类似,但有以下几点例外:

  • Add Site 窗口中输入:

         Name:     Maven Integration for Eclipse
         Location: http://m2eclipse.sonatype.org/update/
    

    然后单击 OK

  • Available Software 窗口中,选择 Maven Integration for Eclipse (Required)Maven SCM handler for Subclipse (Optional) 复选框(如 图 2 所示),然后单击 Next

    图 2. 安装 m2eclipse 插件
    显示可用软件的屏幕快照。“Maven Integration for Eclipse” 和 “Maven SCM handler for Subclipse” 被选中。

获取 Apache Wink

现在,您可以使用 Eclipse 从资源库检查 Apache Wink 示例,将必要的 Java 归档(JAR)文件(包括 Apache Wink JAR 文件)下载到一个本地资源库,构建并运行 Apache Wink HelloWorld 示例。为此,执行以下步骤:

  1. 在 Eclipse 中,选择 File > Import 启动 Import Wizard。
  2. Select 向导页面的 Select and import source 文本框中输入 maven
  3. Maven 下,选择 Materialize Maven Projects 并单击 Next
  4. Select Maven artifacts 向导页面上单击 Add
  5. Add Dependency 页面上的 Enter groupId, artifactId 文本框中输入 org.apache.wink.example
    注意: Artifact(工件) 是一个用于 Maven 的术语,指的是设置了版本并存储在资源库中的软件包的层级结构。
  6. Search Results 区域中,选择 org.apache.wink.example apps (如 图 3 所示)并单击 OK

    图 3. org.apache.wink.example 组中的应用程序工件
    “Add dependency” 窗口,“org.apache.wink.example apps” 被选中。

  7. Select Maven artifacts 向导页面上,单击 Next ,然后单击 Finish
  8. 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;
   }
}

 

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 应用程序的部署描述符
web.xml 文件的屏幕快照

注意,URI 模式 /rest/* 被绑定到 restSdkService servlet,这个 servlet 的 context path 是 HelloWorld ,由 HelloWorld/pom.xml 文件中的 <finalName> 元素定义。这样,HelloWorld 资源的绝对 URI 是:

     http://host:port/HelloWorld/rest/world

 

图 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 资源的限定名:

org.apache.wink.example.helloworld.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 安装阶段
显示选中 “Run As --> Maven install” 路径的屏幕快照。

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,方法是指定插件的 groupIdartifactId ,如 图 6 所示(pom.xml 中的 45-46 行)。


图 6. Tomcat Maven 插件
显示 pom.xml 文件的屏幕快照

您还需要告知 Maven 用于访问 Tomcat manager 应用程序的用户名和密码。Maven 使用 manager 应用程序来指导 Tomcat 部署或取消部署一个 Web 应用程序。按照以下步骤告知 Maven 身份验证信息:

  1. 声明 tomcat-maven-plugin 工件的一个 Tomcat 服务器配置 — 称为 tomcat-localhost ,如 图 6 所示(pom.xml 中的 47-49 行)
  2. 在 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 了,方法是执行 Tomcat 插件的 redeploy 目标。(一个 Maven 目标(goal) 被自身执行,这与生命周期阶段不同,后者的执行由生命周期中的此前阶段自动推进。)要执行 redeploy 目标,执行以下步骤:

  1. 在 Tomcat 配置文件 conf/tomcat-users.xml(位于 CATALINA_HOME 下)中插入身份验证信息(如 图 7 所示),但要使用一个密码,而不是 admin

    图 7. Tomcat 身份验证配置
    Tomcat 身份验证配置

  2. 通过运行以下命令启动 Tomcat:

    In Windows:   %CATALINA_HOME%\bin\catalina.bat start
    In Linux:     $CATALINA_HOME/bin/catalina.sh start
    

  3. 执行 maven tomcat:redeploy ,这条命令使用 Tomcat manager 应用程序将 HelloWorld.war 部署到 Tomcat。为此,执行以下步骤:
    1. 在 Project Explorer 视图中,右键单击 HelloWorld,然后单击 Run As > Run configurations
    2. Create, manage, and run configurations 窗口中,选择 Maven Build > New_configuration ,然后单击 Main 选项卡(参见 图 8 )。

      图 8. 运行 tomcat:redeploy 目标
      “Run Configurations” 屏幕快照

    3. 单击 Browse workspace ,然后选择 apps > HelloWorld ,然后单击 OK
    4. 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 服务的源代码可以从下面的 下载 表中获取。

开发这样一个服务的关键步骤是:

  1. 定义资源的 URIs,用于操作资源的方法,以及每个方法的数据格式。
  2. 定义表示图书资源的 Java 对象,提供 Java 代码或注释来编组和解组 Java 对象。
  3. 定义将 URIs 和 HTTP 方法绑定到 Java 方法的 Java 服务。
  4. 提供 javax.ws.rs.core.Application 抽象类的一个具体子类。

下面我们就执行这些步骤。

将路径和 HTTP 方法绑定到 Java 方法

这个服务支持 GET , POSTPUTDELETE HTTP 方法,并按如下方式将 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 个类:


清单 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 对象,包括创建执行编组和解组工作的 MarshallerUnmarshaller 实例。

您将使用 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; 
	}
}

 

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 POSTGETPUTDELETE 操作绑定到紧随其后的 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}")
	@DELETE
	public void deleteBook(@PathParam("id") int id);	
}

 

对于其 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 实现类

				
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;
	}

}

 

BookWebApp 的构造函数获取这个图书服务实现对象的 singleton 实例。getSingletons 方法返回一个组,其惟一元素就是这个 singleton。JAX-RS 在服务一个请求后并不删除这个 singleton。


构建和部署 REST Web 服务

您将使用 Eclipse 来创建一个动态 Web 项目,这个项目包含上一小节介绍过的 Java 类和其他资源,比如 Web 应用程序部署描述符和必要的 JAR 文件。

注意: 创建一个 Eclipse 动态 Web 项目的另一种方法是从一个 archetype(比如 maven-archetype-webappwebapp-jee5 )创建一个 Maven 项目(archetype 是一个 Maven 项目模板)。但是,在 Maven 当前版本中,生成 Eclipse 使用的项目元数据时会出现一些问题:要支持 IDE 中的自动代码构建,必须手动修改一些 Eclipse 项目文件。因此,本文使用 Eclipse 动态 Web 项目。

Web 服务的 Eclipse 项目

Eclipse 动态 Web 项目支持开发在一个 servlet 容器中运行的 Web 应用程序,因此它是用于开发 Apache Wink 服务的一个不错的项目模板。要为这个图书 REST 服务创建一个动态 Web 项目,执行以下步骤:

  1. 在 Eclipse 中,单击 File > New > Dynamic Web Project
  2. 在 Dynamic Web Project Wizard 中,在 Project name 文本框中输入 Books
  3. 单击 Target runtime 方框旁边的 New 创建一个 Tomcat 运行时。
  4. New Server Runtime Environment 向导页面上,单击 Apache > Apache Tomcat v6.0 ,然后单击 Next
  5. Tomcat Server 向导页面上,单击 Browse ,然后导航到 先决条件 小节中定义的 CATALINA_HOME 目录。
  6. 单击 OK ,然后单击 Finish
  7. Dynamic Web Project 页面上,单击 Finish

将上一小节中介绍的 Java 类添加到刚才创建的 Books 项目中。为此,执行以下步骤:

  1. 在 Project Explorer 视图中,打开 Books 文件夹。右键单击 Java Resources:src ,然后单击 New > Package
  2. Java Package 窗口中的 Name 文本框中,输入包名称 — com.ibm.devworks.ws.rest.books — 并单击 Finish
  3. 将 Java 类添加到 com.ibm.devworks.ws.rest.books 包:
    1. 在 Project Explorer 视图中,右键单击上述包,然后单击 New > Class
    2. Name 文本框中,输入类名称(比如为 Book.java 输入 Book ),然后单击 Finish
    3. 使用 Eclipse Java 编辑器来创建类。

然后,向项目添加构建和运行一个 Apache Wink 服务所需的 JAR 文件。当您创建这个应用程序项目时,Maven 将 JAR 文件下载到本地资源库,本地资源库驻留在 %HOMEPATH%\.m2\repository(Windows)或 $HOME/.m2/repository(Linux)中。

要将 JAR 文件添加到这个项目,执行以下步骤:

  1. 在 Project Explorer 视图中,导航到 Books/Web Content/WEB-INF。
  2. 右键单击 lib ,然后单击 Import > General > File System ,然后单击 Next
  3. File System 窗口中,从 Maven 资源库(已在导入应用程序 Apache Wink 模块时由 m2eclipse 填充)导入 JAR 文件 jsr311-api-1.0.jar,方法是导航到包含这个 JAR 文件的目录,然后单击 OK 。在 File System 窗口中,选中这个 JAR 文件,然后单击 Finish
  4. 重复步骤 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 服务所需的库
Project Explorer 窗口屏幕快照,WEB-INF lib 文件夹展开,显示一列 Wink JAR 文件。

您还可以通过从下面的 下载 部分中提供的代码样例中导入 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.RestServletRestServlet 被传递为 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>

 

部署描述符设置好后,就可以将这个 Books 服务部署到 Tomcat 了。为了进行测试,将这个 Books 服务部署到一个由 Eclipse 托管的 Tomcat 实例中并运行。为此,执行以下步骤:

  1. 在 Project Explorer 视图中,右键单击 Books ,然后单击 Run As > Run on Server
  2. Run on Server 窗口中,单击 Finish ,这将把这个 Books 服务部署到创建这个 Books 项目时配置的 Tomcat 运行时中并启动 Tomcat。

测试完成后,您将这个 Books 服务打包到一个 WAR 文件中,以备部署到生产环境中。为此,在 Project Explorer 视图中,右键单击 Books ,然后单击 Export > WAR file 。在 WAR Export Wizard 中,单击 Browse ,选择创建 WAR 文件的文件夹,然后单击 SaveFinish


调用 REST Web 服务

可以使用一个支持 HTTP 操作 GETPOSTPUTDELETE 的 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-1.3.0-src.tar.gz

    总结起来,"apache-wink-1.3.0-src.tar.gz"是一个包含Apache Wink 1.3.0版本源代码的压缩包,适合对RESTful Web服务感兴趣的开发者,他们可以借此深入了解Wink的内部机制,进行定制开发,并与其他Java技术结合使用,...

    apache-wink-1.4-src.tar.gz

    5. **开发和调试**:使用IDE(如Eclipse、IntelliJ IDEA)导入项目,然后就可以开始编写自己的RESTful服务或客户端代码,并进行调试。 **标签"jar"的关联:** Apache Wink的源代码中包含了许多.jar文件,它们是编译...

    sblim-gather-provider-2.2.8-9.el7.x64-86.rpm.tar.gz

    1、文件内容:sblim-gather-provider-2.2.8-9.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/sblim-gather-provider-2.2.8-9.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、更多资源/技术支持:公众号禅静编程坊

    基于pringboot框架的图书进销存管理系统的设计与实现(Java项目编程实战+完整源码+毕设文档+sql文件+学习练手好项目).zip

    本图书进销存管理系统管理员功能有个人中心,用户管理,图书类型管理,进货订单管理,商品退货管理,批销订单管理,图书信息管理,客户信息管理,供应商管理,库存分析管理,收入金额管理,应收金额管理,我的收藏管理。 用户功能有个人中心,图书类型管理,进货订单管理,商品退货管理,批销订单管理,图书信息管理,客户信息管理,供应商管理,库存分析管理,收入金额管理,应收金额管理。因而具有一定的实用性。 本站是一个B/S模式系统,采用Spring Boot框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得图书进销存管理系统管理工作系统化、规范化。本系统的使用使管理人员从繁重的工作中解脱出来,实现无纸化办公,能够有效的提高图书进销存管理系统管理效率。 关键词:图书进销存管理系统;Spring Boot框架;MYSQL数据库

    2024中国在人工智能领域的创新能力如何研究报告.pdf

    2024中国在人工智能领域的创新能力如何研究报告.pdf

    安全生产_人脸识别_移动目标跟踪_智能管控平台技术实现与应用_1741777778.zip

    人脸识别项目实战

    人脸识别_TF2_Facenet_训练预测应用仓库_1741778670.zip

    人脸识别项目实战

    安全人脸识别_对抗攻击_多模型集成_减少扰动_竞赛方案_Ne_1741779504.zip

    人脸识别项目实战

    Python实现基于CEEMDAN完全自适应噪声集合经验模态分解时间序列信号分解的详细项目实例(含完整的程序,GUI设计和代码详解)

    内容概要:本文档详细介绍了基于CEEMDAN(完全自适应噪声集合经验模态分解)的方法实现时间序列信号分解的具体项目。文中涵盖项目背景介绍、主要目标、面临的挑战及解决方案、技术创新点、应用领域等多方面内容。项目通过多阶段流程(数据准备、模型设计与构建、性能评估、UI设计),并融入多项关键技术手段(自适应噪声引入、并行计算、机器学习优化等)以提高非线性非平稳信号的分析质量。同时,该文档包含详细的模型架构描述和丰富的代码样例(Python代码),有助于开发者直接参考与复用。 适合人群:具有时间序列分析基础的科研工作者、高校教师与研究生,从事信号处理工作的工程技术人员,或致力于数据科学研究的从业人员。 使用场景及目标:此项目可供那些面临时间序列数据中噪声问题的人群使用,尤其适用于需从含有随机噪音的真实世界信号里提取有意义成分的研究者。具体场景包括但不限于金融市场趋势预测、设备故障预警、医疗健康监控以及环境质量变动跟踪等,旨在提供一种高效的信号分离和分析工具,辅助专业人士进行精准判断和支持决策。 其他说明:本文档不仅限于理论讲解和技术演示,更着眼于实际工程项目落地应用,强调软硬件资源配置、系统稳定性测试等方面的细节考量。通过完善的代码实现说明以及GUI界面设计指南,使读者能够全面理解整个项目的开发流程,同时也鼓励后续研究者基于已有成果继续创新拓展,探索更多的改进空间与发展机遇。此外,针对未来可能遇到的各种情况,提出了诸如模型自我调整、多模态数据融合等发展方向,为长期发展提供了思路指导。

    监护人,小孩和玩具数据集 4647张原始图片 监护人 食物 孩子 玩具 精确率可达85.4% pasical voc xml格式

    监护人,小孩和玩具数据集 4647张原始图片 监护人 食物 孩子 玩具 精确率可达85.4% pasical voc xml格式

    根据提供的内容可以构建以下_1741777949.zip

    人脸识别项目实战

    `计算机视觉_人脸识别_Python_OpenCV_树莓派毕业设计`.zip

    人脸识别项目实战

    智慧生产企业园区解决方案PPT(54页).pptx

    在智慧园区建设的浪潮中,一个集高效、安全、便捷于一体的综合解决方案正逐步成为现代园区管理的标配。这一方案旨在解决传统园区面临的智能化水平低、信息孤岛、管理手段落后等痛点,通过信息化平台与智能硬件的深度融合,为园区带来前所未有的变革。 首先,智慧园区综合解决方案以提升园区整体智能化水平为核心,打破了信息孤岛现象。通过构建统一的智能运营中心(IOC),采用1+N模式,即一个智能运营中心集成多个应用系统,实现了园区内各系统的互联互通与数据共享。IOC运营中心如同园区的“智慧大脑”,利用大数据可视化技术,将园区安防、机电设备运行、车辆通行、人员流动、能源能耗等关键信息实时呈现在拼接巨屏上,管理者可直观掌握园区运行状态,实现科学决策。这种“万物互联”的能力不仅消除了系统间的壁垒,还大幅提升了管理效率,让园区管理更加精细化、智能化。 更令人兴奋的是,该方案融入了诸多前沿科技,让智慧园区充满了未来感。例如,利用AI视频分析技术,智慧园区实现了对人脸、车辆、行为的智能识别与追踪,不仅极大提升了安防水平,还能为园区提供精准的人流分析、车辆管理等增值服务。同时,无人机巡查、巡逻机器人等智能设备的加入,让园区安全无死角,管理更轻松。特别是巡逻机器人,不仅能进行360度地面全天候巡检,还能自主绕障、充电,甚至具备火灾预警、空气质量检测等环境感知能力,成为了园区管理的得力助手。此外,通过构建高精度数字孪生系统,将园区现实场景与数字世界完美融合,管理者可借助VR/AR技术进行远程巡检、设备维护等操作,仿佛置身于一个虚拟与现实交织的智慧世界。 最值得关注的是,智慧园区综合解决方案还带来了显著的经济与社会效益。通过优化园区管理流程,实现降本增效。例如,智能库存管理、及时响应采购需求等举措,大幅减少了库存积压与浪费;而设备自动化与远程监控则降低了维修与人力成本。同时,借助大数据分析技术,园区可精准把握产业趋势,优化招商策略,提高入驻企业满意度与营收水平。此外,智慧园区的低碳节能设计,通过能源分析与精细化管理,实现了能耗的显著降低,为园区可持续发展奠定了坚实基础。总之,这一综合解决方案不仅让园区管理变得更加智慧、高效,更为入驻企业与员工带来了更加舒适、便捷的工作与生活环境,是未来园区建设的必然趋势。

    第八届全国大学生创新创业年会-创新创业展示项目集

    本届年会的主题是“青春梦想创新创业”。通过学术论文报告、创新创业项目展示、创业项目推介、工作研讨、联谊活动、大会报告等活动,全面展示大学生最新的创新创业成果。年会共收到491所高校推荐的学术论文756篇、创新创业展示项目721项、创业推介项目156项,合计1633项,为历届年会数量最高。经过36所“985”高校相关学科专家的初评以及国家级大学生创新创业训练计划专家组的复选,最终遴选出可参加本次年会的学术论文180篇,创新创业展示项目150个,创业推介项目45项,共计375项,涉及30个省市的236所高校。年会还收到了来自澳门特别行政区、俄罗斯的13项学术论文及参展项目。这些材料集中反映了各高校最新的创新创业教育成果,也直接体现了当代大学生的创新思维和实践能力。

    人脸识别_实时_ArcFace_多路识别技术_JavaScr_1741771263.zip

    人脸识别项目实战

    6ES7215-1AG40-0XB0-V04.04.01固件4.5

    6ES7215-1AG40-0XB0_V04.04.01固件4.5

    在无人机上部署SchurVins的yaml配置文件

    在无人机上部署SchurVins的yaml配置文件

    uniapp实战商城类app和小程序源码​​​​​​.rar

    uniapp实战商城类app和小程序源码,包含后端API源码和交互完整源码。

    基于MobileNet轻量级网络实现的常见30多种食物分类

    基于MobileNet轻量级网络实现的常见30多种食物分类,包含数据集、训练脚本、验证脚本、推理脚本等等。 数据集总共20k左右,推理的形式是本地的网页推理

    2024年央国企RPA市场研究报.pdf

    2024年央国企RPA市场研究报.pdf

Global site tag (gtag.js) - Google Analytics