webService wsdl详解
<wsdl:definitions
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:ns1="http://org.apache.axis2/xsd"
xmlns:ns="http://impl.service.utcs.ctc"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:ax21="http://beans.service.utcs.ctc/xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
targetNamespace="http://impl.service.utcs.ctc"> <wsdl:documentation>UtcsClient</wsdl:documentation>
Types 是一个数据类型定义的容器。Element元素定义在消息(message)定义中需要的XML元素的类型定义。complexType 元素定义了XML元素由哪些具体的类型组成以及组成元素的顺序。 complexType元素如果放在Types元素下面而又不被element元素包含,那么它就定义了一个公用的数据类型。可以被多个element元素所引用 <wsdl:types> <xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://beans.service.utcs.ctc/xsd"> <xs:complexType name="CrossControlMode"> <!- 定义一个 CrossControlMode类 这个类有三个属性crossID,value,sHeadPackage -> <xs:sequence> <xs:element minOccurs="0" name="crossID" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="value" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="sHeadPackage" nillable="true" type="ax21:HeadPackage"/> </xs:sequence> </xs:complexType> <xs:complexType name="HeadPackage"> <xs:sequence> <xs:element minOccurs="0" name="from" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="seq" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="to" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="token" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="type" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="version" nillable="true" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="CrossCycle"> <xs:sequence> <xs:element minOccurs="0" name="crossID" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="lastCycleLen" type="xs:short"/> <xs:element minOccurs="0" name="startTime" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="sHeadPackage" nillable="true" type="ax21:HeadPackage"/> </xs:sequence> </xs:complexType> <xs:complexType name="CrossParam"> <xs:sequence> <xs:element minOccurs="0" name="crossID" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="crossName" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="detID" nillable="true" type="xs:string"/> <xs:element maxOccurs="unbounded" minOccurs="0" name="detIDList" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="feature" nillable="true" type="xs:string"/> <xs:element minOccurs="0" name="isKey" type="xs:short"/> <xs:element maxOccurs="unbounded" minOccurs="0" name="laneNoList" nillable="true" type="xs:short"/> <xs:element maxOccurs="unbounded" minOccurs="0" name="phaseNoList" nillable="true" type="xs:short"/> <xs:element maxOccurs="unbounded" minOccurs="0" name="planNoList" nillable="true" type="xs:short"/> <xs:element maxOccurs="unbounded" minOccurs="0" name="stageNoList" nillable="true" type="xs:short"/> <xs:element minOccurs="0" name="sHeadPackage" nillable="true" type="ax21:HeadPackage"/> </xs:sequence> </xs:complexType>
WSDL: Web 服务描述语言(Web Services Descirption Language). a. 服务提供者是通过web服务描述将所有用于调用Web服务的规范传送给服务请求者的。 b. WSDL是通过标准的XML格式来描述Web服务。 c. 它用一种与实现语言无关的抽象方式定义了web服务的操作和消息。 d. 操作和消息被抽象描述,然后绑定到具体的网络协议和端点。 e. web服务包含了一组抽象的端点。 WSDL概念模型: 1. 服务做些什么: 服务所提供的操作(方法)。 对应porttype,operation元素。 2. 如何访问服务: 数据格式详情(types,message)及访问服务操作的必要协议(Binding)。 3. 服务位于何处: 由特定协议约定的网络地址。如URL。 (service,port)。 WSDL的组成元素 1. Types 是一个数据类型定义的容器。Element元素定义在消息(message)定义中需要的XML元素的类型定义。complexType 元素定义了XML元素由哪些具体的类型组成以及组成元素的顺序。 complexType元素如果放在Types元素下面而又不被element元素包含,那么它就定义了一个公用的数据类型。可以被多个element元素所引用。 例如: <wsdl:types> <xsd:schema targetNamespace="" xmlns="" xmlns:wsdl="" elementFormDefault="qualified"> <xsd:complexType name="Transaction"> <xsd:sequence> <xsd:element minOccurs="1" maxOccurs="1" name="number" type="xsd:int" /> <xsd:element minOccurs="0" maxOccurs="1" name="checknumber" type="xsd:int" /> <xsd:element minOccurs="1" maxOccurs="1" name="date" type="xsd:date" /> <xsd:element minOccurs="1" maxOccurs="1" name="header" type="xsd:string" /> <xsd:element minOccurs="1" maxOccurs="1" name="amount" type="xsd:float" /> </xsd:sequence> </xsd:complexType> 这是一个复杂类型的定义,这个有点像定义了一个叫做Transaction的类,而这个类有属性number,checknumber,date,header和amount。这里定义了一个公用的数据类型结构。 <xsd:element name="LookupTransactionsResponse"> <xsd:complexType> <xsd:sequence> <xsd:element minOccurs="0" maxOccurs="unbounded" name="transactions" type="xsd1:Transaction" /> </xsd:sequence> </xsd:complexType> </xsd:element> 这里定义了一个数据类型元素(element)叫做LookupTransactionsResponse,在这里引用了前面定义的Transaction的集合. 在后面的消息定义中将会引用到这里所定义的数据类型元素。 <xsd:element name="LookupTransactions"> <xsd:complexType> <xsd:sequence> <xsd:element minOccurs="1" maxOccurs="1" name="accountNumber" type="xsd:int" /> <xsd:element minOccurs="0" maxOccurs="1" name="date1" type="xsd:date" /> <xsd:element minOccurs="0" maxOccurs="1" name="date2" type="xsd:date" /> <xsd:element minOccurs="1" maxOccurs="1" name="token" type="xsd:base64Binary" /> </xsd:sequence> </xsd:complexType> </xsd:element> 这里定义的数据类型是一个参数列表,它有accountNumber,date1,date2,token组成。类似于 SomeObject.lookupTransactions(accountNumber,date1,date2,token) 里面的参数列表。complexType 定义在了element里面,那么这个数据类型结构只能是LookupTransactions 私有的了。 </xsd:schema> </wsdl:types> 2. Message具体定义了在通信中使用的消息的数据结构。什么叫通信中使用?因为WSDL是给调用服务的人看的。那我要调用你的服务,我的soap请求消息应该怎么写呢,格式是什么呢?这里就给出定义了。 <wsdl:message name="LookupTransactionsResponse"> <wsdl:part name="parameters" element="xsd1:LookupTransactionsResponse" /> </wsdl:message> 这里定义了服务在调用之后消息返回的数据格式。其名字为parameters,数据的类型就是xsd1:LookupTransactionsResponse。 <wsdl:message name="LookupTransactions"> <wsdl:part name="parameters" element="xsd1:LookupTransactions" /> </wsdl:message> 这里定义了访问服务时需要传什么样的数据。 3. PortType 具体定义了一个服务可以访问的接口。是对于某个端口类型所支持操作的抽象集合。其实就是说服务定义了多少个可以被调用的方法。 这里面有两层意思:第一,针对某个端口(porttype),如soap端口类型,http端口类型。端口可以包含任意数量的操作。第二,定义了服务所拥有的操作(operation)。 <wsdl:portType name="OnlineBankingPortType"> <wsdl : peration name="LookupTransactions"> <wsdl:input message="tns:LookupTransactions" /> <wsdl : utput message="tns:LookupTransactionsResponse" /> </wsdl : peration> </wsdl:portType> 这里定义了一个可以访问的方法LookupTransactions。这个方法的入参,又叫入站消息吧是message里面定义的tns:LookupTransactions。 同时这个方法还有一个返回对象,又叫出战消息,是message里面所定义的tns:LookupTransactionsResponse <wsdl:portType name="ChinaStockWebServiceSoap"> <wsdl : peration name="getStockImageByCode"> <wsdl:documentation xmlns:wsdl=""> sdf </wsdl:documentation> <wsdl:input message="tns:getStockImageByCodeSoapIn" /> <wsdl : utput message="tns:getStockImageByCodeSoapOut" /> </wsdl : peration> </wsdl:portType> <wsdl:portType name="ChinaStockWebServiceHttpPost"> <wsdl : peration name="getStockImageByCode"> <wsdl:documentation xmlns:wsdl=""> test </wsdl:documentation> <wsdl:input message="tns:getStockImageByCodeHttpPostIn" /> <wsdl : utput message="tns:getStockImageByCodeHttpPostOut" /> </wsdl : peration> </wsdl:portType> 这个例子就定义了两个端口类型soap和httppost。 Types,Message和PortType抽象地描述了是如何调用webservice的,与具体的web服务部署无关。注意这里全部用的是wsdl的命名空间。没有用到soap的命名空间。在后面的绑定和部署就会用到soap消息的命名空间了。 4. Binding 定义了某个PortType与某个具体的网络传输协议或是消息传输协议的绑定。 <wsdl:binding name="OnlineBankingPortBinding" type="tns:OnlineBankingPortType"> <soap:binding transport="" /> <wsdl : peration name="LookupTransactions"> <soap : peration soapAction="" /> <wsdl:input> <soap:body use="literal" /> </wsdl:input> <wsdl : utput> <soap:body use="literal" /> </wsdl : utput> </wsdl : peration> </wsdl:binding> 前面所定义的端口类型OnlineBankingPortType 绑定在 soap/http协议上面了。这里用到soap的命名空间进行了绑定。 Soap:binding :指出绑定是针对soap协议格式的。Transport指定了传输协议。Style指定通信风格。有“rpc”和“document”两种风格。 Soap : peration :为SOAP服务操作提供消息。通常可以指明此操作的SOAPActionHTTP头。 Soap:body :指出消息如何在SOAP BODY元素中表现。 5. Service 一个服务所有访问入口的部署细节。一个Service往往包含多个访问入口(如URL),每个访问入口都会使用一个port来描述。 6. Port 描述一个服务访问入口的部署细节。由哪个web地址(URL)来访问,绑定到什么样的端口上面。 <wsdl:service name="OnlineBankingService"> <wsdl:port name="OnlineBankingPort" binding="tns:OnlineBankingPortBinding"> <soap:address location="http://localhost:8080/axis2/services/OnlineBankingService" /> </wsdl:port> </wsdl:service> Soap:address 为SOAP服务访问指定的网络地址。 下面的例子就定义了多个访问端口。 <wsdl:service name="ChinaStockWebService"> <wsdl:documentation xmlns:wsdl=""> test </wsdl:documentation> <wsdl:port name="ChinaStockWebServiceSoap" binding="tns:ChinaStockWebServiceSoap"> <soap:address location="" /> </wsdl:port> <wsdl:port name="ChinaStockWebServiceSoap12" binding="tns:ChinaStockWebServiceSoap12"> <soap12:address location="" /> </wsdl:port> <wsdl:port name="ChinaStockWebServiceHttpGet" binding="tns:ChinaStockWebServiceHttpGet"> <http:address location="" /> </wsdl:port> <wsdl:port name="ChinaStockWebServiceHttpPost" binding="tns:ChinaStockWebServiceHttpPost"> <http:address location="" /> </wsdl:port> </wsdl:service> 客户端测试代码: public class OnlineBankAXIOMClient { private static EndpointReference targetEPR = new EndpointReference( "http://localhost:8088/ums/services/OnlineBankingService"); public static OMElement getLoginPayload(String usernamestr,String passswordstr) { OMFactory fac = OMAbstractFactory.getOMFactory(); //命名空间必须是, //而不是 //因为这里是定义消息格式的命名空间。在Types元素里面的定义是 //<wsdl:types> //<xsd:schema //targetNamespace="" //....... //所以数据类型的定义的命名空间就是"" OMNamespace omNs = fac.createOMNamespace( "", "tns"); OMElement method = fac.createOMElement("login", omNs); OMElement username = fac.createOMElement("username", omNs); username.addChild(fac.createOMText(username, usernamestr)); method.addChild(username); OMElement password = fac.createOMElement("password", omNs); password.addChild(fac.createOMText(password, passswordstr)); method.addChild(password); return method; } public static void main(String[] args) { try { OMElement payload = getLoginPayload("dragon","123"); Options options = new Options(); options.setTo(targetEPR); //这里必须配置SOAPAction=; //否则就会报“org.apache.axis2.AxisFault: //The endpoint reference (EPR) for the Operation not found is //http://localhost:8088/ums/services/OnlineBankingService and the WSA Action = urn:anonOutInOp” //的错误. //而且必须跟WSDL里面定义的一致 //<wsdl : peration name="Login"> //<soap : peration soapAction="" /// /> options.setAction(""); options.setExceptionToBeThrownOnSOAPFault(true); options.setTransportInProtocol(Constants.TRANSPORT_HTTP); ServiceClient sender = new ServiceClient(); sender.setOptions(options); OMElement result = sender.sendReceive(payload); String response = result.getFirstElement().getText(); System.out.println("if login is valid: " + response); } catch (Exception e) { e.printStackTrace(); } } } 小结: 1. 想要很好地运用AXIOM写客户端程序,必须要充分熟悉WSDL规范的定义。 2. 注意命名空间。 3. 采用自底向上的实现(code-->WSDL)方法虽然开发轻松,但是很多知识点会弄不清楚。 采用自顶向下的实现(WSDL-->code)方法可控性更强,可以更好地掌握知识点。