Contents
·什么是WebService?
- WebService,顾名思义就是基于Web的服务。它使用Web(HTTP)方式,接收和响应外部系统的某种请求。从而实现远程调用。
- 从WebService的工作模式上理解的话,它跟普通的Web程序(比如ASP、JSP等)并没有本质的区别,都是基于HTTP传输协议的程序。
- WebService所使用的数据均是基于XML格式的。目前标准的WebService在数据格式上主要采用SOAP协议。SOAP协议实际上就是一种基于XML编码规范的文本协议。
·WebService三要素
-
SOAP:用来描述传递信息的格式。
SOAP是一种简单的基于XML的协议,可以使应用程序在分散或分布式的环境中通过HTTP来交换信息。它基于XML语言和XSD标准,其定义了一套编码规则,编码规则定义如何将数据表示为消息,以及怎样通过HTTP协议来传输SOAP消息,一条 SOAP 消息就是一个普通的 XML 文档,包含下列元素:
-
必需的 Envelope 元素,它可把 XML 文档定义为 SOAP 消息。
-
xmlns:soap 命名空间: SOAP 消息必须拥有与命名空间 “http://www.w3.org/2001/12/soap-envelope” 相关联的一个 Envelope 元素,如果使用了不同的命名空间,应用程序会发生错误,并抛弃此消息。
-
encodingStyle :SOAP 的 encodingStyle 属性用于定义在文档中使用的数据类型。此属性可出现在任何 SOAP 元素中,并会被应用到元素的内容及元素的所有子元素上。
-
-
可选的 Header 元素,包含头部信息,作用是可包含有关 SOAP 消息的应用程序专用信息(比如认证、支付等)。
-
必需的 Body 元素,可以包含打算传送到消息最终端点的实际 SOAP (调用或响应信息)消息。
-
可选的 Fault 元素,提供有关在处理此消息所发生错误的信息,如果已提供了 Fault 元素,则它必须是 Body 元素的子元素。在一条 SOAP 消息中,Fault 元素只能出现一次。
SOAP 的 Fault 元素拥有下列子元素:
子元素 描述 供识别故障的代码 可供人阅读的有关故障的说明 有关是谁引发故障的信息 存留涉及 Body 元素的应用程序专用错误信息
SOAP消息的基本结构
<?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>
-
-
WSDL: 用来描述如何访问具体的接口。
WSDL是一个用于精确描述Web服务的文档,WSDL文档是一个遵循WSDL-XML模式的XML文档。WSDL 文档将Web服务定义为服务访问点或端口的集合。在 WSDL 中,由于服务访问点和消息的抽象定义已从具体的服务部署或数据格式绑定中分离出来,因此可以对抽象定义进行再次使用。消息,指对交换数据的抽象描述;而端口类型,指操作的抽象集合。用于特定端口类型的具体协议和数据格式规范构成了可以再次使用的绑定。将Web访问地址与可再次使用的绑定相关联,可以定义一个端口,而端口的集合则定义为服务。
一个WSDL文档通常包含8个重要的元素,即definitions、types、import、message、portType、operation、binding、service元素。这些元素嵌套在definitions元素中,definitions是WSDL文档的根元素。
WSDL结构样例:
<definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://service.easyway.net.cn/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://service.easyway.net.cn/" name="MyServiceImplService"> <types> <xsd:schema> <xsd:import namespace="http://service.easyway.net.cn/" schemaLocation="http://localhost:8888/ws?xsd=1"/> </xsd:schema> </types> <message name="login"> <part name="parameters" element="tns:login"/> </message> <message name="loginResponse"> <part name="parameters" element="tns:loginResponse"/> </message> <portType name="IMyService"> <operation name="login"> <input message="tns:login"/> <output message="tns:loginResponse"/> </operation> </portType> <binding name="MyServiceImplPortBinding" type="tns:IMyService"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/> <operation name="login"> <soap:operation soapAction=""/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> <service name="MyServiceImplService"> <port name="MyServiceImplPort" binding="tns:MyServiceImplPortBinding"> <soap:address location="http://localhost:8888/ws"/> </port> </service> </definitions>
-
2.1 types:用来定义访问的数据类型。这个类型是有谁生成的呢?请看上面代码第4行的schemaLocation属性,把http://localhost:8888/ws?xsd=1拷贝到浏览器,回车,就会出现如下文档:
<xs:schema xmlns:tns="http://service.easyway.net.cn/" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://service.easyway.net.cn/"> <xs:element name="login" type="tns:login"/> <xs:element name="loginResponse" type="tns:loginResponse"/> <xs:complexType name="login"> <xs:sequence> <xs:element name="username" type="xs:string" minOccurs="0"/> <xs:element name="password" type="xs:string" minOccurs="0"/> </xs:sequence> </xs:complexType> <xs:complexType name="loginResponse"> <xs:sequence> <xs:element name="loginUser" type="tns:user" minOccurs="0"/> </xs:sequence> </xs:complexType> <xs:complexType name="user"> <xs:sequence> <xs:element name="id" type="xs:int"/> <xs:element name="password" type="xs:string" minOccurs="0"/> <xs:element name="username" type="xs:string" minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:schema>
从上面文档中看出,有两个元素分别是login和loginResponse,也就是参数和返回值,并且里面详细的定义了方法参数以及返回值的具体类型,直到基本类型(type),因此,可以看出,不论是多么复杂的数据结构,用这种方式都可以用基本类型的方式表现出来。
-
2.2 import:import元素使得可以在当前的WSDL文档中使用其他WSDL文档中指定的命名空间中的定义元素。本例子中没有使用import元素。通常在用户希望模块化WSDL文档的时候,该功能是非常有效果的。 import的格式如下:
<wsdl:import namespace="http://xxx.xxx.xxx/xxx/xxx" location="http://xxx.xxx.xxx/xxx/xxx.wsdl"/>
必须有namespace属性和location属性: namespace属性:值必须与正导入的WSDL文档中声明的targetNamespace相匹配; location属性:必须指向一个实际的WSDL文档,并且该文档不能为空。
-
2.3 message:定义好数据类型后,我们就要存储这种信息,并且传递,存储这个信息的叫做SOAP(Simple Object Access Protocol,关于SOAP后面会重点讲),这个消息就叫做SOAPMessage,传递就是通过SOAP协议来传递的。一般有多少个方法一般就会产生二倍的消息,是因为参数需要一个消息,返回值也需要一个消息,可以继续看上面wsdl的文档,message有login和loginResponse两个,一个是用来传递参数,一个是用来传递返回值。到此时,我们就把把消息和元素对应起来了。
-
2.4 portType:定义好消息后,要在服务器端指明哪个接口对它进行操作,也就是指明接口名称,并且要指明接口中有哪些方法,大家可观察上面的wsdl文档,operation就是绑定该接口有哪些方法(login),input表示方法参数,output表示返回值。
-
2.5 binding:指明传递消息所用的格式。定义消息应该以什么样的形式呈现给用户,有两种形式:document和RPC,用的最多的是document,关于二者区别可以自行查询,不在此概述。确定展现形式后,那用什么方式进行传递呢,有两种:literal和encoded,前者是通过XML方式传递,后者通过RMI的方式来访问,因为jdk6之前是不能用jax进行访问的,只能通过RMI。
-
2.6 service:指定服务所发布的名称。需要注意的是服务的名称和上面definitions的名称是一致的,port的名称就是绑定服务的名称,而服务发布的地址可能是与WSDL地址不同的。
-
-
UDDI:用来管理,分发,查询webService 。具体实现可以搜索 Web Services简单实例(可以忽略) 。
-
JAVA调用WS方式:
- 使用开源jar中的ws client调用远程的webservice服务,如cxf,axis,jaxws,apache soap等;
- 通过idea或eclipse生成客户端;
- 通过post请求调用,需要注意以下几点:
- WebService只采用HTTP POST方式传输数据,不使用GET方式;
- WebService协议主要有SOAP1.1与1.2,两者存在:差异,请求时需要注意HTTP头信息也是不同的:
- SOAP1.1:Content-Type为 text/xml; charset=UTF-8,存在soapAction;
- SOAP1.2:Content-Type为application/soap+xml;charset=UTF-8,不存在soapACtion(有说被action取代,未进行验证);
- 两者的命名空间和发布的WSDL格式也不相同,但不影响调用;
- SOAP1.2的WSDL示例:
-
<binding name="EmployeeServiceImplPortBinding" type="tns:EmployeeServiceImpl">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="findEmployeeById">
<soap12:operation soapAction=""/>
<input><soap12:body use="literal"/></input>
<output><soap12:body use="literal"/></output>
</operation><operation name="create">
<soap12:operation soapAction=""/>
<input><soap12:body use="literal"/></input>
<output><soap12:body use="literal"/></output>
</operation>
</binding>
发表回复