WSDL 样式
对于刚刚学习 WSDL 的开发人员而言,最容易混淆的是为文档选择样式。让我们了解一下不同的选项及其对 WSDL 和 SOAP 文档的影响。
编程样式和编码
在 XML 世界中,通常有两种类型的人:将 XML 视为数据格式的人和将 XML 视为文档标记的人。通常,二者永远对立。在某种程度上,这种对立也进入了 Web 服务中。有人将其视为基于 XML 的远程过程调用 (Remote Procedure Call),还有些人将其视为将 XML 信息从一个位置传递到另一个位置的方法。
对 WSDL 而言,这会在选择消息的“样式”时表现出来。创建绑定时,可以选择 Document 样式(如 Larry 为 Classifieds 服务就是选择的此样式)或 RPC 样式。这两个样式并不一定就“正确”或“错误”。但二者均具有自己的优点和缺点。
使用 RPC 样式时,要执行的方法的名称同时也是有效负载的根元素的名称。您可能会说,等一等。Classifieds WSDL 的结构不就是这样吗?是,也不是。之所以说是,是因为根元素的名称与我们希望服务执行的方法的名称一样。不过,从某种意义而言,这只是巧合;Larry 是有意这样设计服务的。
让我们看看不同的选择及其在 WSDL 和 SOAP 方面的表现。
Document/Literal
Document/Literal 样式意味着有效负载仅包含要向服务传递的实际数据。任何将消息发送到其目的地所必需的路由均以其他方式来完成,如通过 soapAction
Header 或服务的特定 URL。
这样的消息简单而直接(请参见清单 27)。
清单 27. Document/Literal 消息
<env:Envelope
xmlns:env="http://schemas.xmlSOAP.org/SOAP/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<req:content>Vintage 1963 T-Bird...</req:content>
<req:endDate>4/30/07</req:endDate>
</env:Body>
</env:Envelope>
|
请注意,有效负载没有根元素。在 WSDL 文件中,您直接定义相应的元素并将其添加到消息中(请参见清单 28)。
清单 28. Document/Literal WSDL
...
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://org.apache.axis2/xsd"
elementFormDefault="unqualified"
attributeFormDefault="unqualified">
...
<xs:element type="xs:string" name="content" />
<xs:element type="xs:string" name="endDate" />
...
</xs:schema>
</wsdl:types>
<wsdl:message name="createNewAdRequestMessage">
<wsdl:part name="part1" element="ns1:content" />
<wsdl:part name="part2" element="ns1:endDate" />
</wsdl:message>
...
<wsdl:portType name="ClassifiedServicePortType">
...
<wsdl:operation name="createNewAd">
<wsdl:input message="tns:createNewAdRequestMessage" />
<wsdl:output message="tns:createNewAdResponseMessage" />
</wsdl:operation>
...
</wsdl:portType>
...
<wsdl:binding name="ClassifiedServiceBinding"
type="tns:ClassifiedServicePortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<wsdl:operation name="createNewAd">
<soap:operation soapAction="createNewAd" style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
...
</wsdl:binding>
...
|
请注意,在 Document 样式中,属于有效负载的所有元素都在模式中具有相应的定义。另请注意,此消息具有两个截然不同的部分,每个部分各自引用一个特定的元素。
Wrapped 样式
本教程使用 Document/Literal/Wrapped 样式。此样式与 Document/Literal 样式类似,不过其有效负载具有根元素。这具有包含要执行的方法的名称的优点(虽然这并不是必需的),同时也符合 WS-I 基本概要的要求。为了便于理解,下面提供了一个简单的消息(请参见清单 29)。
清单 29. Document/Literal/Wrapped 消息
<env:Envelope
xmlns:env="http://schemas.xmlSOAP.org/SOAP/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<req:createNewAdRequest
xmlns:req="http://daily-moon.com/classifieds/">
<req:content>Vintage 1963 T-Bird...</req:content>
<req:endDate>4/30/07</req:endDate>
</req:createNewAdRequest>
</env:Body>
</env:Envelope>
|
为了保持完整性,下面提供了相关的 WSDL(请参见清单 30)。
清单 30. Document/literal/Wrapped WSDL
...
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://org.apache.axis2/xsd"
elementFormDefault="unqualified"
attributeFormDefault="unqualified">
...
<xs:element name="createNewAdRequest">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="content" />
<xs:element type="xs:string" name="endDate" />
</xs:sequence>
</xs:complexType>
</xs:element>
...
</xs:schema>
</wsdl:types>
<wsdl:message name="createNewAdRequestMessage">
<wsdl:part name="part1" element="ns1:createNewAdRequest"
/>
</wsdl:message>
...
<wsdl:portType name="ClassifiedServicePortType">
<wsdl:operation name="createNewAd">
<wsdl:input message="tns:createNewAdRequestMessage" />
<wsdl:output message="tns:createNewAdResponseMessage" />
</wsdl:operation>
...
</wsdl:portType>
...
<wsdl:binding name="ClassifiedServiceBinding"
type="tns:ClassifiedServicePortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<wsdl:operation name="createNewAd">
<soap:operation soapAction="createNewAd" style="document"
/>
<wsdl:input>
<soap:body use="literal"
namespace="http://ws.apache.org/axis2" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal"
namespace="http://ws.apache.org/axis2" />
</wsdl:output>
</wsdl:operation>
...
</wsdl:binding>
...
|
同样,有效负载中的所有元素都在模式中定义。
RPC/Literal
RPC 样式进行处理的方式略为不同。进入消息中的是 WSDL 的相应内容,而不是模式中的内容。例如,请看以下的 SOAP 消息(请参见清单 31)。
清单 31. RPC/Literal 消息
<env:Envelope
xmlns:env="http://schemas.xmlSOAP.org/SOAP/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<req:createNewAdRequest
xmlns:req="http://daily-moon.com/classifieds/">
<req:content>Vintage 1963 T-Bird...</req:content>
<req:endDate>4/30/07</req:endDate>
</req:createNewAdRequest>
</env:Body>
</env:Envelope>
|
消息本身与 Document/Literal/Wrapped 样式一样,但 WSDL 大不相同(请参见清单 32)。
清单 32. RPC/Literal 消息的 WSDL
...
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://org.apache.axis2/xsd"
elementFormDefault="unqualified"
attributeFormDefault="unqualified">
...
</xs:schema>
</wsdl:types>
<wsdl:message name="createNewAdRequest">
<wsdl:part name="content
" element="
xsd:string" />
<wsdl:part name="endDate
" element="
xsd:string" />
</wsdl:message>
...
<wsdl:portType name="ClassifiedServicePortType">
<wsdl:operation name="createNewAd">
<wsdl:input message="tns:createNewAdRequest" />
<wsdl:output message="tns:createNewAdResponseMessage" />
</wsdl:operation>
...
</wsdl:portType>
...
<wsdl:binding name="ClassifiedServiceBinding"
type="tns:ClassifiedServicePortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<wsdl:operation name="createNewAd">
<soap:operation soapAction="createNewAd" style="rpc" />
<wsdl:input>
<soap:body use="literal"
namespace="http://ws.apache.org/axis2" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal"
namespace="http://ws.apache.org/axis2" />
</wsdl:output>
</wsdl:operation>
...
</wsdl:binding>
...
|
首先,请注意模式中并未定义任何实际内容。相反,message
指定要执行的方法的名称,而 message part
直接定义每个元素。另请注意,在 RPC 样式中,消息部分的名称很重要;此名称是有效负载内的元素的名称。消息类型是直接定义的。(当然,这意味着您无法在有效负载中包含复杂元素,但由于此样式用于模拟远程过程调用,因此这并不是一个问题。)
在 portType
中,当您指定消息时,可以直接引用与这些元素一起创建的消息。然后,在绑定中,通过指定 RPC 样式,可以清楚地确定如何将所有这些内容转换为 SOAP 消息。
RPC/Encoded
我们要了解的最后一个样式是 RPC/Encoded。此样式与 RPC/Literal 类似,唯一的不同之处在于由 SOAP 消息定义实际类型信息(请参见清单 33)。
清单 33. RPC/Encoded SOAP 消息
<env:Envelope
xmlns:env="http://schemas.xmlSOAP.org/SOAP/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<req:createNewAdRequest
xmlns:req="http://daily-moon.com/classifieds/">
<req:content xsi:type="xs:string">Vintage 1963
T-Bird...</req:content>
<req:endDate
xsi:type="xs:string">4/30/07</req:endDate>
</req:createNewAdRequest>
</env:Body>
</env:Envelope>
|
用于定义此消息的 WSDL 与 RPC/Literal 一样,但向绑定添加了额外的编码信息(请参见清单 34)。
清单 34. RPC/Encoded WSDL
<wsdl:definitions xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://ws.apache.org/axis2"
xmlns:axis2="http://ws.apache.org/axis2"
xmlns:ns1="http://org.apache.axis2/xsd"
targetNamespace="http://ws.apache.org/axis2">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://org.apache.axis2/xsd"
elementFormDefault="unqualified"
attributeFormDefault="unqualified">
...
</xs:schema>
</wsdl:types>
<wsdl:message name="createNewAdRequest">
<wsdl:part name="content" element="xsd:string" />
<wsdl:part name="endDate" element="xsd:string" />
</wsdl:message>
...
<wsdl:portType name="ClassifiedServicePortType">
<wsdl:operation name="createNewAd">
<wsdl:input message="tns:createNewAdRequest" />
<wsdl:output message="tns:createNewAdResponse" />
</wsdl:operation>
...
</wsdl:portType>
<wsdl:binding name="ClassifiedServiceBinding"
type="tns:ClassifiedServicePortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="rpc" />
<wsdl:operation name="createNewAd">
<soap:operation soapAction="createNewAd" style="document" />
<wsdl:input>
<soap:body use="encoded"
encodingStyle=http://schemas.xmlsoap.org/soap/encoding/
namespace="http://ws.apache.org/axis2" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" namespace=
"http://ws.apache.org/axis2" />
</wsdl:output>
</wsdl:operation>
...
</wsdl:binding>
...
|
手动创建 WSDL 文件时,必须自己处理其中的所有内容。幸运的是,并不一定始终要手动进行创建。
使用 WSDL 生成代码
Gene 和 Francis 是该报社的团队程序员,借调自 IT 部门,Classifieds Department 可以随时调请他们处理自己的项目。他们将通过采用两种方法来进行生成 WSDL 代码的工作;Gene 将重点进行从 Java 到 WSDL 的代码生成工作,而 Francis 将从 WSDL 生成 Java 代码。
代码生成的工作原理
在 WSDL 的早期,最先出现的两个应用程序是 Java2WSDL 和 WSDL2Java。那么,不能用来实现自动化功能的自动化格式究竟有什么好处呢?当然,当时您的选择是有限的。这些代码最初是面向 RPC 样式的,很难自动生成带复杂有效负载的系统。
很快发展到了目前的阶段,这些问题得到了很好的解决。Axis2 几乎可以从任何 WSDL 文档生成 Java 代码,也能从 WSDL 生成 Java 类。它通过数据绑定实现了这个目标,在数据绑定中,XML 结构可以转换为 Java 对象,反之亦然。此生成过程将创建代码,以供随后进行更改、调整、编译和运行。
首先,Gene 从 Java 类开始,使用其生成 WSDL 文档。然后,Francis 获取该文档,并使用其生成服务和客户机。对于服务,此生成过程将创建一个框架,可以在其中添加自己的代码,以执行希望服务执行的操作。对于客户机,它将创建一个存根,以用于像使用 Java 方法一样调用 Web 服务方法。
准备工作
第一步要确保环境已经准备就绪。下载 Apache Axis2 的 0.95 版,对其进行解压缩,然后确保 lib 目录中的所有其他 *.jar 文件都位于 CLASSPATH 上。
要运行 Web 服务,请安装 Apache Geronimo(如果尚未安装)并将其启动。(具体说明,请参见第 1 部分。)下载 Axis2 v0.95 War 分发版并将其复制到 <GERONIMO_HOME>/deploy 目录。Geronimo 将自动部署 Axis2。
Java 类
Gene 从 ClassifiedService
类着手,他会将此类作为主服务,同时也作为进行测试的方法,以确保所有部分均按预期工作(请参见清单 35)。
清单 35. ClassifiedService.java
package org.dailymoon.classifieds;
public class ClassifiedService {
public static int createNewAd(String content, String endDate){
ClassifiedAd newAd = new ClassifiedAd();
newAd.setEnd(endDate);
newAd.setContent(content);
newAd.save();
return 1;
}
public static boolean editExistingAd(ClassifiedAd adToEdit){
//Do stuff with the ad here
return true;
}
public static ClassifiedList getExistingAds(){
ClassifiedAd[] listOfAds = {new ClassifiedAd(), new
ClassifiedAd(), new ClassifiedAd()};
ClassifiedList listToReturn = new ClassifiedList(listOfAds);
return listToReturn;
}
public static void finalizeIssue(String dateToFinalize){
//Don't return anything.
System.out.println(dateToFinalize + " finalized.");
}
public static void main (String args[]){
ClassifiedService.createNewAd(
"Eclipse experts needed. Contact Nick for details.",
"4/21/2006");
ClassifiedAd adToEdit = new ClassifiedAd();
adToEdit.setId(1);
adToEdit.setStart("4/8/2006");
adToEdit.setEnd("4/30/2006");
adToEdit.setContent(
"Geronimo experts needed. Contact Nick for details.");
ClassifiedService.editExistingAd(adToEdit);
ClassifiedList adList = ClassifiedService.getExistingAds();
System.out.println(adList.toString());
}
}
|
此应用程序本身相当简单。它提供了创建新广告、编辑现有广告和列出现有广告的示例。它提供了对 Gene 希望公开的四个方法(createNewAd
、editExistingAd
、getExistingAds
和 finalizeIssue
)的基本限制。
(请确保在生成 WSDL 前将 main 方法注释掉。此方法不会有负作用,但会生成不必要的额外代码。)
此类还引用其他两个类 ClassifiedAd
和 ClassifiedList
。为了生成过程能够了解如何将这些对象构建为 XML 结构,Gene 将其创建为独立的类(请参见清单 36)。
清单 36. ClassifiedAd.java
package org.dailymoon.classifieds;
public class ClassifiedAd {
private int id;
private String startDate;
private String endDate;
private String content;
public void setId(int newId){
id = newId;
}
public void setStartDate(String newStart){
startDate = newStart;
}
public void setEndDate(String newEnd){
endDate = newEnd;
}
public void setContent(String newContent){
content = newContent;
}
public void save(){
//Save data here
System.out.println("Ad saved.");
}
}
|
同样,类本身并不完整,但已经具有了相应的结构(请参见清单 37)。
清单 37. ClassifiedList.java
package org.dailymoon.classifieds;
public class ClassifiedList {
public ClassifiedAd[] listOfAds;
public ClassifiedList(ClassifiedAd[] newListOfAds){
listOfAds = newListOfAds;
}
public ClassifiedAd[] getRawAds(){
return listOfAds;
}
public String toString(){
return "This is a string of results.";
}
}
|
此处,Gene 指定 ClassifiedList
包含一个 ClassifiedAd
对象数组。
有了所有这些类后,他就可以生成 WSDL 了。
生成 WSDL 并定义消息
创建 WSDL 是一个简单的过程。Gene 从命令行发出相应的命令,如清单 38 中所示:
清单 38. 用于生成 WSDL 的命令
java org.apache.axis2.wsdl.Java2WSDL -cn
org.dailymoon.classifieds.ClassifiedService -o
|
(请注意,此命令应该全部在一行输入。)
-cn
开关指定形成服务基础的类。-o
开关指定输出目录。如果没有出现问题,此类将以静默方式执行,在输出文件中生成 ClassifiedService.wsdl 文件。此文件与 Larry 前面生成的文件很相似——它们设计为在相同的服务上工作——但需要进行一些小更改,以调整生成过程中采用一般方式命名的项。具体来说,不一定始终正确地进行参数转换,将可能必须进行重命名。
以下是生成的 WSDL 文件,其中调整的部分以黑体显示(请参见清单 39)。
清单 39. WSDL 文件
<wsdl:definitions xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://ws.apache.org/axis2"
xmlns:ns1="http://org.apache.axis2/xsd"
targetNamespace="http://ws.apache.org/axis2">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://org.apache.axis2/xsd"
elementFormDefault="unqualified"
attributeFormDefault="unqualified">
<xs:element type="ns1:ClassifiedAd" name="ClassifiedAd" />
<xs:complexType name="ClassifiedAd">
<xs:sequence>
<xs:element type="xs:int" name="id" />
<xs:element type="xs:string" name="content" />
<xs:element type="xs:string" name="endDate" />
<xs:element type="xs:string" name="startDate" />
</xs:sequence>
</xs:complexType>
<xs:element type="ns1:ClassifiedList" name="ClassifiedList" />
<xs:complexType name="ClassifiedList">
<xs:sequence>
<xs:element minOccurs="0" type="ns1:ClassifiedAd"
name="ClassifiedAd"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:element name="createNewAdRequest">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="content" />
<xs:element type="xs:string" name="endDate" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="createNewAdResponse">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:int" name="newAdId" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="editExistingAdRequest">
<xs:complexType>
<xs:sequence>
<xs:element type="ns1:ClassifiedAd"
name="existingAd" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="editExistingAdResponse">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:boolean" name="
wasSuccessful"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="getExistingAdsRequest">
<xs:complexType />
</xs:element>
<xs:element name="getExistingAdsResponse">
<xs:complexType>
<xs:sequence>
<xs:element type="ns1:ClassifiedList"
name="ClassifiedList" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="finalizeIssueRequest">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="issueToFinalize"
/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>
<wsdl:message name="createNewAdRequestMessage">
<wsdl:part name="part1" element="ns1:createNewAdRequest" />
</wsdl:message>
<wsdl:message name="createNewAdResponseMessage">
<wsdl:part name="part1" element="ns1:createNewAdResponse" />
</wsdl:message>
<wsdl:message name="getExistingAdsResponseMessage">
<wsdl:part name="part1" element="ns1:getExistingAdsResponse" />
</wsdl:message>
<wsdl:message name="editExistingAdRequestMessage">
<wsdl:part name="part1" element="ns1:editExistingAdRequest" />
</wsdl:message>
<wsdl:message name="getExistingAdsRequestMessage">
<wsdl:part name="part1" element="ns1:getExistingAdsRequest" />
</wsdl:message>
<wsdl:message name="editExistingAdResponseMessage">
<wsdl:part name="part1" element="ns1:editExistingAdResponse" />
</wsdl:message>
<wsdl:message name="finalizeIssueRequestMessage">
<wsdl:part name="part1" element="ns1:finalizeIssueRequest" />
</wsdl:message>
<wsdl:portType name="ClassifiedServicePortType">
<wsdl:operation name="finalizeIssue">
<wsdl:input message="tns:finalizeIssueRequestMessage" />
</wsdl:operation>
<wsdl:operation name="createNewAd">
<wsdl:input message="tns:createNewAdRequestMessage" />
<wsdl:output message="tns:createNewAdResponseMessage" />
</wsdl:operation>
<wsdl:operation name="editExistingAd">
<wsdl:input message="tns:editExistingAdRequestMessage" />
<wsdl:output message="tns:editExistingAdResponseMessage" />
</wsdl:operation>
<wsdl:operation name="getExistingAds">
<wsdl:input message="tns:getExistingAdsRequestMessage" />
<wsdl:output message="tns:getExistingAdsResponseMessage" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ClassifiedServiceBinding"
type="tns:ClassifiedServicePortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<wsdl:operation name="createNewAd">
<soap:operation soapAction="createNewAd" style="document" />
<wsdl:input>
<soap:body use="literal"
namespace="http://daily-moon.com/classifieds" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal"
namespace="http://daily-moon.com/classifieds" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="finalizeIssue">
<soap:operation soapAction="finalizeIssue" style="document" />
<wsdl:input>
<soap:body use="literal"
namespace="http://daily-moon.com/classifieds" />
</wsdl:input>
</wsdl:operation>
<wsdl:operation name="editExistingAd">
<soap:operation soapAction="editExistingAd" style="document" />
<wsdl:input>
<soap:body use="literal"
namespace="http://daily-moon.com/classifieds" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal"
namespace="http://daily-moon.com/classifieds" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getExistingAds">
<soap:operation soapAction="getExistingAds" style="document" />
<wsdl:input>
<soap:body use="literal"
namespace="http://daily-moon.com/classifieds" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal"
namespace="http://daily-moon.com/classifieds" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ClassifiedService">
<wsdl:port name="ClassifiedServicePort"
binding="tns:ClassifiedServiceBinding">
<soap:address location=
"http://127.0.0.1:8080/axis2/services/ClassifiedService" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
|
其中的大部分更改都只是为了方便或提供易用性;“content”要比“param0”好记得多。其中的两个更改——顶部的命名空间和底部的命名空间前缀——是由于 Axis2 的 0.95 版中的两个小软件错误而需要进行的,在您阅读本文时,可能已经不再需要这样处理了。
从 WSDL 生成服务
有了 WSDL 文件后,Francis 就可以使用其生成服务和客户机。(实际上,Francis 可以直接使用 Larry 生成的版本。)
Francis 首先生成服务器端的代码,如清单 40 中所示:
清单 40. 服务器端代码
java org.apache.axis2.wsdl.WSDL2Java -uri ClassifiedService.wsdl
-ss -sd -p org.dailymoon.classifieds -d xmlbeans -o service
|
(同样,请在一行输入此命令。)
第一个参数是 WSDL 文件的 URL。当然,您可以使用此应用程序访问远程文件。第二个开关 -ss
告知应用程序生成服务(而不是客户机)。-sd
开关告知应用程序生成 XML 服务描述符,从而更便于在生成服务代码后进行部署。下一个参数当然是包,其后紧跟数据绑定方法。可用的方法有 adb
、xmlbeans
和 jaxme
。最后,为了保持条理清楚,Francis 将服务生成到名为 source 的新目录中。
所得到的结果是数百个文件。幸运的是,您只需要处理其中的一个即可。
实现服务
尽管在本例中,服务是从 WSDL 文件生成,而该文件本身又是从 Java 类生成的,但生成的代码中并没有实际的逻辑。其中仅包含相应的结构。为了让服务实际进行一些工作,需要对框架文件进行编辑。
在此结构中,要处理的文件如清单 41 中所示:
清单 41. 从 Java 类生成的文件
service\src\org\dailymoon\classifieds\ClassifiedServicePortTypeSkeleton.
java
|
此代码中包含大量注释,当尝试自己进行配置时,这些注释就非常有用;但需要对其进行说明时,就很容易带来干扰。下面是经过清理的版本,并包含为了实现部分服务而添加的代码(请参见清单 42)。
清单 42. ClassifiedServicePortTypeSkeleton.java
package org.dailymoon.classifieds;
public class ClassifiedServicePortTypeSkeleton {
public axis2.apache.org.xsd.CreateNewAdResponseDocument
createNewAd
(axis2.apache.org.xsd.CreateNewAdRequestDocument param0 )
throws Exception {
//Todo fill this with the necessary business logic
//throw new java.lang.UnsupportedOperationException();
System.out.println("New ad requested, to end on " +
param0.getCreateNewAdRequest().getEndDate());
System.out.println(
param0.getCreateNewAdRequest().getContent());
axis2.apache.org.xsd.CreateNewAdResponseDocument
responseDoc =
axis2.apache.org.xsd.CreateNewAdResponseDocument
.Factory.newInstance();
axis2.apache.org.xsd.CreateNewAdResponseDocument
.CreateNewAdResponse response =
responseDoc.addNewCreateNewAdResponse();
response.setNewAdId(1138);
return responseDoc;
}
public void finalizeIssue
(axis2.apache.org.xsd.FinalizeIssueRequestDocument param2)
throws Exception {
//Todo fill this with the necessary business logic
}
public axis2.apache.org.xsd.EditExistingAdResponseDocument
editExistingAd
(axis2.apache.org.xsd.EditExistingAdRequestDocument param3)
throws Exception {
//Todo fill this with the necessary business logic
throw new java.lang.UnsupportedOperationException();
}
public axis2.apache.org.xsd.GetExistingAdsResponseDocument
getExistingAds
(axis2.apache.org.xsd.GetExistingAdsRequestDocument param5)
throws Exception {
//Todo fill this with the necessary business logic
throw new java.lang.UnsupportedOperationException();
}
}
|
在实际实现方法前,每个方法都会引发 UnsupportedOperationException
。为了将数据提交到服务,请首先处理参数和获得请求本身。这样,就可以使用 getter 方法来提取各个成员了。
显然,在实际的服务中,您希望进行的不仅是输出文本,而 Francis 仅是为了确保此服务能够正常工作。要创建响应,请从恰当的响应文档着手,通过类的 Factory
获得一个实例。(类本身非常复杂,包含大量内部类,但有必要了解一下它的结构。)获得了此文档后,请创建实际响应本身,并将其添加到此文档中。
可以通过使用 setter 方法在响应上设置值。直接返回响应文档,支持类负责将其发送回请求方。
部署服务
为了部署服务,您需要对其进行编译,并将其转换为 Axis2 存档文件。首先编译和打包服务,如清单 43 中所示。
清单 43. 打包服务
set ANT_HOME=e:\apache-ant-1.6.5
PATH=%PATH%;%ANT_HOME%\bin;
set AXIS2_HOME=e:\axis2
cd service
ant jar.service
|
对于非 Windows 安装,请对所用语法进行恰当调整,并确保使用的是实际文件位置。
此 Ant 任务将编译所有相应的文件,并创建两个存档文件 ClassifiedService.aar 和 XBeans-packaged.jar,这两个文件都位于 build/lib 目录中。
要部署服务,请确保 Geronimo 正在运行,并将浏览器指向清单 44 中所示的位置:
清单 44. 部署服务
http://localhost:8080/axis2/Login.jsp
|
使用凭据 admin/axis2 登录,并单击 Upload Service>Browse。导航到 ClassifiedService.aar 文件,然后单击 OK。单击 Upload,以完成此过程。
如果单击 View Services,应该看到列出了新服务。
从 WSDL 生成客户机存根
现在剩下任务就是生成用于访问新服务的客户机。为此,请从命令行执行以下命令:
清单 45. 用于生成客户机的命令
java org.apache.axis2.wsdl.WSDL2Java -uri ClassifiedService.wsdl -p
org.dailymoon.classifieds -d xmlbeans -o client
|
同样,这也是单个命令,需要在单行中输入。相应的参数和服务器端代码生成几乎完全相同,不过不需要服务描述符。另外,为了保持条理性,Francis 将新文件放入了独立的 client 目录中。
这个类应该以静默方式执行,在调用时会生成数百个文件,但您并不需要直接处理其中的任何文件。
创建客户机
代码生成过程并不会实际创建客户机,但会创建一个类,可以利用此类方便地创建客户机。为了简化编译,Francis 在 client\src\org\dailymoon\classifieds 目录中创建了一个名为 Client.java 的新类文件。这样, Ant 就会选取 .java 文件,并将其与其他源文件一起编译。
Francis 添加了清单 46 中的代码。
清单 46. 客户机
package org.dailymoon.classifieds;
import axis2.apache.org.xsd.*;
public class Client{
public static void main(java.lang.String args[]){
try{
ClassifiedServicePortTypeStub stub =
new ClassifiedServicePortTypeStub(null,
"http://localhost:8080/axis2/services/ClassifiedService");
CreateNewAdRequestDocument cnaDoc =
CreateNewAdRequestDocument.Factory.newInstance();
CreateNewAdRequestDocument.CreateNewAdRequest cnaReq =
cnaDoc.addNewCreateNewAdRequest();
cnaReq.setContent("Vintage 1963 T-Bird...");
cnaReq.setEndDate("7/4/06");
CreateNewAdResponseDocument cnaResDoc =
stub.createNewAd(cnaDoc);
System.out.println("New ad ID number: "+
cnaResDoc.getCreateNewAdResponse().getNewAdId());
} catch(Exception e){
e.printStackTrace();
}
}
}
|
ClassifiedServicePortTypeStub
类表示实际的服务,您将使用 AXIS_HOME(此处进行了省略,以使用缺省设置)和实际服务的位置对其进行实例化。接下来,通过引用其 Factory
创建请求文档,并使用其创建新的 CreateNewAdRequest
,而且在此过程中将其添加到请求文档中。和在服务本身中一样,可以随后直接使用 setter 方法设置各个属性。
为了获得响应,请使用存根执行 createNewAd()
方法,将其作为参数传递给请求文档。获得了响应文档或 CreateNewAtResponseDocument
后,可以使用其提取响应本身以及该响应的属性。
现在让我们运行此应用程序。
运行客户机
为了运行客户机,Francis 首先需要对其进行编译。执行以下步骤(请参见清单 47)。
清单 47. 编译客户机
>>set ANT_HOME=e:\apache-ant-1.6.5
>>PATH=%PATH%;%ANT_HOME%\bin;
>>set AXIS2_HOME=e:\axis2
>>cd client
>>ant jar.client
Buildfile: build.xml
init:
pre.compile.test:
[echo] Stax Availability= true
[echo] Axis2 Availability= true
compile.src:
compile.test:
jar.client:
BUILD SUCCESSFUL
Total time: 2 seconds
|
首先,确保环境中包含相应的环境变量。(这假定您已经安装了所有的 AXIS2_HOME\lib jar 文件。)接下来,转到 client 目录(或作为生成过程输出的任何目录)并针对 jar.client 目标运行 Ant。应该看到与斜体所示类似的结果(请参见清单 47)。要运行客户机,首先将 CLASSPATH 修改为包括 resources 目录以及包含数据绑定过程创建的所有类的目录(请参见清单 48)。
清单 48. 运行客户机
>>set CLASSPATH=E:\WSDLFiles\client\resources\;E:\WSDLFiles\client\bui
ld\classes\axis2\apache\org\xsd\;%CLASSPATH%
>>cd build\classes
>>java org.dailymoon.classifieds.Client
|
应该看到与清单 49 所示类似的结果:
清单 49. New ad ID number
本教程的内容到此结束了。
posted on 2006-12-29 19:11
SIMONE 阅读(1349)
评论(0) 编辑 收藏 所属分类:
AXIS 、
JAVA