在你开始前
关于本教程
在本教程中,您将设计一个开发订单处理应用程序,该应用程序将其功能公开为Web服务,由此各种使用者可以以与平台无关的方式下达订单信息。
目标
在学习完本教程之后,您可以应用概念和知识来使用JAX-WS技术为您的应用程序开发Web服务。
先决条件
为了成功完成本教程,您应该对Web服务技术有基本的了解,并且对Java编程有所了解。
系统要求
要运行本教程中的示例,您需要安装Java平台标准版(Java SE)6.0。
JAX-WS简介
为什么选择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还包括用于XML绑定的Java体系结构(JAXB)和带有Java附件API的SOAP(SAAJ)。
JAXB通过提供将XML模式映射到Java代码中的表示形式的便捷方法来启用数据绑定功能。 JAXB不需要将XML消息中的XML模式消息转换为Java代码,而无需完全了解XML和SOAP解析。 JAXB规范定义了Java和XML模式之间的绑定。 SAAJ提供了一种处理SOAP消息中包含的XML附件的标准方法。
此外,JAX-WS通过提供注释库将普通的旧Java对象(POJO)类转换为Web服务来加快Web服务的开发。 它还指定了从Web服务描述语言(WSDL)中定义的服务到实现该服务的Java类的详细映射。 遵循JAXB规范定义的映射,将WSDL中定义的任何复杂类型映射为Java类。 JAX-WS以前与Java平台企业版(Java EE)5捆绑在一起。JAX-WS2.0规范是根据Java Community Process(JCP)的JSR 224开发的。
开发网络服务
合同优先方法与代码优先方法
入门JAX-WS的一个好方法是首先开发一个Web服务。 您可以使用以下两种方法之一开发Web服务:
- 首先签约:从WSDL签约开始,并生成Java类以实现服务。
- 代码优先:从Java类开始,并使用批注生成WSDL文件和Java接口。
合同优先的WSDL方法要求对WSDL和XSD(XML架构定义)进行很好的理解,以定义消息格式。 如果您是Web服务的新手,那么从代码优先方法开始是个好主意,本教程将在本教程中使用它来开发Web服务。
代码优先的Web服务开发
使用代码优先方法,您可以从一个Java类开始,这些类实现要作为服务公开的功能。 当Java实现已经可用并且您需要将实现公开为服务时,代码优先方法特别有用。
开发订单处理Web服务
首先,我们创建一个订单处理Web服务,该服务接受订单信息,运输信息和订购的商品,并最终生成一个确认ID作为响应。 清单1中提供了订单处理服务的代码。这是一个虚拟实现,可在控制台上打印客户ID和商品数量,然后返回虚拟订单ID A1234 。 (您可以在本文的“ 下载”部分中下载完整应用程序的源代码。)将源代码提取到C驱动器中,在该驱动器中创建了一个名为JAXWS-Tutorial的文件夹。 该文件夹包含源代码,如清单1所示。
清单1.订单处理Web服务实现
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
批注的Java类。 所使用的JAX-WS注释是Java平台规范(JSR-181)的Web服务元数据的一部分。 您可能已经注意到, OrderProcessService
带有WebService
批注,该批注将类定义为Web服务终结点。
OrderProcessService
类(带有@javax.jws.WebService
批注的类)隐式定义了服务端点接口(SEI),该接口声明了客户端可以在服务上调用的方法。 该类中定义的所有公共方法,除非该方法使用@WebMethod
批注注释,并且exclude元素设置为true ,否则将映射到WSDL操作。 @WebMethod
批注是可选的,用于自定义Web服务操作。 除了exclude元素之外, javax.jws.WebMethod
批注还提供了操作名称和操作元素,用于自定义操作的名称属性和WSDL文档中的SOAP操作元素。 这些属性是可选的。 如果未定义,则默认值从类名称派生。
实施Web服务后,您需要生成部署服务所需的任何工件,然后将Web服务打包为已部署的工件(通常作为WAR文件),并将WAR文件部署到支持JAX-WS的任何兼容服务器上2.0规范。 生成的典型工件是提供将Java对象转换为XML以及基于服务接口的WSDL文件和XSD模式的类。
为了进行测试,Java 6捆绑了一个轻量级Web服务器,可以通过调用简单的API调用将Web服务发布到该服务器。 接下来,您将了解如何使用这种方法测试Web服务。
发布服务
生成JAX-WS工件
通过运行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.
The web service is published at http://localhost:8080/OrderProcessWeb/orderprocess. To stop running the web service, terminate this Java process.
这将在http:// localhost:8080 / OrderProcessWeb / orderprocess位置发布订单Web服务。 您可以通过显示订单处理Web服务生成的WSDL来验证Web服务是否正在运行:
- 打开浏览器,然后导航到http:// localhost:8080 / OrderProcessWeb / orderprocess?wsdl。
分析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虚拟机(JVM)中运行,可以通过有条件地调用endpoint.stop()
方法或终止OrderWebServicePublisher
客户端来终止。
分析生成的WSDL
要查看生成的订单处理Web服务WSDL,请在浏览器中键入以下URL位置: http://localhost:8080/OrderProcessWeb/orderprocess?wsdl
。
让我们分析一些重要的WSDL方面,并从分析生成的XSD开始,看看如何基于JAX-WS元数据生成WSDL和模式构件。 使用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
批注中定义的targetNamespace
http://jawxs.ibm.tutorial/jaxws/orderprocess。 清单5提供了代码。
清单5.模式名称空间声明
<xs:schema version="1.0"
targetNamespace="http://jawxs.ibm.tutorial/jaxws/orderprocess"
xmlns:tns="http://jawxs.ibm.tutorial/jaxws/orderprocess"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
较早执行的wsgen工具生成两个包装bean类, ProcessOrder
和ProcessOrderResponse
,它们保存订单处理Web服务的输入和输出消息。 基于包装器bean类,将生成以下模式元素:
-
processOrder
的类型为processOrder
,它表示一种复杂类型,其中包含一个名称为arg0
且元素为orderBean
。 您可以看到ProcessOrder
类和processOrder
复杂类型之间的一对一映射。 -
processOrderResponse
与processOrderResponse
类型类似,其定义映射到ProcessOrderResponse
类。
让我们更仔细地查看清单6中的内容。
清单6. processOrder的模式声明
<xs:element name="processOrder" type="tns:processOrder"/>
<xs:element name="processOrderResponse" type="tns:processOrderResponse"/>
<xs:complexType name="processOrder">
<xs:sequence>
<xs:element name="arg0" type="tns:orderBean" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
清单7中所示的orderBean
类型定义映射到OrderBean
类。 orderBean
类型定义包括:
- 一个类型为
customer
customer
元素。 - 一个类型为
string
的orderId
。 -
orderItems
(这是一个数组,因为它指定的maxOccurs
属性作为unbounded
),其类型为orderItem
。 - 类型为
address
shippingAddress
。
清单7. processOrder的模式声明
<xs:complexType name="orderBean">
<xs:sequence>
<xs:element name="customer" type="tns:customer" minOccurs="0" />
<xs:element name="orderId" type="xs:string" minOccurs="0" />
<xs:element nillable="true" maxOccurs="unbounded" name="orderItems"
type="tns:orderItem" minOccurs="0" />
<xs:element name="shippingAddress" type="tns:address"
minOccurs="0" />
</xs:sequence>
</xs:complexType
类似地, customer
, orderItems
和address
的其余模式定义分别映射到Customer
, OrderItem
和Address
Java Bean。
分析了模式定义之后,让我们重新访问WSDL中的消息定义,如清单8所示processOrder
指定消息processOrder
和processOrderResponse
,它们的组成部分是processOrder
和processOrderResponse
(您已经了解了它们的模式定义)。 portType
指定操作processOrder
其输入消息为processOrder
,其输出消息为processOrderResponse
。
清单8. WSDL文档中的processOrder消息元素
<message name="processOrder">
<part element="tns:processOrder" name="parameters" />
</message>
<message name="processOrderResponse">
<part element="tns:processOrderResponse" name="parameters" />
</message>
<portType name="OrderProcessService">
<operation name="processOrder">
<input message="tns:processOrder" />
<output message="tns:processOrderResponse" />
</operation>
</portType>
接下来,定义WSDL绑定。 这将soap:binding
样式定义为document
, soap:body
使用tag作为literal
作为操作processOrder
输入和输出消息格式。 生成的WSDL定义映射到您在OrderProcessService
类上定义的@SOAPBinding
注释(请参见清单9)。
清单9. WSDL文档的绑定信息
<binding name="OrderProcessPortBinding" type="tns:OrderProcessService">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="processOrder">
<soap:operation soapAction="" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
接下来,定义WSDL服务。 这些指定端口和相应的绑定类型,以及服务的实际位置。 这通常是一个HTTP位置,在这种情况下为http:// localhost:8080 / OrderProcessWeb / orderprocess。 您可以在清单10中详细看到这一点。
清单10. WSDL文档的服务信息
<service name="OrderProcess">
<port name="OrderProcessPort" binding="tns:OrderProcessPortBinding">
<soap:address location="http://localhost:8080/OrderProcessWeb/orderprocess" />
</port>
这样,您就分析了生成的WSDL和模式构件。 清单11展示了Web服务客户端调用processOrder
操作时发送的示例SOAP请求消息。
清单11.用于processOrder操作的示例SOAP消息
<?xml version="1.0"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1=" http://jawxs.ibm.tutorial/jaxws/orderprocess"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soapenv:Body>
<ns1:processOrder>
<arg0>
<customer><customerId>A123</customerId>
<firstName>John</firstName><lastName>Smith</lastName></customer>
<orderItems><itemId>11</itemId><qty>11</qty></orderItems>
</arg0>
</ns1:processOrder>
</soapenv:Body>
</soapenv:Envelope>
创建Web服务客户端
从WSDL创建Web服务客户端
在本部分中,您将学习如何从WSDL创建Web服务客户端。 JAX-WS带有一个称为wsimport的工具,该工具用于从WSDL生成JAX-WS便携式工件。 通常生成的可移植工件包括以下内容:
- 精工
- 服务(您需要实现的服务实现类)
- JAXB从架构类型生成的类
- 从wsdl:fault映射的异常类(如果有)
客户端使用生成的工件来调用Web服务。 Web服务客户端不需要处理任何SOAP格式,例如创建或解析SOAP消息。 而是由JAX-WS运行时处理,该运行时使用生成的工件代码(JAXB生成的类)。 Web服务客户端依次处理Java对象(由JAXB生成的类),这简化了Web服务客户端的开发和对Web服务的调用。
您可以使用wsimport工具从OrderProcess
WSDL生成JAX-WS工件。 然后,创建一个Web服务客户端,该客户端使用生成的工件代码来调用订单处理Web服务。 要生成JAX-WS工件,请导航到JAXWS-Tutorial目录,并运行清单12中所示的wsimport命令。但是,在执行此操作之前,请确保已按照步骤5所述运行OrderWebServicePublisher
来发布Web服务。在生成JAX-WS工件部分中 。
清单12. wsimport命令,用于生成Web服务客户端使用的JAX-WS工件
wsimport -keep -p com.ibm.jaxws.tutorial.service.client
http://localhost:8080/OrderProcessWeb/orderprocess?wsdl
-keep
选项指示您保留生成的文件, -p
选项指定需要在其中生成构件的软件包名称。 http://localhost:8080/OrderProcessWeb/orderprocess?wsdl
指定WSDL文件的位置。 以下工件是从OrderProcessService
WSDL生成的:
- JAXB类(
Address
,Customer
,OrderBean
和OrderItem
):通过读取OrderProcessService
WSDL中定义的模式定义生成 -
RequestWrapper
和ResponseWrapper
类(ProcessOrder
和ProcessOrderResponse
):将输入和输出包装为文档文字包装样式 - 服务类(
OrderProcess
):您的客户端用于向Web服务发出请求的类 - 服务接口(
OrderProcessService
):类包含您的服务实现的接口
现在看一下如何使用上面生成的构件来创建Web服务客户端。 com \ ibm \ jaxws \ tutorial \ service \ client文件夹中提供了示例参考代码。 清单13提供了Web服务客户端的代码。
清单13.用于订单处理Web服务客户端的代码清单
package com.ibm.jaxws.tutorial.service.client;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
public class OrderClient {
final QName qName = new QName(
"http://jawxs.ibm.tutorial/jaxws/orderprocess", "OrderProcess");
public static void main(String[] args) {
if (args.length != 1) {
System.out
.println("Specify the URL of the OrderProcess Web Service");
System.exit(-1);
}
URL url = getWSDLURL(args[0]);
OrderClient client = new OrderClient();
client.processOrder(url);
}
private static URL getWSDLURL(String urlStr) {
URL url = null;
try {
url = new URL(urlStr);
} catch (MalformedURLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return url;
}
public void processOrder(URL url) {
OrderProcess orderProcessingService = new OrderProcess(url, qName);
System.out.println("Service is" + orderProcessingService);
OrderBean order = populateOrder();
OrderProcessService port = orderProcessingService.getOrderProcessPort();
OrderBean orderResponse = port.processOrder(order);
System.out.println("Order id is " + orderResponse.getOrderId());
}
private OrderBean populateOrder() {
OrderBean order = new OrderBean();
Customer customer = new Customer();
customer.setCustomerId("A123");
customer.setFirstName("John");
customer.setLastName("Smith");
order.setCustomer(customer);
// Populate Order Item.
OrderItem item = new OrderItem();
item.setItemId("11");
item.setQty(11);
order.getOrderItems().add(item);
return order;
}
}
上面列出的Web服务客户端代码:
- 通过传入
OrderProcess
Web服务的WSDL URL和服务的QName
来创建OrderProcess
类的实例。 - 创建
OrderBean
的实例,并在populateOrder()
方法中填充订单信息。 - 通过在服务上调用
getOrderProcessPort()
来检索该服务的代理(也称为端口getOrderProcessPort()
。 端口实现服务定义的服务接口。 - 调用端口的
processOrder
方法,并传递在OrderBean
的第二个列表项中创建的OrderBean
实例。 - 从服务获取
OrderBean
响应并打印订单ID。
运行Web服务客户端
要运行Web服务客户端,请首先通过运行JAXWS-Tutorial文件夹中的以下命令来编译Web服务客户端:
javac com\ibm\jaxws\tutorial\service\client\OrderClient.java
通过使用以下命令提供定单处理Web服务的WSDL URL,执行Web服务客户端:
java com.ibm.jaxws.tutorial.service.client.OrderClient http://localhost:8080/OrderProcessWeb/orderprocess?wsdl
当执行Web服务客户端时,您将在运行OrderWebServicePublisher
的控制台上看到以下输出:
processOrder called for customer A123
Number of items is 1
在执行Web服务客户端的控制台上,您将获得以下输出:
Order id is A1234
正如在客户端代码中看到的那样,您不会处理用于调用Web服务操作的任何基于SOAP或XML的格式。 取而代之的是,您处理生成的用于输入和输出消息的JAXB类,并使用服务接口和服务类对象,它们充当Web服务调用的存根。 存根负责根据JAXB批注创建SOAP请求,并将SOAP响应转换回Java对象。
您现在已经成功创建并发布了Web服务,并通过Web服务客户端执行了该服务!
摘要
在本教程中,您学习了如何使用代码优先的开发方法和JAX-WS技术来设计和开发Web服务。 JAX-WS是一个不错的选择,因为它提供了完整的Web服务堆栈,以简化Web服务的开发和部署。
您在本教程中开发的订单处理Web服务使用文档样式的Web服务,该服务可确保服务使用者和服务提供者使用XML文档进行通信。 XML文档遵守定义良好的合同,通常使用XML Schema定义创建合同。 XML模式格式指定服务使用者可以调用的业务消息的合同,并遵守该合同。 文档样式的Web服务应该是开发企业Web服务的首选方法。
翻译自: https://www.ibm.com/developerworks/webservices/tutorials/ws-jax/ws-jax.html