posts - 495,comments - 227,trackbacks - 0

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 希望公开的四个方法(createNewAdeditExistingAdgetExistingAdsfinalizeIssue)的基本限制。

(请确保在生成 WSDL 前将 main 方法注释掉。此方法不会有负作用,但会生成不必要的额外代码。)

此类还引用其他两个类 ClassifiedAdClassifiedList。为了生成过程能够了解如何将这些对象构建为 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 服务描述符,从而更便于在生成服务代码后进行部署。下一个参数当然是包,其后紧跟数据绑定方法。可用的方法有 adbxmlbeansjaxme。最后,为了保持条理清楚,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
                    
New ad ID number: 1138

本教程的内容到此结束了。





回页首

posted on 2006-12-29 19:11 SIMONE 阅读(1338) 评论(0)  编辑  收藏 所属分类: AXISJAVA

只有注册用户登录后才能发表评论。


网站导航: