简介: 使用 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
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 方法包括 GET
、POST
、PUT
和 DELETE
。
总之,REST 仅仅是一个规范,提供了一种标准方法供用户使用 Web 服务风格中的 HTTP 请求方法调用对 Web 资源的操作。REST 与 HTTP 紧密相关并利用了所有的 HTTP 特性,比如方法、头和类型。
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 来调用这些功能并管理您的订单应用程序。在开发此应用程序之前,先要定义用例:
- 用户创建订单(生成惟一的订单 ID)。
- 用户查询订单细节(基于订单 ID)。
- 用户查询所有订单。
使用 URI 调用每个操作,这通常是 Web 服务的调用方法。每个操作对应于如下的 HTTP 请求方法之一:GET
、POST
、PUT
和DELETE
。这个 API 使用 Java Rest Annotations (JRA) 映射操作到 HTTP/URI 谓词组合。表 1 列出了 JRA/谓词组合。
JRA | HTTP 请求方法 | 动词 |
---|---|---|
@Get | GET |
get |
@Post | POST |
add /create |
@Put | PUT |
update |
@Delete | DELETE |
delete |
要开发一个 RESTful Web 服务,首先要创建一个 Service Endpoint Interface (SEI) 和一个实现类。然后使用一个基于 Spring 的 CXF 配置文件进行连接。执行如下步骤:
- 创建一个 SEI 并用 REST 注释标注。
- 创建这个实现类。
- 创建 beans.xml,使用 HTTP 绑定将这个服务类定义为 Spring bean,将其作为 JAX-WS 端点发布。
- 创建 web.xml。
所创建的 SEI 名为 OrderProcess
,充当一个资源表示接口。Order
类是一个资源类。清单 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 所示。
方法 | URI |
---|---|
getOrder |
/orders/{id} |
getOrders |
/orders |
addOrder |
/orders |
现在可以创建 OrderProcessImpl
实现类,如清单 2 所示。
@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 所示。
<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 的请求/响应数据不应使用作为操作名称的根元素包装起来。
<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
类。
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 时的输出。
本文展示了 GET
和 POST
方法的使用。您了解了有关 REST 架构风格的特性和概念以及如何使用它与 CXF 开发 RESTful 服务。
RESTful HTTP 提供了访问和处理资源的方式的独特概念以及 Web 服务开发的全新角度。随着基于 Web 的开发越来越流行和常见,REST 技术必将越来越好。
下载
描述 | 名字 | 大小 | 下载方法 |
---|---|---|---|
Order application | orderapp_rest.zip | 12KB | HTTP |
学习
- 阅读教程 “设计和开发 JAX-WS 2.0 Web 服务”(developerWorks,2007 年 9 月),以获取使用 JAX-WS 技术来开发 Web 服务的逐步指南。
- 阅读 Hands on Web Services 一书,了解关于如何设计和开发实际 Web 服务应用程序的全面实践信息。
- 阅读文章 “使用 MVC 样式的 Web 服务体系结构”(developerWorks, 2002 年 2 月),以了解如何应用模型-视图-控制器 (MVC) 体系结构来调用静态或动态 Web 服务。
- 阅读教程 “Deliver Web services to mobile apps”(developerWorks, 2003 年 1 月)解释了如何使用支持 Java 2 Platform, Micro Edition (J2ME) 的移动设备访问 Web 服务。
- IBM developerWorks SOA and Web services 专区 提供了大量的文章,以及关于如何开发 Web 服务应用程序的初级、中级和高级教程。
- 使用 IBM SOA Sandbox 进行试验!通过 IBM SOA 进行实际的亲手实践来提高您的 SOA 技能。
- IBM SOA 网站 提供 SOA 的概述,并介绍 IBM 是如何帮助您实现 SOA 的。
- 随时关注 developerWorks 技术活动和网络广播。
- 访问 Safari 书店,阅读关于这些和其他技术主题的图书。 .
- 查看 Web services on demand 演示。