jax-ws 生成soap_使用JAX-RPC发送和接收SOAP消息

jax-ws 生成soap

Web服务的基础之一是互操作性。 这意味着Web服务以标准格式发送和接收消息。 通常,该格式是SOAP。 有很多发送SOAP消息的方法。

最基本的是对URL流执行println ,但这要求您对SOAP协议以及服务期望并发送的SOAP消息了解得太多。 没有简单的方法可以从服务中获取此信息,并且这种方法的可伸缩性不是很高。

加强使用SAAJ API(带有Java附件的SOAP)。 SAAJ API为您提供了一种在更抽象的级别上操作SOAP构造的方法,但是它们仍然与URL流共享许多println问题。

一种更友好的方法是使用一种将应用程序拉到SOAP消息传递协议之上的抽象级别的系统。 这种系统的好处包括:

  • 应用程序程序员可以专注于他们的应用程序逻辑,而不是SOAP的严格性
  • 可以使用除SOAP之外的其他消息传递方案,并且即使有的话,应用程序代码的更改也很少。

基于XML的RPC的Java API(JAX-RPC)提供了这种抽象方法。

JAX-RPC和Barnes&Noble Web服务

JAX-RPC不再依赖SOAP,而是依赖于Web服务描述语言(WSDL)。 WSDL以声明性,标准化的方式为Web服务定义API。 WSDL可以为服务定义SOAP绑定,但是它也可以在SOAP消息传递层之上的级别上定义服务的更抽象描述。 (请参阅相关主题有关WSDL的更多细节。)

上面提到的SAAJ文章中的示例使用了Barnes&Noble Web服务。 XMethods站点还提供了此Web服务的WSDL(请参阅参考资料 )。 在这些示例中使用了WSDL -请参见清单1。

清单1. XMethods的Barnes&Noble WSDL
<?xml version="1.0" ?>
<definitions name="BNQuoteService"
    targetNamespace="http://www.xmethods.net/sd/BNQuoteService.wsdl"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:tns="http://www.xmethods.net/sd/BNQuoteService.wsdl">
  <message name="getPriceRequest">
    <part name="isbn" type="xsd:string" /> 
  </message>
  <message name="getPriceResponse">
    <part name="return" type="xsd:float" /> 
  </message>
  <portType name="BNQuotePortType">
    <operation name="getPrice">
      <input message="tns:getPriceRequest" name="getPrice" /> 
      <output message="tns:getPriceResponse" name="getPriceResponse" /> 
    </operation>
  </portType>
  <binding name="BNQuoteBinding" type="tns:BNQuotePortType">
    <soap:binding style="rpc"
        transport="http://schemas.xmlsoap.org/soap/http" />
    <operation name="getPrice">
      <soap:operation soapAction="" />
      <input name="getPrice">
        <soap:body
            use="encoded"
            namespace="urn:xmethods-BNPriceCheck"
            encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
      </input>
      <output name="getPriceResponse">
        <soap:body
            use="encoded"
            namespace="urn:xmethods-BNPriceCheck"
            encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
      </output>
    </operation>
  </binding>
  <service name="BNQuoteService">
    <documentation>Returns price of a book at BN.com given an
        ISBN number</documentation>
    <port name="BNQuotePort" binding="tns:BNQuoteBinding">
      <soap:address location=
          "http://services.xmethods.net:80/soap/servlet/rpcrouter" />
    </port>
  </service>
</definitions>

在任何JAX-RPC应用程序中,您必须做三件事:

  1. 实例化Service类,它是Web服务的客户端表示形式
  2. 实例化Web服务应用程序的代理(并可能设置该代理)
  3. 调用Web服务的应用程序的操作

JAX-RPC DII客户端应用程序

SAAJ API不依赖于WSDL,仅依赖于SOAP,但是您必须确切地知道该服务的SOAP消息是什么样的。 JAX-RPC定义了一个动态调用接口(DII)API来访问Web服务,严格来说,该服务也不依赖WSDL(尽管您必须了解WSDL中捕获的某些信息)。 但是,您不再需要了解SOAP消息的详细信息。 DII JAX-RPC应用程序特定的三个步骤是:

  1. 实例化没有WSDL的DII Service
  2. 实例化DII Call对象代理并进行设置
  3. 调用Call对象的invoke方法

实例化没有WSDL的DII Service

此类不知道WSDL,但必须有一个名称。 使用WSDL中的服务名称。

清单2.实例化一个DII服务类
import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
public class DIITip {
    public static void main(String args[]) {
        try {
            // Create a service class with no WSDL information.  You
            // still must know something about the WSDL, however: the
            // service's name.
            QName serviceName = new QName(
                    "http://www.xmethods.net/sd/BNQuoteService.wsdl",
                    "BNQuoteService");
            ServiceFactory factory = ServiceFactory.newInstance();
            Service service = factory.createService(serviceName);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

实例化DII Call对象代理并进行设置

DII代理对象实现javax.xml.rpc.Call接口。 您可以从刚刚创建的服务中获得Call接口的实现。

清单3.实例化一个Call对象
import javax.xml.namespace.QName;
import javax.xml.rpc.Call;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
public class DIITip {
    public static void main(String args[]) {
        try {
            // Create a service class with no WSDL information.  You
            // still must know something about the WSDL, however: the
            // service's name.
            QName serviceName = new QName(
                    "http://www.xmethods.net/sd/BNQuoteService.wsdl",
                    "BNQuoteService");
            ServiceFactory factory = ServiceFactory.newInstance();
            Service service = factory.createService(serviceName);
           // Now create a dynamic Call object from this service.
           // This call object is not yet associated with any
           // operation.  We'll do that below.
           Call call = service.createCall();
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

您现在拥有的Call对象尚未可用。 它对操作一无所知。 向对象提供以下数据:

  • 操作名称: getPrice
  • 输入参数:字符串
  • 返回类型:浮点数
  • 绑定信息:rpc样式; 编码风格
  • 端点: http://services.xmethods.net:80/soap/servlet/rpcrouter ://services.xmethods.net: http://services.xmethods.net:80/soap/servlet/rpcrouter soap / servlet / http://services.xmethods.net:80/soap/servlet/rpcrouter
清单4.填充Call对象
import javax.xml.namespace.QName;
import javax.xml.rpc.Call;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.encoding.XMLType;
public class DIITip {
    public static void main(String args[]) {
        try {
            // Create a service class with no WSDL information.  You
            // still must know something about the WSDL, however: the
            // service's name.
            QName serviceName = new QName(
                    "http://www.xmethods.net/sd/BNQuoteService.wsdl",
                    "BNQuoteService");
            ServiceFactory factory = ServiceFactory.newInstance();
            Service service = factory.createService(serviceName);
            // Now create a dynamic Call object from this service.
            // This call object is not yet associated with any
            // operation.  We'll do that below.
            Call call = service.createCall();
          // Next, build up the information about the operation...
          // The operation name
          QName operationName = new QName(
                  "urn:xmethods-BNPriceCheck",
                  "getPrice");
                  call.setOperationName(operationName);
                  // The input parameter
                  call.addParameter(
                       "isbn",             // parameter name
                       XMLType.XSD_STRING, // parameter XML type QName
                       String.class,       // parameter Java type class
                       ParameterMode.IN);  // parameter mode
                       // The return
                       call.setReturnType(XMLType.XSD_FLOAT);
                       // The operation is an RPC-style operation.
                       call.setProperty(
            Call.OPERATION_STYLE_PROPERTY,
                       "rpc");
               // The encoding style property value comes from the
               // binding's operation's input clauses encodingStyle
               // attribute.  Note that, in this case, this call is not
               // really necessary - the value we're setting this
               // property to is the default.
               call.setProperty(
               Call.ENCODINGSTYLE_URI_PROPERTY,
                       "http://schemas.xmlsoap.org/soap/encoding/");
               // The target endpoint
               call.setTargetEndpointAddress(
               "http://services.xmethods.net:80/soap/servlet/rpcrouter");
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

调用Call对象的invoke方法

最后,您现在可以调用getPrice操作了。

清单5.调用getPrice操作
import javax.xml.namespace.QName;
import javax.xml.rpc.Call;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.encoding.XMLType;
public class DIITip {
    public static void main(String args[]) {
        try {
            // Create a service class with no WSDL information.  You
            // still must know something about the WSDL, however: the
            // service's name.
            QName serviceName = new QName(
                    "http://www.xmethods.net/sd/BNQuoteService.wsdl",
                    "BNQuoteService");
            ServiceFactory factory = ServiceFactory.newInstance();
            Service service = factory.createService(serviceName);
            // Now create a dynamic Call object from this service.
            // This call object is not yet associated with any
            // operation.  We'll do that below.
            Call call = service.createCall();
            // Next, build up the information about the operation...
            // The operation name
            QName operationName = new QName(
                    "urn:xmethods-BNPriceCheck",
                    "getPrice");
            call.setOperationName(operationName);
            // The input parameter
            call.addParameter(
                    "isbn",             // parameter name
                    XMLType.XSD_STRING, // parameter XML type QName
                    String.class,       // parameter Java type class
                    ParameterMode.IN);  // parameter mode
            // The return
            call.setReturnType(XMLType.XSD_FLOAT);
            // The operation is an RPC-style operation.
            call.setProperty(
                    Call.OPERATION_STYLE_PROPERTY,
                    "rpc");
            // The encoding style property value comes from the
            // binding's operation's input clauses encodingStyle
            // attribute.  Note that, in this case, this call is not
            // really necessary - the value we're setting this
            // property to is the default.
            call.setProperty(
                    Call.ENCODINGSTYLE_URI_PROPERTY,
                    "http://schemas.xmlsoap.org/soap/encoding/");
            // The target endpoint
            call.setTargetEndpointAddress(
            "http://services.xmethods.net:80/soap/servlet/rpcrouter");
           // Invoke the operation
              Object[] actualArgs = {"0672324229"};
              Float price = (Float) call.invoke(actualArgs);
              System.out.println("price = " + price);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

当您运行java DIITip ,您会得到价格: 44.99

如果将此与SAAJ文章中的代码进行比较,您会发现您与SOAP协议的知识相距很远。 您需要的唯一与SOAP相关的信息是操作样式和编码样式。

顾名思义,DII编程模型旨在与动态服务一起使用。 如果服务稍有变化,则不需要花费很多时间来更改客户端代码以使其匹配,并且如果您确实很聪明,则客户端代码可以是动态的,因此根本不需要更改。

该模型仍然相当复杂,尤其是在必须填充Call对象的地方。 操作越复杂,需要提供给Call对象的信息就越复杂。 因此,如果您知道服务是静态的并且不会改变,那么您可以在抽象食物链上再上一层。

JAX-RPC SEI客户端应用程序

下一个抽象级别需要更多的设置,但是生成的客户端代码要简单得多。 您从WSDL开始。 JAX-RPC实现提供了一个WSDL-to-Java代码生成器,该生成器除其他功能外还生成服务端点接口(SEI)。 这是Web服务应用程序的客户端Java接口。 清单6显示了XMethods Barnes&Noble应用程序的SEI。

清单6. Barnes&Noble SEI
package xmethods.bn;
public interface BNQuotePortType extends java.rmi.Remote {
    public float getPrice(java.lang.String isbn)
            throws java.rmi.RemoteException;
}

在我使用的WSDL-to-Java工具中,我将targetNamespace映射到Java包xmethods.bn ,这就是生成SEI的包。 SEI的名称是从WSDL的portType名称派生的: BNQuotePortTypegetPrice方法是从portTypegetPrice操作及其引用的消息和类型派生的。 如果运行您喜欢的WSDL-to-Java工具,您将看到xmethods.bn包中生成了其他类。 您必须全部编译它们,但是您的客户端应用程序只需要了解SEI。

要使用此SEI调用Web服务,请执行与DII基本上相同的三个步骤:

  1. 使用WSDL实例化Service
  2. 实例化代理
  3. 调用代理的操作

SEI和DII的步骤1相似。 步骤2和3得以简化,尤其是步骤2。

使用WSDL实例化Service

SEI模型和DII模型中此步骤之间的唯一区别是,在这里您提供了额外的信息:WSDL。

清单7.实例化SEI的Service类
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
public class SEITip {
    public static void main(String args[]) {
        try {
            // Create a service class with WSDL information.
            QName serviceName = new QName(
                    "http://www.xmethods.net/sd/BNQuoteService.wsdl",
                    "BNQuoteService");
            URL wsdlLocation = new URL
              ("http://www.xmethods.net/sd/2001/BNQuoteService.wsdl");
            ServiceFactory factory = ServiceFactory.newInstance();
            Service service = factory.createService(
                    wsdlLocation,
                    serviceName);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

实例化代理

获得服务后,您必须找到SEI的实现。 此实现是真实应用程序的代理。 有关如何访问该应用程序的所有信息都隐藏在实现中-它是从WSDL的服务端口收集的-因此,一旦获得了代理,就无需进行任何设置。 已经为您完成了。

清单8.实例化SEI的实现
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
import xmethods.bn.BNQuotePortType;
public class SEITip {
    public static void main(String args[]) {
        try {
            // Create a service class with WSDL information.
            QName serviceName = new QName(
                    "http://www.xmethods.net/sd/BNQuoteService.wsdl",
                    "BNQuoteService");
            URL wsdlLocation = new URL
              ("http://www.xmethods.net/sd/2001/BNQuoteService.wsdl");
            ServiceFactory factory = ServiceFactory.newInstance();
            Service service = factory.createService(
                    wsdlLocation,
                    serviceName);
           // Get an implementation for the SEI for the given port
           QName portName = new QName("", "BNQuotePort");
           BNQuotePortType quote = (BNQuotePortType) service.getPort(
                      portName,
                      BNQuotePortType.class);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

调用代理的操作

最后,调用操作再简单不过了:

清单9.在SEI上调用一个操作
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
import xmethods.bn.BNQuotePortType;
public class SEITip {
    public static void main(String args[]) {
        try {
            // Create a service class with WSDL information.
            QName serviceName = new QName(
                    "http://www.xmethods.net/sd/BNQuoteService.wsdl",
                    "BNQuoteService");
            URL wsdlLocation = new URL
              ("http://www.xmethods.net/sd/2001/BNQuoteService.wsdl");
            ServiceFactory factory = ServiceFactory.newInstance();
            Service service = factory.createService(
                    wsdlLocation,
                    serviceName);
            // Get an implementation for the SEI for the given port
            QName portName = new QName("", "BNQuotePort");
            BNQuotePortType quote = (BNQuotePortType) service.getPort(
                    portName,
                    BNQuotePortType.class);
           // Invoke the operation
              float price = quote.getPrice("0672324229");
              System.out.println("price = " + price);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

摘要

在调用Web服务的许多方法中,最基本的方法是手动生成和发送SOAP消息。 您必须对服务和SOAP协议了解太多,这不是很有用。 下一步是使用SAAJ API。 您仍然必须对服务和SOAP协议了解很多-仍然不是特别有用。 从那里开始的下一步是使用JAX-RPC DII。 这使您远离SOAP,但是代码仍然相当复杂。 通常,最好的方法是从服务的WSDL生成SEI并调用SEI代理。


翻译自: https://www.ibm.com/developerworks/xml/library/x-tipjaxrpc/index.html

jax-ws 生成soap

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值