Web Service概述

Web Service的定义
W3C组织对其的定义例如以下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计。Web Service服务通常被定义为一组模块化的API,它们可以通过网络进行调用,来运行远程系统的请求服务。

这里我们从一个程序猿的视角来观察web service。在传统的程序编码中,存在这各种的函数方法调用。通常,我们知道一个程序模块M中的方法A,向其发出调用请求,并传入A方法须要的參数P,方法A运行完毕后,返回处理结果R。这样的函数或方法调用通常发生在同一台机器上的同一程序语言环境下。如今的我们须要一种可以在不同计算机间的不同语言编写的应用程序系统中,通过网络通讯实现函数和方法调用的能力,而Web service正是应这样的需求而诞生的。

最普遍的一种说法就是,Web Service = SOAP + HTTP + WSDL。当中,SOAP Simple Object Access Protocol)协议是web service的主体,它通过HTTP或者SMTP等应用层协议进行通讯,自身使用XML文件来描写叙述程序的函数方法和參数信息,从而完毕不同主机的异构系统间的计算服务处理。这里的WSDL(Web Services Description Language)web 服务描写叙述语言也是一个XML文档,它通过HTTP向公众公布,公告client程序关于某个详细的 Web service服务的URL信息、方法的命名,參数,返回值等。
以下,我们先来熟悉一下SOAP协议,看看它是怎样描写叙述程序中的函数方法、參数及结果对象的。

SOAP协议简单介绍

什么是SOAP
SOAP 指简单对象訪问协议,它是一种基于XML的消息通讯格式,用于网络上,不同平台,不同语言的应用程序间的通讯。可自己定义,易于扩展。一条 SOAP 消息就是一个普通的 XML 文档,包括下列元素:
• Envelope 元素,标识XML 文档一条 SOAP 消息
• Header 元素,包括头部信息的XML标签
• Body 元素,包括全部的调用和响应的主体信息的标签
• Fault 元素,错误信息标签。

以上的元素都在 SOAP的命名空间http://www.w3.org/2001/12/soap-envelope中声明;
SOAP的语法规则
• SOAP 消息必须用 XML 来编码
• SOAP 消息必须使用 SOAP Envelope 命名空间
• SOAP 消息必须使用 SOAP Encoding 命名空间
• SOAP 消息不能包括 DTD 引用
• SOAP 消息不能包括 XML 处理指令

SOAP 消息的基本结构

Java代码
  1. <? xml version="1.0"?>
  2. <soap:Envelope
  3. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
  4. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
  5. <soap:Header>
  6. ...
  7. ...
  8. </soap:Header>
  9. <soap:Body>
  10. ...
  11. ...
  12. <soap:Fault>
  13. ...
  14. ...
  15. </soap:Fault>
  16. </soap:Body>
  17. </soap:Envelope>
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Header>......
</soap:Header>
<soap:Body>......<soap:Fault>......</soap:Fault>
</soap:Body>
</soap:Envelope>

SOAP Envelope 元素
Envelope 元素是 SOAP 消息的根元素。它指明 XML 文档是一个SOAP 消息。它的属性 xmlns:soap的值必须是http://www.w3.org/2001/12/soap-envelope。
 encodingStyle 属性,语法:soap:encodingStyle="URI"
encodingStyle 属性用于定义文档中使用的数据类型。此属性可出如今不论什么 SOAP 元素中,并会被应用到元素的内容及元素的全部子元素上。

Java代码
  1. <? xml version="1.0"?>
  2. <soap:Envelope
  3. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
  4. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
  5. ...
  6. Message information goes here
  7. ...
  8. </soap:Envelope>
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">...Message information goes here...
</soap:Envelope>

SOAP Header 元素

  • actor 属性,语法soap:actor="URI"

通过沿着消息路径经过不同的端点,SOAP 消息可从某个发送者传播到某个接收者。并不是 SOAP 消息的全部部分均打算传送到 SOAP 消息的终于端点,只是,还有一个方面,或许打算传送给消息路径上的一个或多个端点。SOAP 的 actor 属性可被用于将 Header 元素寻址到一个特定的端点。

  • mustUnderstand 属性 ,语法soap:mustUnderstand="0|1"

SOAP 的 mustUnderstand 属性可用于标识标题项对于要对其进行处理的接收者来说是强制的还是可选的。假如您向 Header 元素的某个子元素加入了 "mustUnderstand="1",则要求处理此头部的接收者必须认可此元素。

Java代码
  1. <? xml version="1.0"?>
  2. <soap:Envelope
  3. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
  4. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
  5. <soap:Header>
  6. <m:Trans
  7. xmlns:m="http://www.jsoso.net/transaction/"
  8. soap:mustUnderstand="1"
  9. soap:actor="http://www.w3schools.com/appml/ “  >234</m:Trans>
  10. </soap:Header>
  11. ...
  12. ...
  13. </soap:Envelope>
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Header>
<m:Trans
xmlns:m="http://www.jsoso.net/transaction/"
soap:mustUnderstand="1"
soap:actor="http://www.w3schools.com/appml/ “  >234</m:Trans>
</soap:Header>
...
...
</soap:Envelope>

SOAP Body 元素
必需的 SOAP Body 元素可包括打算传送到消息终于端点的实际 SOAP 消息。Body元素中既能够包括SOAP定义的命名空间中的元素,如Fault,也能够是用户的应用程序自己定义的元素。下面是一个用户定义的请求:

Java代码
  1. <? xml version="1.0"?>
  2. <soap:Envelope
  3. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
  4. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
  5. <soap:Body>
  6. <m:GetPrice xmlns:m="http://www.jsoso.net/prices">
  7. <m:Item>Apples</m:Item>
  8. </m:GetPrice>
  9. </soap:Body>
  10. </soap:Envelope>
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body><m:GetPrice xmlns:m="http://www.jsoso.net/prices"><m:Item>Apples</m:Item></m:GetPrice>
</soap:Body>
</soap:Envelope>

上面的样例请求苹果的价格。请注意,上面的 m:GetPrice 和 Item 元素是应用程序专用的元素。它们并非 SOAP 标准的一部分。而相应的 SOAP 响应应该相似这样:

Java代码
  1. <?xml version="1.0"?>
  2. <soap:Envelope
  3. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
  4. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
  5. <soap:Body>
  6. <m:GetPriceResponse xmlns:m="http://www.jsoso.net/prices">
  7. <m:Price>1.90</m:Price>
  8. </m:GetPriceResponse>
  9. </soap:Body>
  10. </soap:Envelope>
<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body><m:GetPriceResponse xmlns:m="http://www.jsoso.net/prices"><m:Price>1.90</m:Price></m:GetPriceResponse>
</soap:Body>
</soap:Envelope>

SOAP Fault 元素
Fault 元素表示 SOAP的错误消息。它必须是 Body 元素的子元素,且在一条 SOAP 消息中,Fault 元素仅仅能出现一次。Fault 元素拥有下列子元素:

经常使用的SOAP Fault Codes

HTTP协议中的SOAP 实例
以下的样例中,一个 GetStockPrice 请求被发送到了server。此请求有一个 StockName 參数,而在响应中则会返回一个 Price 參数。此功能的命名空间被定义在此地址中: "http://www.jsoso.net/stock"

  • SOAP 请求:(注意HTTP的Head属性)
Java代码
  1. POST /InStock HTTP/1.1
  2. Host: www.jsoso.net
  3. Content-Type: application/soap+xml; charset=utf-8
  4. Content-Length: XXX
  5. <? xml version="1.0"?>
  6. <soap:Envelope
  7. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
  8. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
  9. <soap:Body xmlns:m="http://www.jsoso.net/stock">
  10. <m:GetStockPrice>
  11. <m:StockName>IBM</m:StockName>
  12. </m:GetStockPrice>
  13. </soap:Body>
  14. </soap:Envelope>
POST /InStock HTTP/1.1
Host: www.jsoso.net
Content-Type: application/soap+xml; charset=utf-8
Content-Length: XXX<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding"><soap:Body xmlns:m="http://www.jsoso.net/stock"><m:GetStockPrice><m:StockName>IBM</m:StockName></m:GetStockPrice></soap:Body>
</soap:Envelope>
  • SOAP 响应:(注意HTTP的Head属性)
Java代码
  1. HTTP/1.1 200 OK
  2. Content-Type: application/soap+xml; charset=utf-8
  3. Content-Length: XXX
  4. <? xml version="1.0"?>
  5. <soap:Envelope
  6. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
  7. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
  8. <soap:Body xmlns:m="http://www.jsoso.net/stock">
  9. <m:GetStockPriceResponse>
  10. <m:Price>34.5</m:Price>
  11. </m:GetStockPriceResponse>
  12. </soap:Body>
  13. </soap:Envelope>
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: XXX<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding"><soap:Body xmlns:m="http://www.jsoso.net/stock"><m:GetStockPriceResponse><m:Price>34.5</m:Price></m:GetStockPriceResponse></soap:Body>
</soap:Envelope>

HTTP协议中的SOAP RPC工作流程

WSDL简单介绍
介绍过了SOAP,让我们关注Web Service中另外一个重要的组成WSDL。
WSDL的主要文档元素

WSDL文档能够分为两部分。顶部分由抽象定义组成,而底部分则由详细描写叙述组成。抽象部分以独立于平台和语言的方式定义SOAP消息,它们并不包括不论什么随机器或语言而变的元素。这就定义了一系列服务,截然不同的应用都能够实现。详细部分,如数据的序列化则归入底部分,由于它包括详细的定义。在上述的文档元素中,<types>、<message>、<portType>属于抽象定义层,<binding>、<service>属于详细定义层。全部的抽象能够是单独存在于别的文件里,也能够从主文档中导入。

WSDL文档的结构实例解析
以下我们将通过一个实际的WSDL文档样例来详细说明各标签的作用及关系。

Java代码
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <definitions
  3. xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  4. xmlns:tns="http://www.jsoso.com/wstest"
  5. xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  6. xmlns="http://schemas.xmlsoap.org/wsdl/"
  7. targetNamespace="http://www.jsoso.com/wstest"
  8. name="Example">
  9. <types>
  10. <xsd:schema>
  11. <xsd:import
  12. namespace="http://www.jsoso.com/wstest"
  13. schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>
  14. </xsd:schema>
  15. </types>
  16. <message name="toSayHello">
  17. <part name="userName" type="xsd:string"></part>
  18. </message>
  19. <message name="toSayHelloResponse">
  20. <part name="returnWord" type="xsd:string"></part>
  21. </message>
  22. <message name="sayHello">
  23. <part name="person" type="tns:person"></part>
  24. <part name="arg1" type="xsd:string"></part>
  25. </message>
  26. <message name="sayHelloResponse">
  27. <part name="personList" type="tns:personArray"></part>
  28. </message>
  29. <message name="HelloException">
  30. <part name="fault" element="tns:HelloException"></part>
  31. </message>
  32. <portType name="Example">
  33. <operation name="toSayHello" parameterOrder="userName">
  34. <input message="tns:toSayHello"></input>
  35. <output message="tns:toSayHelloResponse"></output>
  36. </operation>
  37. <operation name="sayHello" parameterOrder="person arg1">
  38. <input message="tns:sayHello"></input>
  39. <output message="tns:sayHelloResponse"></output>
  40. <fault message="tns:HelloException" name="HelloException"></fault>
  41. </operation>
  42. </portType>
  43. <binding name="ExamplePortBinding" type="tns:Example">
  44. <soap:binding
  45. transport="http://schemas.xmlsoap.org/soap/http"
  46. style="rpc"></soap:binding>
  47. <operation name="toSayHello">
  48. <soap:operation soapAction="sayHello"></soap:operation>
  49. <input>
  50. <soap:body use="literal"
  51. namespace="http://www.jsoso.com/wstest"></soap:body>
  52. </input>
  53. <output>
  54. <soap:body use="literal"
  55. namespace="http://www.jsoso.com/wstest"></soap:body>
  56. </output>
  57. </operation>
  58. <operation name="sayHello">
  59. <soap:operation soapAction="sayHello"></soap:operation>
  60. <input>
  61. <soap:body use="literal"
  62. namespace="http://www.jsoso.com/wstest"></soap:body>
  63. </input>
  64. <output>
  65. <soap:body use="literal"
  66. namespace="http://www.jsoso.com/wstest"></soap:body>
  67. </output>
  68. <fault name="HelloException">
  69. <soap:fault name="HelloException" use="literal"></soap:fault>
  70. </fault>
  71. </operation>
  72. </binding>
  73. <service name="Example">
  74. <port name="ExamplePort" binding="tns:ExamplePortBinding">
  75. <soap:address location="http://localhost:8080/hello"></soap:address>
  76. </port>
  77. </service>
  78. </definitions>
<?xml version="1.0" encoding="UTF-8"?>
<definitionsxmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"xmlns:tns="http://www.jsoso.com/wstest"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns="http://schemas.xmlsoap.org/wsdl/"targetNamespace="http://www.jsoso.com/wstest"name="Example"><types><xsd:schema><xsd:importnamespace="http://www.jsoso.com/wstest"schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import></xsd:schema>
</types><message name="toSayHello"><part name="userName" type="xsd:string"></part>
</message>
<message name="toSayHelloResponse"><part name="returnWord" type="xsd:string"></part>
</message><message name="sayHello"><part name="person" type="tns:person"></part><part name="arg1" type="xsd:string"></part>
</message>
<message name="sayHelloResponse"><part name="personList" type="tns:personArray"></part>
</message>
<message name="HelloException"><part name="fault" element="tns:HelloException"></part>
</message><portType name="Example"><operation name="toSayHello" parameterOrder="userName"><input message="tns:toSayHello"></input><output message="tns:toSayHelloResponse"></output></operation><operation name="sayHello" parameterOrder="person arg1"><input message="tns:sayHello"></input><output message="tns:sayHelloResponse"></output><fault message="tns:HelloException" name="HelloException"></fault></operation>
</portType><binding name="ExamplePortBinding" type="tns:Example"><soap:bindingtransport="http://schemas.xmlsoap.org/soap/http" style="rpc"></soap:binding><operation name="toSayHello"><soap:operation soapAction="sayHello"></soap:operation><input><soap:body use="literal"namespace="http://www.jsoso.com/wstest"></soap:body></input><output><soap:body use="literal"namespace="http://www.jsoso.com/wstest"></soap:body></output></operation><operation name="sayHello"><soap:operation soapAction="sayHello"></soap:operation><input><soap:body use="literal"namespace="http://www.jsoso.com/wstest"></soap:body></input><output><soap:body use="literal"namespace="http://www.jsoso.com/wstest"></soap:body></output><fault name="HelloException"><soap:fault name="HelloException" use="literal"></soap:fault></fault></operation>
</binding><service name="Example"><port name="ExamplePort" binding="tns:ExamplePortBinding"><soap:address location="http://localhost:8080/hello"></soap:address></port>
</service>
</definitions>

因为上面的事例XML较长,我们将其逐段分解解说

WSDL文档的根元素:<definitions>

Java代码
  1. <definitions
  2. xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  3. xmlns:tns="http://www.jsoso.com/wstest"
  4. xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  5. xmlns="http://schemas.xmlsoap.org/wsdl/"
  6. targetNamespace="http://www.jsoso.com/wstest"
  7. name="Example">
  8. ……
  9. ……
  10. </definitions>
<definitionsxmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"xmlns:tns="http://www.jsoso.com/wstest"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns="http://schemas.xmlsoap.org/wsdl/"targetNamespace="http://www.jsoso.com/wstest"name="Example">
……
……
</definitions>

<definitions>定义了文档中用到的各个xml元素的namespace缩写,也界定了本文档自己的targetNamespace="http://www.jsoso.com/wstest",这意味着其他的XML要引用当前XML中的元素时,要声明这个namespace。注意xmlns:tns="http://www.jsoso.com/wstest"这个声明,它标示了使用tns这个前缀指向自身的命名空间。

引用
WSDL文档数据类型定义元素:<types>
Java代码
  1. <types>
  2. <xsd:schema>
  3. <xsd:import
  4. namespace="http://www.jsoso.com/wstest"
  5. schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>
  6. </xsd:schema>
  7. </types>
<types><xsd:schema><xsd:importnamespace="http://www.jsoso.com/wstest"schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import></xsd:schema>
</types>

<types>标签定义了当前的WSDL文档用到的数据类型。要说明的是,为了最大程度的平台中立性,WSDL 使用 XML Schema 语法来定义数据类型。这些数据类型用来定义web service方法的參数和返回指。对于通用的原生数据类型如:integer , boolean , char , float等,在W3C的标准文档http://www.w3.org/2001/XMLSchema中已经做了定义。这里我们要引入的schema定义schemaLocation="http://localhost:8080/hello?xsd=1"是我们自己定义的Java对象类型。

WSDL文档消息体定义元素:< message >

Java代码
  1. <message name="toSayHello">
  2. <part name="userName" type="xsd:string"></part>
  3. </message>
  4. <message name="toSayHelloResponse">
  5. <part name="returnWord" type="xsd:string"></part>
  6. </message>
  7. <message name="sayHello">
  8. <part name="person" type="tns:person"></part>
  9. <part name="arg1" type="xsd:string"></part>
  10. </message>
  11. <message name="sayHelloResponse">
  12. <part name="personList" type="tns:personArray"></part>
  13. </message>
  14. <message name="HelloException">
  15. <part name="fault" element="tns:HelloException"></part>
  16. </message>
<message name="toSayHello"><part name="userName" type="xsd:string"></part>
</message>
<message name="toSayHelloResponse"><part name="returnWord" type="xsd:string"></part>
</message><message name="sayHello"><part name="person" type="tns:person"></part><part name="arg1" type="xsd:string"></part>
</message>
<message name="sayHelloResponse"><part name="personList" type="tns:personArray"></part>
</message>
<message name="HelloException"><part name="fault" element="tns:HelloException"></part>
</message>

<message>元素定义了web service函数的參数。<message>元素中的每一个<part>子元素都和某个參数相符。输入參数在<message>元素中定义,与输出參数相隔离,输出參数有自己的<message>元素。兼作输入、输出的參数在输入输出的<message>元素中有它们相应的<part>元素。输出<message>元素以"Response"结尾,对Java而言方法得返回值就相应一个输出的<message>。每一个<part>元素都有名字和类型属性,就像函数的參数有參数名和參数类型。

在上面的文档中有两个输入參数、两个输出參数和一个错误參数(相应Java中的Exception)。

 输入參数<message>的name属性分别命名为toSayHello,sayHello。
toSayHello相应输入參数userName,參数类型为xsd:string,在Java语言中就是String;
sayHello相应两个输入參数person和arg1,类型为tns:person和xsd:string。这里tns:person类型就是引用了< types >标签中的类型定义。

 输出參数<message>的name属性分别命名为toSayHelloResponse和sayHelloResponse。
这个名称和输入參数的<message>标签name属性相应,在其后面加上Response尾缀。
toSayHelloResponse相应的返回值是returnWord,參数类型为xsd:string;
sayHelloResponse相应的返回值是personList,參数类型为tns:personArray(自己定义类型);

 错误參数<message>的name属性为HelloException。
它的<part>子标签element而不是type来定义类型。

以上的message标签的name属性通常使用web service函数方法名作为參照,错误參数标签则使用异常类名为參照。标签中的參数名称,即part子元素的name属性是可自己定义的(下一章节具体说明)。message标签的參数类型将引用types标签的定义。

WSDL文档函数体定义元素:< portType >

Java代码
  1. <portType name="Example">
  2. <operation name="toSayHello" parameterOrder="userName">
  3. <input message="tns:toSayHello"></input>
  4. <output message="tns:toSayHelloResponse"></output>
  5. </operation>
  6. <operation name="sayHello" parameterOrder="person arg1">
  7. <input message="tns:sayHello"></input>
  8. <output message="tns:sayHelloResponse"></output>
  9. <fault message="tns:HelloException" name="HelloException"></fault>
  10. </operation>
  11. </portType>
<portType name="Example"><operation name="toSayHello" parameterOrder="userName"><input message="tns:toSayHello"></input><output message="tns:toSayHelloResponse"></output></operation><operation name="sayHello" parameterOrder="person arg1"><input message="tns:sayHello"></input><output message="tns:sayHelloResponse"></output><fault message="tns:HelloException" name="HelloException"></fault></operation>
</portType>

<portType> 元素是最重要的 WSDL 元素。它可描写叙述一个 web service、可被运行的操作,以及相关的消息。portType的name属性相应Java中的一个服务类的类名。<portType> 元素使用其子元素< operation>描写叙述一个web service的服务方法。

在<operation>元素中,name属性表示服务方法名,parameterOrder属性表示方法的參数顺序,使用空格符切割多个參数,如:“parameterOrder="person arg1”。<operation>元素的子标签<input>表示输入參数说明,它引用<message>标签中的输入參数。<output>表示输出參数说明,它引用<message>标签中的输出參数。<fault>标签在Java方法中的特别用来表示异常(其他语言有相应的错误处理机制),它引用<message>标签中的错误參数。

WSDL绑定实现定义元素:< binding >

Java代码
  1. <binding name="ExamplePortBinding" type="tns:Example">
  2. <soap:binding
  3. transport="http://schemas.xmlsoap.org/soap/http"
  4. style="rpc"></soap:binding>
  5. <operation name="toSayHello">
  6. <soap:operation soapAction="sayHello"></soap:operation>
  7. <input>
  8. <soap:body use="literal"
  9. namespace="http://www.jsoso.com/wstest"></soap:body>
  10. </input>
  11. <output>
  12. <soap:body use="literal"
  13. namespace="http://www.jsoso.com/wstest"></soap:body>
  14. </output>
  15. </operation>
  16. <operation name="sayHello">
  17. <soap:operation soapAction="sayHello"></soap:operation>
  18. <input>
  19. <soap:body use="literal"
  20. namespace="http://www.jsoso.com/wstest"></soap:body>
  21. </input>
  22. <output>
  23. <soap:body use="literal"
  24. namespace="http://www.jsoso.com/wstest"></soap:body>
  25. </output>
  26. <fault name="HelloException">
  27. <soap:fault name="HelloException" use="literal"></soap:fault>
  28. </fault>
  29. </operation>
  30. </binding>
<binding name="ExamplePortBinding" type="tns:Example"><soap:bindingtransport="http://schemas.xmlsoap.org/soap/http" style="rpc"></soap:binding><operation name="toSayHello"><soap:operation soapAction="sayHello"></soap:operation><input><soap:body use="literal"namespace="http://www.jsoso.com/wstest"></soap:body></input><output><soap:body use="literal"namespace="http://www.jsoso.com/wstest"></soap:body></output></operation><operation name="sayHello"><soap:operation soapAction="sayHello"></soap:operation><input><soap:body use="literal"namespace="http://www.jsoso.com/wstest"></soap:body></input><output><soap:body use="literal"namespace="http://www.jsoso.com/wstest"></soap:body></output><fault name="HelloException"><soap:fault name="HelloException" use="literal"></soap:fault></fault></operation>
</binding>

<binding>标签是完整描写叙述协议、序列化和编码的地方,<types>,<message>和<portType>标签处理抽象的数据内容,而<binding>标签是处理传输数据的物理实现。
<binding>标签把前三部分的抽象定义详细化。

首先<binding>标签使用<soap:binding>的transport和style属性定义了Web Service的通讯协议HTTP和SOAP的请求风格RPC。其次<operation>子标签将portType中定义的operation同SOAP的请求绑定,定义了操作名称soapAction,输出输入參数和异常的编码方式及命名空间。

WSDL服务地址绑定元素:< service >

Java代码
  1. <service name="Example">
  2. <port name="ExamplePort" binding="tns:ExamplePortBinding">
  3. <soap:address location="http://localhost:8080/hello"></soap:address>
  4. </port>
  5. </service>
<service name="Example"><port name="ExamplePort" binding="tns:ExamplePortBinding"><soap:address location="http://localhost:8080/hello"></soap:address></port>
</service>

service是一套<port>元素。在一一相应形式下,每一个<port>元素都和一个location关联。假设同一个<binding>有多个<port>元素与之关联,能够使用额外的URL地址作为替换。

一个WSDL文档中能够有多个<service>元素,并且多个<service>元素十分实用,当中之中的一个就是能够依据目标URL来组织端口。在一个WSDL文档中,<service>的name属性用来区分不同的service。在同一个service中,不同端口,使用端口的"name"属性区分。

这一章节,我们简单的描写叙述了WSDL对SOAP协议的支持,以及在Web Service中的作用。在接下来的章节中,我们将学习怎样使用Java6.0的Annotation标签来定义和生成相应的WSDL。

JavaSE6.0下的Web Service
从JavaSE6.0開始,Java引入了对Web Service的原生支持。我们仅仅须要简单的使用Java的Annotation标签就可以将标准的Java方法公布成Web Service。(PS:Java Annotation资料请參考JDK5.0 Annotation学习笔记(一) )

但不是全部的Java类都能够公布成Web Service。Java类若要成为一个实现了Web Service的bean,它须要遵循下边这些原则:

  •  这个类必须是public类
  •  这些类不能是final的或者abstract
  •  这个类必须有一个公共的默认构造函数
  •  这个类绝对不能有finalize()方法

以下我们将通过一个详细的Java Web Service代码样例,配合上述的WSDL文件,讲述怎样编写JavaSE6.0的原生Web Service应用。

完整的Java Web Service类代码

Java代码
  1. package org.jsoso.jws.server;
  2. import java.util.ArrayList;
  3. import javax.jws.WebMethod;
  4. import javax.jws.WebParam;
  5. import javax.jws.WebResult;
  6. import javax.jws.WebService;
  7. import javax.jws.WebParam.Mode;
  8. import javax.jws.soap.SOAPBinding;
  9. /
  10. * 提供WebService服务的类
  11. */
  12. @WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example")
  13. @SOAPBinding(style=SOAPBinding.Style.RPC)
  14. public class Example {
  15. private ArrayList<Person> persons = new ArrayList<Person>();;
  16. /**
  17. *
  18. * 返回一个字符串
  19. * @param userName
  20. * @return
  21. */
  22. @WebMethod(operationName="toSayHello",action="sayHello",exclude=false)
  23. @WebResult(name="returnWord")//自己定义该方法返回值在WSDL中相关的描写叙述
  24. public String sayHello(@WebParam(name="userName")String userName) {
  25. return "Hello:" + userName;
  26. }
  27. /**
  28. * web services 方法的返回值与參数的类型不能为接口
  29. * @param person
  30. * @return
  31. * @throws HelloException
  32. */
  33. @WebMethod(operationName="sayHello", action="sayHello")
  34. @WebResult(partName="personList")
  35. public Person[] sayHello(@WebParam(partName="person", mode=Mode.IN)Person person,
  36. String userName) throws HelloException {
  37. if (person == null || person.getName() == null) {
  38. throw new HelloException("说hello出错,对像为空。。");
  39. }
  40. System.out.println(person.getName() + " 对 " + userName + " 说:Hello,我今年" + person.getAge() + "岁");
  41. persons.add(person);
  42. return persons.toArray(new Person[0]);
  43. }
  44. }
package org.jsoso.jws.server;import java.util.ArrayList;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.WebParam.Mode;
import javax.jws.soap.SOAPBinding;
/* 提供WebService服务的类*/
@WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example")
@SOAPBinding(style=SOAPBinding.Style.RPC)
public class Example {private ArrayList<Person> persons = new ArrayList<Person>();;/*** * 返回一个字符串* @param userName* @return*/@WebMethod(operationName="toSayHello",action="sayHello",exclude=false)@WebResult(name="returnWord")//自己定义该方法返回值在WSDL中相关的描写叙述public String sayHello(@WebParam(name="userName")String userName) {return "Hello:" + userName;}/*** web services 方法的返回值与參数的类型不能为接口* @param person* @return* @throws HelloException*/@WebMethod(operationName="sayHello", action="sayHello")@WebResult(partName="personList")public Person[] sayHello(@WebParam(partName="person", mode=Mode.IN)Person person, String userName) throws HelloException {if (person == null || person.getName() == null) {throw new HelloException("说hello出错,对像为空。。");}System.out.println(person.getName() + " 对 " + userName + " 说:Hello,我今年" + person.getAge() + "岁");persons.add(person);return persons.toArray(new Person[0]);}
}

Annotation 1@WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example")
@WebService标签主要将类暴露为WebService,当中targetNamespace属性定义了自己的命名空间,serviceName则定义了< definitions >标签和<service>标签的name属性。

Annotation 2:@SOAPBinding(style=SOAPBinding.Style.RPC)
@SOAPBinding标签定义了WSDL文档中SOAP的消息协议,当中style属性相应SOAP的文档类型,可选的有RPC和DOCUMENT

Annotation 3:@WebMethod(operationName="toSayHello",action="sayHello",exclude=false)
@WebMethod定义Web Service运作的方法,
属性action 相应操作的活动 ,如<soap:operation soapAction="sayHello" />
属性operationName匹配的wsdl:operation 的名称,如<operation name="toSayHello" parameterOrder="userName">
属性exclude 用于阻止将某一继承方法公开为web服务,默觉得false

Annotation 4:@WebResult(name="returnWord")
@ WebResult定义方法返回值得名称,如<part name="returnWord" type="xsd:string" />

Annotation 5:@WebParam(partName="person", mode=Mode.IN
@WebParam定义方法的參数名称,如<part name="person" type="tns:person" />,当中mode属性表示參数的流向,可选值有IN / OUT / INOUT

这里要着重说明的是,上述Web Service类的sayHello方法中,带有HelloException这个异常声明,造成该服务类不能直接公布成Web Service。须要使用wsgen工具为其生存异常Bean。关于wsgen工具的使用,请參考wsgen与wsimport命令说明

公布一个的Java Web Service
在完毕了上述的Web Service Annotation凝视后,我们使用wsgen工具为其进行服务资源文件的构造(这里主要是生成一个名为org.jsoso.jws.server.jaxws.HelloExceptionBean的异常bean类),最后使用下面的类公布Web 服务:

Java代码
  1. package org.jsoso.jws.server;
  2. import java.util.LinkedList;
  3. import java.util.List;
  4. import javax.xml.ws.Binding;
  5. import javax.xml.ws.Endpoint;
  6. import javax.xml.ws.handler.Handler;
  7. /**
  8. * @author zsy 启动web services服务
  9. */
  10. public class StartServer {
  11. /**
  12. * @param args
  13. */
  14. public static void main(String[] args) {
  15. /*
  16. * 生成Example 服务实例
  17. */
  18. Example serverBean = new Example();
  19. /*
  20. * 公布Web Service到http://localhost:8080/hello地址
  21. */
  22. Endpoint endpoint =
  23. Endpoint.publish("http://localhost:8080/hello", serverBean);
  24. Binding binding = endpoint.getBinding();
  25. /*
  26. * 设置一个SOAP协议处理栈
  27. * 这里就简单得打印SOAP的消息文本
  28. */
  29. List<Handler> handlerChain = new LinkedList<Handler>();
  30. handlerChain.add(new TraceHandler());
  31. binding.setHandlerChain(handlerChain);
  32. System.out.println("服务已启动 http://localhost:8080/hello");
  33. }
  34. }
package org.jsoso.jws.server;import java.util.LinkedList;
import java.util.List;
import javax.xml.ws.Binding;
import javax.xml.ws.Endpoint;
import javax.xml.ws.handler.Handler;/*** @author zsy 启动web services服务*/
public class StartServer {/*** @param args*/public static void main(String[] args) {/** 生成Example 服务实例*/Example serverBean = new Example();/** 公布Web Service到http://localhost:8080/hello地址*/Endpoint endpoint = Endpoint.publish("http://localhost:8080/hello", serverBean);Binding binding = endpoint.getBinding();/** 设置一个SOAP协议处理栈* 这里就简单得打印SOAP的消息文本*/List<Handler> handlerChain = new LinkedList<Handler>();handlerChain.add(new TraceHandler());binding.setHandlerChain(handlerChain);System.out.println("服务已启动 http://localhost:8080/hello");}
}

在控制台执行这个类,就能够使用URL :http://localhost:8080/hello?wsdl 浏览到上文所描写叙述的WSDL的全文了。这说明您的第一个Web Service应用公布成功!

构建Web Serviceclient
使用JavaSE6.0构建Web Service的client是一件相当简单的事。这里我们要使用到JDK中的还有一个命令行工具wsimport。在控制台下输入下面命令:

引用
wsimport -d ./bin -s ./src -p org.jsoso.jws.client.ref http://localhost:8080/hello?wsdl

就可以在包org.jsoso.jws.client.ref中生成client的存根及框架文件。当中我们要使用的类仅仅有两个:服务类Example_Service和本地接口Example。编写例如以下client,就可以调用Web Service服务:

Java代码
  1. package org.jsoso.jws.client;
  2. import org.jsoso.jws.client.ref.*;
  3. public class RunClient {
  4. /**
  5. * @param args
  6. */
  7. public static void main(String[] args) {
  8. //初始化服务框架类
  9. Example_Service service = new Example_Service();
  10. //或者本地服务借口的实例
  11. Example server = (Example) service.getExamplePort();
  12. try {
  13. //调用web service的toSayHello方法
  14. System.out.println("输入toSayHello的返回值——" + server.toSayHello("阿土"));
  15. Person person = new Person();
  16. person.setName("阿土");
  17. person.setAge(25);
  18. //调用web service的sayHello方法
  19. server.sayHello(person, "机器人");
  20. person = new Person();
  21. person.setName("aten");
  22. person.setAge(30);
  23. //调用web service的sayHello方法
  24. PersonArray list = server.sayHello(person, "机器人");
  25. //输出返回值
  26. System.out.println("/n下面输入sayHello的返回值——");
  27. for (Person p : list.getItem()) {
  28. System.out.println(p.getName() + ":" + p.getAge());
  29. }
  30. } catch (HelloException_Exception e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }
package org.jsoso.jws.client;import org.jsoso.jws.client.ref.*;public class RunClient {/*** @param args*/public static void main(String[] args) {//初始化服务框架类Example_Service service = new Example_Service();//或者本地服务借口的实例Example server = (Example) service.getExamplePort();try {//调用web service的toSayHello方法System.out.println("输入toSayHello的返回值——" + server.toSayHello("阿土"));         Person person = new Person();person.setName("阿土");person.setAge(25);//调用web service的sayHello方法server.sayHello(person, "机器人");person = new Person();person.setName("aten");person.setAge(30);//调用web service的sayHello方法PersonArray list = server.sayHello(person, "机器人");//输出返回值System.out.println("/n下面输入sayHello的返回值——");for (Person p : list.getItem()) {System.out.println(p.getName() + ":" + p.getAge());}            } catch (HelloException_Exception e) {e.printStackTrace();}}
}

届此,本次Web Service的学习暂告一个段落。Java Web Service是一个相当庞大的知识体系,当中涉及的相关技术较多,这里无法一一道来,我们将会在今后的开发和使用中,同大家做进一步深入的探讨和学习。

附录:wsgen与wsimport命令说明

wsgen
wsgen是在JDK的bin文件夹下的一个exe文件(Windows版),该命令的主要功能是用来生成合适的JAX-WS。它读取Web Service的终端类文件,同一时候生成全部用于公布Web Service所依赖的源码文件和经过编译过的二进制类文件。这里要特别说明的是,通常在Web Service Bean中用到的异常类会另外生成一个描写叙述Bean,假设Web Service Bean中的方法有申明抛出异常,这一步是必需的,否则server无法绑定该对像。此外,wsgen还能辅助生成WSDL和相关的xsd文件。wsgen从资源文件生成一个完整的操作列表并验证web service是否合法,能够完整公布。
命令參数说明:

  •  -cp 定义classpath
  •  -r 生成 bean的wsdl文件的存放文件夹
  •  -s 生成公布Web Service的源码文件的存放文件夹(假设方法有抛出异常,则会生成该异常的描写叙述类源文件)
  •  -d 生成公布Web Service的编译过的二进制类文件的存放文件夹(该异常的描写叙述类的class文件)

命令范例:wsgen -cp ./bin -r ./wsdl -s ./src -d ./bin -wsdl org.jsoso.jws.server.Example

wsimport
wsimport也是在JDK的bin文件夹下的一个exe文件(Windows版),主要功能是依据服务端公布的wsdl文件生成client存根及框架,负责与Web Service server通信,并在将其封装成实例,client能够直接使用,就像使用本地实例一样。对Java而言,wsimport帮助程序猿生存调用web service所须要的client类文件.java和.class。要提醒指出的是,wsimport能够用于非Java的server端,如:server端或许是C#编写的web service,通过wsimport则生成Java的client实现。
命令參数说明:

  •  -d 生成client运行类的class文件的存放文件夹
  •  -s 生成client运行类的源文件的存放文件夹
  •  -p 定义生成类的包名

命令范例:wsimport -d ./bin -s ./src -p org.jsoso.jws.client.ref http://localhost:8080/hello?wsdl

转载于:https://www.cnblogs.com/blfshiye/p/4384446.html

Web Service学习笔记相关推荐

  1. Web Service学习笔记(4)

    代理类文件: 在客户端使用程序中生成的Reference.cs的文件即代理类,Service1.wsdl为相应的XML文件 代理类说明: 1. 代理类开始是引出一系列的命名空间,代码的主题是定义一个跟 ...

  2. Web Service 学习笔记(2)

    1.SOAP的目标是允许使用标准化的方法在客户机和运行在Internet上的应用程序交换原文的信息. 2.每个SOAP消息都是一个XML文档,XML文档具有一个根元素,即SOAP封套. 3.串行化:把 ...

  3. Spring Web Service 学习之Hello World篇

    http://fuxueliang.iteye.com/blog/175184 Spring Web Service是Spring社区基于Spring提供的一个关注于创建"文档驱动" ...

  4. Web Components 学习笔记一: Web Components是什么?解决了什么问题?

    公众号:妙蛙种子前端 文章原文地址:Web Components笔记一: Web Components是什么?解决了什么问题? | 妙蛙种子 - 记录WEB前端技术学习成长过程的博客 Web Comp ...

  5. Java web与web gis学习笔记(二)——百度地图API调用

    系列链接: Java web与web gis学习笔记(一)--Tomcat环境搭建 Java web与web gis学习笔记(二)--百度地图API调用 JavaWeb和WebGIS学习笔记(三)-- ...

  6. web安全学习笔记--sql语句(sql注入基础上)

    一.基础知和表内操作语法 1.sql语句对大小写不敏感!!! SELECT - 从数据库表中获取数据:select * from (columns/tables/databases); UPDATE ...

  7. 《Android 第一行代码》十一章 Service学习笔记

    Android中Service学习笔记 Service的基本使用方法 Service的启动方式有两种,第一种是使用startService()和stopService()方法来启动和停止Service ...

  8. web前端学习笔记(最新)

    web前端学习笔记 大家好,我是链表哥,新的学期,新的学习,我会为您展示我的学习进程. 一:什么是WEB前端? 所谓的Web前端指的是用户所能接触到的,并服务于用户的前沿端口,经我们程序员编辑修饰后展 ...

  9. Android 使用 ksoap2-android调用Web Service学习

    今天学习<疯狂Android讲义>,看到web service的使用这章时,准备点时间,做个学习笔记,做一个天气预报的apk出来,顺便也巩固下sharedpreference 的用法 该文 ...

最新文章

  1. 大学老师吐血自白:指导学生写论文真是太太太太太难了!
  2. 如何解决从数据库里面取出的时间晚了8个小时
  3. Windows之建立C++开发环境
  4. linux shell命令行及脚本编程实例详解_Linux高手必看的10本经典书籍
  5. Go基础--goroutine和channel
  6. C# 操作MSSQL数据库类
  7. 《英雄联盟:双城之战》全球首映 沉浸式观影打造追剧新潮流
  8. 百度地图API画多边型,测面积
  9. 白话CMMI(一)——CMMI扫盲
  10. vs c语言绘图函数,C语言图形编程(绘图函数部分)
  11. extmail mysql数据库 重启_配置extmail过程详解 | 学步园
  12. 基于DSP的交通灯设计
  13. Golang 高效编程 分号的使用 与 风格
  14. python海龟交易策略_python 海龟交易法则 股票回测-双均线规则(一)
  15. GStreamer修改解码器默认优先级
  16. 本题目要求读入2个整数A和B,然后输出它们的和
  17. 安装出错:Command line option syntax error.Type Command /? for help.解决方案
  18. 重磅!五大电力央企“一把手”华山论剑深谈数字化转型
  19. android支付安全机制,Android_指纹支付_安全问题_前后端交互逻辑
  20. SecureCRT和SecureFx的使用

热门文章

  1. JBPM流程部署校验之java利用XSD校验XML
  2. webpack 相关文章
  3. weblogic调优的经过
  4. C#字典Dictionary排序(顺序、倒序)
  5. hdu 5615 Jam's math problem(判断是否能合并多项式)
  6. js调试工具console详解
  7. 寻找实力高手长期合作
  8. 【集训队互测2015】最大异或和
  9. linq to sql实战
  10. python 为空判断场景