本文介紹了如何編寫(xiě)一個(gè)簡(jiǎn)單的WSDL文件,并根據(jù)WSDL文件編寫(xiě)服務(wù)器端和客戶端代碼,并發(fā)布Web Service服務(wù)的過(guò)程。
首先明確的一點(diǎn)是WSDL現(xiàn)在有兩個(gè)版本,分別為WSDL 1.1和WSDL 2.0,W3C的官方文檔地址分別為:
Web Services Descrīption Language (WSDL) 1.1
W3C Note 15 March 2001
和
Web Services Descrīption Language (WSDL) Version 2.0 Part 0: Primer
W3C Working Draft 26 March 2007
其中很多應(yīng)用還是以版本1.1為基礎(chǔ)實(shí)現(xiàn)。下面是2.0與1.1的區(qū)別:
Adding further semantics to the descrīption language.
Removal of message constructs.
No support for operator overloading.
PortTypes renamed to interfaces.
Ports renamed to endpoints.
下面是一些常見(jiàn)的命名空間:
prefix namespace URI
wsdl http://schemas.xmlsoap.org/wsdl/
soap http://schemas.xmlsoap.org/wsdl/soap/
http http://schemas.xmlsoap.org/wsdl/http/
mime http://schemas.xmlsoap.org/wsdl/mime/
soapenc http://schemas.xmlsoap.org/soap/encoding/
soapenv http://schemas.xmlsoap.org/soap/envelope/
xsi http://www.w3.org/2000/10/XMLSchema-instance
xsd http://www.w3.org/2000/10/XMLSchema
tns (various)
對(duì)于WSDL規(guī)范,可以參考以上兩個(gè)官方文檔,本文主要介紹如何編寫(xiě)WSDL文檔(其實(shí)官方文檔中已經(jīng)給出了很多例子和方法,這里只是簡(jiǎn)單的翻譯與重復(fù)介紹)。
下面舉例說(shuō)明如何編寫(xiě)WSDL文檔:
我們做一個(gè)非常簡(jiǎn)單的加法運(yùn)算服務(wù):客戶端傳入SOAP請(qǐng)求消息,包含兩個(gè)加數(shù),然后在服務(wù)器端獲取這兩個(gè)加數(shù),求和,然后返回給客戶端。
請(qǐng)求消息和響應(yīng)消息結(jié)構(gòu)分別如下(有效負(fù)載部分,外層的SOAP封裝AXIS2會(huì)自動(dòng)添加上去):
request:
<SumRequest>
<First>15</First>
<Second>16</Second>
</SumRequest>
response:
<SumResponse>
<Result>31</Result>
</SumResponse>
1.首先需要進(jìn)行定義的就是soap消息的數(shù)據(jù)類型,無(wú)疑,這里需要定義兩個(gè)復(fù)雜的數(shù)據(jù)類型:
SumRequest
SumResponse
它們分別包含有子元素First、Second和Result.
另外還需要定義一種異常,這里我們定義成為SumFault,比如傳入的兩個(gè)加數(shù)的和超出了xsd:int的范圍時(shí),拋出該異常。
(注意,很多代碼生成器都會(huì)根據(jù)WSDL生成代碼,將SumFault部分生成為后綴為Exception的異常類。)
2.定義數(shù)據(jù)類型的目的是為傳入傳出消息做準(zhǔn)備的,傳入傳出消息的定義方式使用message元素來(lái)定義。
我們定義三種消息:SumRequest,SumResponse以及SumFault,分別為請(qǐng)求消息,響應(yīng)消息以及出錯(cuò)時(shí)的消息。
3.定義好了傳入傳出消息后,就要定義一個(gè)portType,該節(jié)點(diǎn)類型定義了主要的業(yè)務(wù)操作。
4.接著將定義SOAP綁定:
SumSoapBinding:為SumService端口類型所定義的操作和消息指定具體傳輸中所使用的消息格式和協(xié)議細(xì)節(jié)。綁定的方式為SOAP,傳輸方式為http,消息的格式為document。
5.定義Web服務(wù):Web服務(wù)名為SumService。
6.本W(wǎng)eb服務(wù)的操作為Sum操作。
7.端口為:為SumSoapBing綁定指定一個(gè)地址來(lái)定義服務(wù)訪問(wèn)點(diǎn)。
根據(jù)以上七個(gè)部分編寫(xiě)完成的WSDL文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.zzl.org/Sum"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.zzl.org/Sum">
<wsdl:documentation>
The WSDL file of SumService.
</wsdl:documentation>
<wsdl:types>
<wsdl:documentation>
Data types that are used for request and response messages.
</wsdl:documentation>
<xsd:schema targetNamespace="http://www.zzl.org/Sum">
<xsd:element name="SumRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="First" type="xsd:int" />
<xsd:element name="Second" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="SumResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Result" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="SumFault">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:message name="SumRequest">
<wsdl:documentation>
The data that will be transmitted to the service.
</wsdl:documentation>
<wsdl:part element="tns:SumRequest" name="request" />
</wsdl:message>
<wsdl:message name="SumResponse">
<wsdl:documentation>
The data that will be returned to the client.
</wsdl:documentation>
<wsdl:part element="tns:SumResponse" name="response" />
</wsdl:message>
<wsdl:message name="SumFault">
<wsdl:documentation>
The fault that will be thrown when fault occurs.
</wsdl:documentation>
<wsdl:part name="axisFault" element="tns:SumFault" />
</wsdl:message>
<wsdl:portType name="SumService">
<wsdl:documentation>
The SumService contains the business operation.
</wsdl:documentation>
<wsdl:operation name="RevokeCert">
<wsdl:documentation>
The operation that do the business work.
</wsdl:documentation>
<wsdl:input message="tns:SumRequest" />
<wsdl:output message="tns:SumResponse" />
<wsdl:fault name="fault" message="tns:SumFault" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="SumSoapBinding" type="tns:SumService">
<wsdl:documentation>
The SumSoapBinding defines the SOAP message format and
protocol details for Sum operation and messages defined by a
RevokeService portType.
</wsdl:documentation>
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="Sum">
<soap:operation soapAction="urn:Sum" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
<wsdl:fault name="fault">
<soap:fault use="literal" name="fault" />
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="SumService">
<wsdl:documentation>
SumService provides the service of summing.
</wsdl:documentation>
<wsdl:port binding="tns:SumSoapBinding" name="SumSoapBinding">
<wsdl:documentation>
The port defines the endpoint by specifying a soap
address for SumSoapBinding.
</wsdl:documentation>
<soap:address location="http://www.zzl.org/ExampleService/services/SumService" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
服務(wù)器端和客戶端的代碼是根據(jù)WSDL文件編寫(xiě)出來(lái)的,這才是正確的過(guò)程,但是,在國(guó)內(nèi)的軟件開(kāi)發(fā)過(guò)程,常常是先寫(xiě)代碼,再根據(jù)代碼生成WSDL文件,這是不正確的。
編寫(xiě)服務(wù)器端的程序如下:
1. 建立工程ExampleService.如下圖所示:
2. 編寫(xiě)服務(wù)器端代碼:
SumService.java
package org.zzl.service;
import javax.xml.namespace.QName;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.AxisFault;
/**
* The Web Service class SumService which implement add two number and return
* the result.
*
* @author zhangzhongl@gmail.com
* @version 0.7
*/
public class SumService {
/**
* The request soap message object.
*/
private OMElement requestSoap = null;
/**
* First addend.
*/
private static final String FIRST = "First";
/**
* Second addend.
*/
private static final String SECOND = "Second";
/**
* Sum Response element.
*/
private static final String SUM_RESPONSE = "SumResponse";
/**
* Result element.
*/
private static final String SUM = "Result";
public OMElement Sum(OMElement soap) throws AxisFault {
requestSoap = soap;
OMElement first=
requestSoap.getFirstChildWithName(new QName(FIRST));
OMElement second =
requestSoap.getFirstChildWithName(new QName(SECOND));
int sum = Integer.parseInt(first.getText())
+ Integer.parseInt(second.getText());
return getResponse(sum);
}
/**
* Get the SOAP response message.
*
* @param sum
* The adding result.
* @return The SOAP response message.
*/
private OMElement getResponse(int sum) {
OMFactory factory = OMAbstractFactory.getOMFactory();
OMNamespace ōmNs = factory.createOMNamespace("", "");
OMElement response = factory.createOMElement(SUM_RESPONSE, omNs);
OMElement sumElement = factory.createOMElement(SUM, omNs);
sumElement.setText(String.valueOf(sum));
response.addChild(sumElement);
return response;
}
}
編寫(xiě)客戶端代碼:
TestSumService.java
package org.zzl.service.test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
public class TesSumService{
private static EndpointReference targetEPR = new EndpointReference(
"http://localhost/axis2/services/SumService");
public static void main(String[] args) throws FileNotFoundException,
FactoryConfigurationError, XMLStreamException {
OMElement requestSoapMessage =
getSoapRequestMessage("data/request.xml");
Options ōptions = new Options();
options.setAction("urn:Sum");
options.setTo(targetEPR);
ServiceClient sender = null;
try {
sender = new ServiceClient();
sender.setOptions(options);
System.out.println(sender.sendReceive(requestSoapMessage)
.toStringWithConsume());
} catch (AxisFault e) {
System.out.println(e.getMessage());
}
}
public static OMElement getSoapRequestMessage(String filePath)