源自IBM
通过使用 Java™ API for XML Web Services (JAX-WS) 技术设计和开发 Web 服务,可以带来很多好处,能简化 Web 服务的开发和部署,并能加速 Web 服务的开发。通过此教程,可以了解如何开发将其功能作为 Web 服务公开的示例订单处理程序,从而进行所有这些工作以及其他任务。完成了此教程后,您将能够应用这些概念和新获得的知识,来使用 JAX-WS 技术为应用程序开发 Web 服务。
在本教程中,我们将设计和开发一个订单处理应用程序,并将其功能作为 Web 服务公开,以便各种使用者以独立于平台的方式提交订单信息。
要运行此教程中的示例,需要安装 Java Platform, Standard Edition (Java SE) 6.0。
1、JAX-WS 简介
JAX-WS 是用于简化使用 Java 构造 Web 服务和 Web 服务客户机的工作的技术。该技术提供了完整的 Web 服务堆栈,可减少开发和部署 Web 服务的任务。JAX-WS 支持 WS-I Basic Profile 1.1,后者可确保使用 JAX-WS 堆栈开发的 Web 服务能够供采用 WS-I Basic Profile 标准使用任意语言开发的任意客户机使用。JAX-WS 还包括了 Java Architecture for XML Binding (JAXB) 和 SOAP with Attachments API for Java (SAAJ)。
JAXB 提供了一种非常方便的方法来将 XML 模式映射到 Java 代码的表示形式,从而支持数据绑定功能。JAXB 消除了将 SOAP 消息中的 XML 模式消息转换为 Java 代码的工作,因而不必全面了解 XML 和 SOAP 解析。JAXB 规范定义 Java 和 XML 模式之间的绑定。SAAJ 提供了标准的方法来处理 SOAP 消息中包含的 XML 附件。
而且,JAX-WS 提供了用于将传统 Java 对象(Plain Old Java Object,POJO)类转换为 Web 服务的 Annotation 库,从而加速了 Web 服务的开发工作。另外,它还指定了从采用 Web 服务描述语言(Web Services Description Language,WSDL)定义的服务到实现该服务的 Java 类之间的详细映射。采用 WSDL 定义的任意复杂类型都通过遵循 JAXB 规范定义的映射来映射为 Java 类。JAX-WS 之前与 Java Platform, Enterprise Edition (Java EE) 5 绑定。而 JAX-WS 2.0 规范是作为 Java Community Process (JCP) 的 JSR 224 开发的。
2、开发 Web 服务
进入 JAX-WS 时代的最好方法莫过于首先开发一个 Web 服务。可以采用以下两种方法之一开发 Web 服务:
· 契约优先:从 WSDL 契约着手,生成 Java 类来实现服务。
· 代码优先:从 Java 类着手,使用 Annotation 来生成 WSDL 文件和 Java 接口。
契约优先 WSDL 方法需要对用于定义消息格式的 WSDL 和 XML 模式定义(XML Schema Definition,XSD)有良好的理解。如果您对 Web 服务相当陌生,最好从代码优先方法着手,本教程中将使用此方法开发 Web 服务。
使用代码优先方法时,将从实现希望作为服务公开的功能的 Java 类或类入手。在已经提供了 Java 实现且需要将实现作为服务公开的情况下,代码优先方法尤为有用。
让我们首先创建一个订单处理 Web 服务,用于接受订单信息、配送信息和订购物品并最终生成确认 ID 作为响应。订单处理服务的代码如清单 1 中所示。这是一个虚拟实现,将在控制台输出客户 ID 和物品数量,然后输出虚拟订单 ID A1234。
package com.ibm.jaxws.tutorial.service; import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import com.ibm.jaxws.tutorial.service.bean.OrderBean; //JWS annotation that specifies that the portType name of the //Web service is "OrderProcessPort," the service name //is "OrderProcess," and the targetNamespace used in the generated //WSDL is "http://jawxs.ibm.tutorial/jaxws/orderprocess." @WebService(serviceName = "OrderProcess", portName = "OrderProcessPort", targetNamespace = "http://jawxs.ibm.tutorial/jaxws/orderprocess") //JWS annotation that specifies the mapping of the service onto the // SOAP message protocol. In particular, it specifies that the SOAP messages //are document literal. @SOAPBinding(style=SOAPBinding.Style.DOCUMENT,use=SOAPBinding.Use.LITERAL, parameterStyle=SOAPBinding.ParameterStyle.WRAPPED) public class OrderProcessService { @WebMethod public OrderBean processOrder(OrderBean orderBean) { // Do processing... System.out.println("processOrder called for customer" + orderBean.getCustomer().getCustomerId()); // Items ordered are if (orderBean.getOrderItems() != null) { System.out.println("Number of items is " + orderBean.getOrderItems().length); } //Process order. //Set the order ID. orderBean.setOrderId("A1234"); return orderBean; } } |
OrderBean 中包含订单信息,如清单 2 中所示。具体来说,其中包含对客户、订单项和配送地址对象的引用。
清单 2. 包含订单信息的 OrderBean 类
package com.ibm.jaxws.tutorial.service.bean; public class OrderBean { private Customer customer; private Address shippingAddress; private OrderItem[] orderItems; private String orderId; public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } public String getOrderId() { return orderId; } public void setOrderId(String orderId) { this.orderId = orderId; } public Address getShippingAddress() { return shippingAddress; } public void setShippingAddress(Address shippingAddress) { this.shippingAddress = shippingAddress; } public OrderItem[] getOrderItems() { return orderItems; } public void setOrderItems(OrderItem[] orderItems) { this.orderItems = orderItems; } } |
开发 JAX-WS Web 服务的起点是一个使用 javax.jws.WebService Annotation 进行了标注的 Java 类。所使用的 JAX-WS Annotation 属于 Web Services Metadata for the Java Platform 规范 (JSR-181) 的一部分。您可能已经注意到了,OrderProcessService 使用 WebService Annotation 进行了标注,而后者将类定义为了 Web 服务端点。
OrderProcessService 类(带有 @javax.jws.WebService Annotation 的类)隐式地定义了服务端点接口(Service Endpoint Interface,SEI),用于声明客户机可以对服务调用的方法。除了使用 @WebMethod Annotation 标注且 exclude 元素设置为 true 的方法外,类中定义的所有公共方法都会映射到 WSDL 操作。@WebMethod Annotation 是可选的,用于对 Web 服务操作进行自定义。除了 exclude 元素外,javax.jws.WebMethod Annotation 还提供 operation name 和 action 元素,用于在 WSDL 文档中自定义操作的 name 属性和 SOAP action 元素。这些属性是可选的;如果未定义,会从类名称派生缺省值。
实现 Web 服务后,需要生成部署服务所需的所有构件,然后将 Web 服务打包为部署构件(通常为 WAR 文件),并将 WAR 文件部署到任何支持 JAX-WS 2.0 规范的兼容服务器上。通常生成的构件是提供基于服务接口将 Java 对象转换为 XML、WSDL 文件和 XSD 模式的功能的类。
出于测试目的,Java 6 绑定了一个轻量级 Web 服务器,可以通过调用简单的 API 调用将 Web 服务发布到该服务器上。接下来我们将了解如何使用此方法测试 Web 服务。
运行 wsgen 工具,以生成订单处理 Web 服务的 JAX-WS 可移植构件。此工具将读取 Web SEI 类,并生成 Web 服务部署和调用所需的所有构件。wsgen 工具生成需要发布的 Web 服务的 WSDL 文件和 XSD 模式。
为了生成 JAX-WS 构件,首先需要编译服务和 Bean 源文件:
① 打开命令提示符,并进入到 c:\JAXWS-Tutorial目录(本教程中使用的源文件所在目录)。
② 运行以下命令,以编译 Java 文件,并将类文件放入其各自文件夹中:
javac com\ibm\jaxws\tutorial\service\*.java com\ibm\jaxws\tutorial\service\bean\*.java
③ 运行以下命令,以生成 JAX-WS 构件:
wsgen -cp . com.ibm.jaxws.tutorial.service.OrderProcessService -wsdl
④ wsgen 工具提供了大量的选项,例如,其中提供了 -wsdl 选项,用于生成服务的 WSDL 和模式构件。运行此命令后,应该在 JAXWS-Tutorial 文件夹中看到生成的 OrderProcess.wsdl和OrderProcess_schema1.xsd,而且会看到在 com\ibm\jaxws\tutorial\service\jaxws 文件夹中创建了 JAX-WS 构件。生成了构件后,运行以下 Web 服务发布器客户机,以发布订单处理 Web 服务。
⑤ 从 c:\JAXWS-Tutorial 文件夹运行以下命令,以编译 OrderWebServicePublisher:
javac com\ibm\jaxws\tutorial\service\publish\OrderWebServicePublisher.java
⑥ 然后运行以下命令:
java com.ibm.jaxws.tutorial.service.publish.OrderWebServicePublisher
⑦ 运行 Java 程序后,应该看到以下消息: The Web service is published at http://localhost:8080/OrderProcessWeb/orderprocess. To stop running the Web service, terminate this Java process.
这会将订单 Web 服务发布到 http://localhost:8080/OrderProcessWeb/orderprocess。可以通过显示订单处理 Web 服务生成的 WSDL 来验证 Web 服务是否在运行:
⑧ 打开浏览器,并导航到 http://localhost:8080/OrderProcessWeb/orderprocess?wsdl。
5、分析 OrderWebServicePublisher
在分析 WSDL 和模式构件前,让我们分析一下 OrderWebServicePublisher 的代码。清单 3 提供了 OrderWebServicePublisher 客户机的源代码。
清单 3. 用于发布订单处理 Web 服务的代码
package com.ibm.jaxws.tutorial.service.publish; import javax.xml.ws.Endpoint; import com.ibm.jaxws.tutorial.service.OrderProcessService; public class OrderWebServicePublisher { public static void main(String[] args) { Endpoint.publish("http://localhost:8080/OrderProcessWeb/orderprocess", new OrderProcessService()); } } |
通过 Endpoint.publish() 方法,可以方便地发布和测试 JAX-WS Web 服务。publish() 接受两个参数:Web 服务的位置和 JAX-WS Web 服务实现类。publish() 方法在指定的 URL(本例中为本地主机,端口为 8080)创建轻量级 Web 服务器,并将 Web 服务部署到该位置。此轻量级 Web 服务器在 Java 虚拟机(Java Virtual Machine,JVM)中运行,可通过调用 endpoint.stop() 方法以有条件的方式终止,或终止 OrderWebServicePublisher 客户机。
要查看生成的订单处理 Web 服务 WSDL,在浏览器中键入以下 URL 位置: http://localhost:8080/OrderProcessWeb/orderprocess?wsdl.
让我们分析 WSDL 一些重要方面的内容,并了解如何基于 JAX-WS 元数据生成 WSDL 和模式构件,首先要分析的是生成的 XSD。此内容使用 xsd:import 标记导入到 WSDL 文件中(请参见清单 4);schemaLocation 指定 XSD 的位置。
清单 4. 包含订单处理模式定义的 WSDL 文件
<types> <xsd:schema> <xsd:import namespace="http://jawxs.ibm.tutorial/jaxws/orderprocess" schemaLocation="OrderProcess_schema1.xsd"/> </xsd:schema> </types> |
在浏览器中打开 schemaLocation (http://localhost:8080/OrderProcessWeb/orderprocess?xsd=1),以查看模式定义在浏览器中呈现的情况。让我们分析一下其中的情况:模式定义最开始是 targetNamspace 和 tns 声明,映射到在 OrderProcessService 的 @WebService Annotation 中定义的 targetNamespace http://jawxs.ibm.tutorial/jaxws/orderprocess。清单 5 给出了对应的代码。