2 创建一个 RESTful Web 服务

简介: 使用 Apache CXF 这个开源 Web 服务框架创建一个定义为 Spring bean 的 RESTful Web 服务。本文探索了使用 Representational State Transfer (REST) 架构的特性和益处并展示了如何在 CXF 中使用 REST API 轻松开发一个 RESTful 服务。

简介

在本文中,我们要构建一个订单应用程序。此应用程序的功能作为一个使用 CXF 和 Spring 的 RESTful Web 服务公开。这个 Web 服务对一个订单资源执行 read 和 add 操作。阅读本文后,您将能够应用 REST 架构风格的概念和特性并使用基于 CXF 的 REST API 构建和开发一个 RESTful Web 服务。

系统要求

要运行本文中的示例,请确保已在计算机上安装和设置了以下软件:

  • Java™ 5 或更高版本
  • Tomcat 5 或更高版本
  • Ant 构建工具
  • CXF 二进制分发版 2.1

安装上述分发版以后,设置以下环境变量:

  • JAVA_HOME(用于 Java)
  • CATALINA_HOME(用于 Tomcat)
  • ANT_HOME(用于 Ant)
  • CXF_HOME(用于 CXF)

举例来说,可以设置 CXF_HOME=C:\apache-cxf-2.1 并将以下内容添加到 PATH 环境变量:

  • JAVA_HOME\bin
  • CATALINA_HOME\bin
  • ANT_HOME\bin
 

REST 是一种 Web 架构

Web 服务可以非常复杂,这是因为 Web 服务开发常常会涉及到实现多种基础架构组件,比如 Web Services Description Language(WSDL)和 SOAP,而这些组件转而会绑定到各种其他的标准。为创建一个健壮的 Web 服务基础架构模型,每个提供 Web 服务解决方案的 Web 服务器都必须做出极大投入。从开发人员的角度看,掌握这个技术显得越来越复杂。但不要惧怕!REST 可救助大家。

RESTful Web 服务仅仅是 XML-over-HTTP 服务。一般的 Web 服务往往要求定义各种合约并需要在提供者和顾客之间进行协商,与之不同,RESTful 服务以一种简单的 XML 格式封装数据并在 HTTP 上传输,就如同对 Web 服务器发出的 Web 页面请求一样。

REST 更像是一种架构,而非一种实现或一个标准。REST 架构风格与 Web 资源相关,是由 Uniform Resource Indicator(URI)(例如, http://myweb.com/myresource)标识的一种表示。资源可以是任何持久的实体,包括 Order、Customer、 Employee 等。客户端通过此 URI 查询或更新这个资源,进而影响其具象状态更改。简言之,客户端程序可以使用各种 HTTP 方法通过 URI 访问、更新、添加或删除一个 Web 资源,并进而更改其具象状态。HTTP 方法包括 GETPOSTPUT 和 DELETE

总之,REST 仅仅是一个规范,提供了一种标准方法供用户使用 Web 服务风格中的 HTTP 请求方法调用对 Web 资源的操作。REST 与 HTTP 紧密相关并利用了所有的 HTTP 特性,比如方法、头和类型。

REST 和 CXF

CXF 是一个开源 Web 服务框架,提供了一个简单的 API 来方便地构建和开发 Web 服务。在本 系列 的 第 1 部分,您看到了使用一个基于 Spring 的 CXF 配置开发 Web 服务是多么地简单。本篇文章将向您展示开发一个 RESTful 服务亦同样地简单。

CXF 提供了三种 RESTful 风格的 Web 服务实现:

  • JAX-RS (JSR-311)
  • HTTP 绑定
  • Java API for XML Web Services (JAX-WS) Provider 和 Dispatch API
 

订单应用程序

现在可以开始创建一个允许您创建和阅读或查看订单细节的订单应用程序了。您可以使用 RESTful 架构样式和 CXF 来调用这些功能并管理您的订单应用程序。在开发此应用程序之前,先要定义用例:

  1. 用户创建订单(生成惟一的订单 ID)。
  2. 用户查询订单细节(基于订单 ID)。
  3. 用户查询所有订单。

使用 URI 调用每个操作,这通常是 Web 服务的调用方法。每个操作对应于如下的 HTTP 请求方法之一:GETPOSTPUT 和DELETE。这个 API 使用 Java Rest Annotations (JRA) 映射操作到 HTTP/URI 谓词组合。表 1 列出了 JRA/谓词组合。


表 1. JRA/谓词映射表

JRAHTTP 请求方法动词
@GetGETget
@PostPOSTadd /create
@PutPUTupdate
@DeleteDELETEdelete

开发一个 RESTful 服务

要开发一个 RESTful Web 服务,首先要创建一个 Service Endpoint Interface (SEI) 和一个实现类。然后使用一个基于 Spring 的 CXF 配置文件进行连接。执行如下步骤:

  1. 创建一个 SEI 并用 REST 注释标注。
  2. 创建这个实现类。
  3. 创建 beans.xml,使用 HTTP 绑定将这个服务类定义为 Spring bean,将其作为 JAX-WS 端点发布。
  4. 创建 web.xml。

所创建的 SEI 名为 OrderProcess,充当一个资源表示接口。Order 类是一个资源类。清单 1 显示了这个 OrderProcess SEI。


清单 1. OrderProcess SEI

				
@WebService(targetNamespace = "http://demo.order")
public interface OrderProcess {

  // Get all the orders
  @Get
 @HttpResource(location = "/orders")
 @WebResult(name = "Orders")
 public Orders getOrders();

  // Get order data based on the specified order ID
  @Get
 @HttpResource(location = "/orders/{id}")
 public Order getOrder(@WebParam(name = "GetOrder") GetOrder getOrder);

  // Add an order
  @Post
 @HttpResource(location = "/orders")
 public void addOrder(@WebParam(name = "Order") Order order);
}

 

OrderProcess SEI 有三个方法:

  • getOrder 根据指定的订单 ID 返回订单数据。
  • getOrders 返回所有订单。
  • addOrder 支持添加一个订单。此方法接受 Order bean 作为参数。

这些方法可用 REST 注释进行定义,由 URI 标识。@GET 注释用于 getOrder 和 getOrders 方法,@POST 用于 addOrder 方法。每个方法可由 @HttpResource 注释定义的 URI 标识。于是现在就有了 URI 映射,如表 2 所示。


表 2. 方法/URI 映射表

方法URI
getOrder/orders/{id}
getOrders/orders
addOrder/orders

现在可以创建 OrderProcessImpl 实现类,如清单 2 所示。


清单 2. OrderProcessImpl 服务实现

				
@WebService(endpointInterface = "demo.order.OrderProcess")
public class OrderProcessImpl implements OrderProcess {

 Map<String, Order> orders = new HashMap<String, Order>();
  private int i;

  public Orders getOrders() {
   Orders o = new Orders();
   o.setOrder(orders.values());
   return o;
  }

  public Order getOrder(GetOrder order) {
   String orderID = order.getId();
   return orders.get(orderID);

  }

  public void addOrder(Order order) {
   String orderID = "ORD0" + (++i);
   // Added as a POST request
   String customerName = order.getName(); 

   Order newOrder = new Order();
   newOrder.setOrderID(orderID);
   newOrder.setName(customerName);

   orders.put(orderID, newOrder);
   System.out.println("Order added successfully");
 }
}

 

REST 接口准备完毕。让我们来看看它的实现。 OrderProcessImpl 类实现此 SEI 及其方法。 addOrder 方法填充 HashMap 内的订单细节,将订单 ID 作为键,将 Order 实例作为值。Order bean 有两个属性:orderID 和客户名。 客户名使用 POST 请求方法添加,而订单 ID 则是生成的。 getOrder 方法接受订单 ID 作为参数,从 HashMap 获得对应的订单并返回订单。getOrders 方法返回 HashMap 的所有订单。

下一步是创建 beans.xml 配置文件,如清单 3 所示。


清单 3. beans.xml 配置文件

				
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:jaxws="http://cxf.apache.org/jaxws"
 xsi:schemaLocation="
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

 <import resource="classpath:META-INF/cxf/cxf.xml" />
 <import resource="classpath:META-INF/cxf/cxf-extension-http-binding.xml" />
 <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> 

 <jaxws:endpoint 
  id="orderProcess" 
  implementor="demo.order.OrderProcessImpl" 
  address="/"
  bindingUri="http://apache.org/cxf/binding/http" >
    <jaxws:serviceFactory > 
   <bean class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean">
 <property name="wrapped" value="false" />
   </bean>
    </jaxws:serviceFactory > 
 </jaxws:endpoint >
	  
</beans>

 

OrderProcessImpl 的 bean 定义被包装为一个 JAX-WS 端点且绑定 URI 为 http://apache.org/cxf/binding/http。这个绑定 URI 表示该服务使用 HTTP 绑带方法绑定到资源。地址是 /,与 Web 上下文相对。JaxWsServiceFactoryBean 指定了设为 false 的一个包装属性。意思是这个 bean 的基于 XML 的请求/响应数据不应使用作为操作名称的根元素包装起来。


清单 4. web.xml Web 配置文件

				
<web-app>
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>WEB-INF/beans.xml</param-value>
 </context-param>

 <listener>
  <listener-class>
   org.springframework.web.context.ContextLoaderListener
  </listener-class>
 </listener>

 <servlet>
  <servlet-name>CXFServlet</servlet-name>
  <display-name>CXF Servlet</display-name>
  <servlet-class>
   org.apache.cxf.transport.servlet.CXFServlet
  </servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>

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

 

最后创建 web.xml,加载此 CXF 配置文件。然后需要使用 Spring 上下文加载程序来加载此配置文件。还必须注册一个 CXFServlet,由它处理所有来自客户端程序的请求。

开发一个客户端

对于 POST 请求,创建一个客户端类 Client。清单 5 显示了用来添加新订单的 Client 类。


清单 5. 处理 POST 请求的 Client 类

				
public final class Client {

 public static void main(String[] args) throws Exception {
  String xml = null;
  try {
   // Make an HTTP connection to the server
   URL u = new URL("http://localhost:8080/orderapp_rest/orders");
   HttpURLConnection httpCon = (HttpURLConnection) 
   u.openConnection();
   // Set the request method as POST
   httpCon.setRequestMethod("POST"); 
   httpCon.setDoOutput(true);

   OutputStream os = httpCon.getOutputStream();
   // XML encoded in UTF-8 format
   OutputStreamWriter wout = new OutputStreamWriter(os, "UTF-8"); 
   wout.write("<?xml version=\"1.0\"?>\r\n");  
   // Add customer name as XML fragment
   wout.write("<order xmlns=\"http://demo.order\">
   <name>Rajeev</name></order>r\n"); 
   wout.flush();

   // Make implicit connection to the server
   httpCon.getContentLength(); 
   httpCon.disconnect();
   
   os.close();
  } catch (IOException e) { 
   e.printStackTrace();
  }
 }
}

 

此类建立了一个对 http://localhost:8080/orderapp_rest/orders 的 HTTP 连接并将 XML 数据作为 POST 请求发送。此 XML 包含要添加的订单细节。客户名需手动添加,订单 ID 自动生成。一旦调用此 URL,订单 ID 和客户名就会添加到 Map 集合。

对于 GET 请求,只需在浏览器内导航到 http://localhost:8080/orderapp_rest/orders/ORD01 来获得订单细节。它显示的 XML 元素包含了订单 ID 为 ORD01 的订单的数据。同样地,要显示客户下的所有订单,只需在浏览器内导航到 http://localhost:8080/orderapp_rest/orders。

图 1 显示了浏览器导航到 URI http://localhost:8080/orderapp_rest/orders/ORD01 时的输出。


图 1. GET 请求的浏览器输出
GET 请求的浏览器输出

 

结束语

本文展示了 GET 和 POST 方法的使用。您了解了有关 REST 架构风格的特性和概念以及如何使用它与 CXF 开发 RESTful 服务。

RESTful HTTP 提供了访问和处理资源的方式的独特概念以及 Web 服务开发的全新角度。随着基于 Web 的开发越来越流行和常见,REST 技术必将越来越好。


 

下载

描述名字大小下载方法
Order applicationorderapp_rest.zip12KBHTTP

关于下载方法的信息


参考资料

学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值