Web Service学习笔记(webservice、soap、wsdl、jws详细分析)
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向公众发布,公告客户端程序关于某个具体的 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 消息的基本结构
- ?>
- <soap:Envelope
- xmlns:soap=
- soap:encodingStyle=>
- <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 元素中,并会被应用到元素的内容及元素的所有子元素上。

- ?>
- <soap:Envelope
- xmlns:soap=
- soap:encodingStyle=>
- ...
- 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",则要求处理此头部的接收者必须认可此元素。
- <? xml version=?>
- <soap:Envelope
- "http://www.w3.org/2001/12/soap-envelope"
- soap:encodingStyle=>
- <soap:Header>
- <m:Trans
- "http://www.jsoso.net/transaction/"
- soap:mustUnderstand=
- //www.w3schools.com/appml/ “ >234</m:Trans>
- </soap:Header>
- ...
- ...
- </soap:Envelope>
- <? xml version=?>
- <soap:Envelope
- "http://www.w3.org/2001/12/soap-envelope"
- soap:encodingStyle=>
- <soap:Body>
- <m:GetPrice xmlns:m=>
- <m:Item>Apples</m:Item>
- </m:GetPrice>
- </soap:Body>
- </soap:Envelope>
上面的例子请求苹果的价格。请注意,上面的 m:GetPrice 和 Item 元素是应用程序专用的元素。它们并不是 SOAP 标准的一部分。而对应的 SOAP 响应应该类似这样:
- ?>
- <soap:Envelope
- xmlns:soap=
- soap:encodingStyle=>
- <soap:Body>
- <m:GetPriceResponse xmlns:m=>
- <m:Price></m:Price>
- </m:GetPriceResponse>
- </soap:Body>
- </soap:Envelope>
SOAP Fault 元素
Fault 元素表示 SOAP的错误消息。它必须是 Body 元素的子元素,且在一条 SOAP 消息中,Fault 元素只能出现一次。Fault 元素拥有下列子元素:
常用的SOAP Fault Codes
HTTP协议中的SOAP 实例
下面的例子中,一个 GetStockPrice 请求被发送到了服务器。此请求有一个 StockName 参数,而在响应中则会返回一个 Price 参数。此功能的命名空间被定义在此地址中: "http://www.jsoso.net/stock"
- SOAP 请求:(注意HTTP的Head属性)
- 1.1
- Host: www.jsoso.net
- Content-Type: application/soap+xml; charset=utf-
- Content-Length: XXX
- <? xml version=?>
- <soap:Envelope
- xmlns:soap=
- soap:encodingStyle=>
- <soap:Body xmlns:m=>
- <m:GetStockPrice>
- <m:StockName>IBM</m:StockName>
- </m:GetStockPrice>
- </soap:Body>
- </soap:Envelope>
- SOAP 响应:(注意HTTP的Head属性)
- 1.1200 OK
- Content-Type: application/soap+xml; charset=utf-
- Content-Length: XXX
- <? xml version=?>
- <soap:Envelope
- xmlns:soap=
- soap:encodingStyle=>
- <soap:Body xmlns:m=>
- <m:GetStockPriceResponse>
- <m:Price></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文档例子来详细说明各标签的作用及关系。
- encoding=?>
- <definitions
- xmlns:soap=
- xmlns:tns=
- xmlns:xsd=
- xmlns=
- targetNamespace=
- name=>
- <types>
- <xsd:schema>
- <xsd:
- namespace=
- schemaLocation=></xsd:>
- </xsd:schema>
- </types>
- <message name=>
- <part name=
type=></part> - </message>
- <message name=>
- <part name=
type=></part> - </message>
- <message name=>
- <part name=
type=></part> - <part name=
type=></part> - </message>
- <message name=>
- <part name=
type=></part> - </message>
- <message name=>
- <part name=
element=></part> - </message>
- <portType name=>
- <operation name=
parameterOrder=> - <input message=></input>
- <output message=></output>
- </operation>
- <operation name=
parameterOrder=> - <input message=></input>
- <output message=></output>
- <fault message=
name=></fault> - </operation>
- </portType>
- <binding name=
type=> - <soap:binding
- transport=
- style=></soap:binding>
- <operation name=>
- <soap:operation soapAction=></soap:operation>
- <input>
- <soap:body use=
- namespace=></soap:body>
- </input>
- <output>
- <soap:body use=
- namespace=></soap:body>
- </output>
- </operation>
- <operation name=>
- <soap:operation soapAction=></soap:operation>
- <input>
- <soap:body use=
- namespace=></soap:body>
- </input>
- <output>
- <soap:body use=
- namespace=></soap:body>
- </output>
- <fault name=>
- <soap:fault name=
use=></soap:fault> - </fault>
- </operation>
- </binding>
- <service name=>
- <port name=
binding=> - <soap:address location=></soap:address>
- </port>
- </service>
- </definitions>
由于上面的事例XML较长,我们将其逐段分解讲解
WSDL文档的根元素:<definitions>
- <definitions
- xmlns:soap=
- xmlns:tns=
- xmlns:xsd=
- xmlns=
- targetNamespace=
- name=>
- ……
- ……
- </definitions>
<definitions>
定义了文档中用到的各个xml元素的namespace缩写,也界定了本文档自己的
targetNamespace="http://www.jsoso.com/wstest",这意味着其它的XML要引用当前XML中的元素时,要声
明这个namespace。注意xmlns:tns="http://www.jsoso.com/wstest"这个声明,它标示了使用tns这个前缀
指向自身的命名空间。引用WSDL文档数据类型定义元素:<types>- <types>
- <xsd:schema>
- <xsd:
- namespace=
- schemaLocation=></xsd:>
- </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 >
- >
- <part name=
type=></part> - </message>
- <message name=>
- <part name=
type=></part> - </message>
- <message name=>
- <part name=
type=></part> - <part name=
type=></part> - </message>
- <message name=>
- <part name=
type=></part> - </message>
- <message name=>
- <part name=
element=></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 >
view plain- <portType name=>
- <operation name=
parameterOrder=> - ></input>
- <output message=></output>
- </operation>
- <operation name=
parameterOrder=> - ></input>
- <output message=></output>
- name=></fault>
- </operation>
- </portType>
在<operation>
元素中,name属性表示服务方法名,parameterOrder属性表示方法的参数顺序,使用空格符分割多个参数,
如:“parameterOrder="person
arg1”。<operation>元素的子标签<input>表示输入参数说明,它引用<message>标签中的输入参
数。<output>表示输出参数说明,它引用<message>标签中的输出参数。<fault>标签在Java方法中的特别
用来表示异常(其它语言有对应的错误处理机制),它引用<message>标签中的错误参数。- <binding name=
type=> - <soap:binding
- style=></soap:binding>
- >
- <soap:operation soapAction=></soap:operation>
- <input>
- <soap:body use=
- ></soap:body>
- </input>
- <output>
- <soap:body use=
- ></soap:body>
- </output>
- </operation>
- <operation name=>
- ></soap:operation>
- <input>
- namespace=></soap:body>
- </input>
- <output>
- namespace=></soap:body>
- </output>
- <fault name=>
- use=></soap:fault>
- </fault>
- </operation>
- </binding>
首
先<binding>标签使用<soap:binding>的transport和style属性定义了Web
Service的通讯协议HTTP和SOAP的请求风格RPC。其次<operation>子标签将portType中定义的
operation同SOAP的请求绑定,定义了操作名称soapAction,输出输入参数和异常的编码方式及命名空间。
- <service name=>
- <port name=
binding=> - ></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类代码
- package
- import
import
import
import
import
import
import
/ - * 提供WebService服务的类
- */
- @WebService"Example""http://www.jsoso.com/wstest""Example")
- (style=SOAPBinding.Style.RPC)
- publicclass Example {
- ArrayList<Person> persons =
ArrayList<Person>();; - *
- * 返回一个字符串
- * @param userName
- * @return
- (operationName=,action=,exclude=)
- (name=)
- String sayHello((name=)String
userName) { - + userName;
- }
- * web services 方法的返回值与参数的类型不能为接口
- * @param person
- * @return
- * @throws HelloException
- (operationName=,
action=) - (partName=)
- Person[] sayHello((partName=,
mode=Mode.IN)Person person, - String userName)
HelloException { - (person ==
|| person.getName() ==
) { - HelloException();
- }
- System.out.println(person.getName() +
+ userName +
+ person.getAge() +
); - persons.add(person);
- persons.toArray(
Person[]); - }
- }
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命令说明
- package
- import
import
import
import
import - /**
- */
- StartServer {
- * @param args
- main(String[] args) {
- * 生成Example 服务实例
- Example serverBean =
Example(); - * 发布Web Service到http://localhost:8080/hello地址
- Endpoint endpoint =
- Endpoint.publish(,
serverBean); - Binding binding = endpoint.getBinding();
- * 设置一个SOAP协议处理栈
- * 这里就简单得打印SOAP的消息文本
- */
- List<Handler> handlerChain =
LinkedList<Handler>(); - TraceHandler());
- binding.setHandlerChain(handlerChain);
- );
- }
- }
在控制台运行这个类,就可以使用URL :http://localhost:8080/hello?wsdl 浏览到上文所描述的WSDL的全文了。这说明您的第一个Web Service应用发布成功!
构建Web Service客户端
使用JavaSE6.0构建Web Service的客户端是一件相当简单的事。这里我们要使用到JDK中的另一个命令行工具wsimport。在控制台下输入以下命令:
- package
- import
- publicclass RunClient {
- * @param args
- */
- main(String[] args) {
- Example_Service service =
Example_Service(); - Example server = (Example) service.getExamplePort();
- {
- + server.toSayHello());
- Person person =
Person(); - );
- person.setAge();
- server.sayHello(person,
); - person =
Person(); - );
- person.setAge();
- PersonArray list = server.sayHello(person,
); - System.out.println();
- (Person p : list.getItem()) {
- System.out.println(p.getName() +
+ p.getAge()); - }
- }
(HelloException_Exception e) { - e.printStackTrace();
- }
- }
- }
附录:wsgen与wsimport命令说明
- -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
- -d 生成客户端执行类的class文件的存放目录
- -s 生成客户端执行类的源文件的存放目录
- -p 定义生成类的包名
命令范例:wsimport -d ./bin -s ./src -p org.jsoso.jws.client.ref http://localhost:8080/hello?wsdl--转自 http://blog.csdn.net/lfy9608110935/article/details/8302306
Web Service学习笔记(webservice、soap、wsdl、jws详细分析)的更多相关文章
- Web Service学习笔记:动态调用WebService
原文:Web Service学习笔记:动态调用WebService 多数时候我们通过 "添加 Web 引用..." 创建客户端代理类的方式调用WebService,但在某些情况下我 ...
- Web Service学习笔记
Web Service概述 Web Service的定义 W3C组织对其的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计.Web Service服务通常被定义为一组模块化的API ...
- Web Service学习笔记(webservice、soap、wsdl、jws详细分析) (转)
Web Service概述 Web Service的定义 W3C组织对其的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计.Web Service服务通常被定义为一组模块化的API ...
- Web Service学习之八:Soap消息详解
一.区别概念 WSDL是网络服务描述语言,是XML文档:它包含一系列描述某个web service的定义或者说是规则.尤其是定义了传输Sope消息的结构 Soap:简单对象访问协议,是交换数据的一种协 ...
- Java Web Service 学习笔记
一.服务端 1. 创建Java工程 2. 创建接口HostipalServiceInterface package ws_server; import javax.jws.WebMethod; imp ...
- Web Service进阶(四)WebService注解
@WebService 1.serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service.缺省值为 Java 类的简单名称 + Service.(字符 ...
- Web Service学习之一:Web Service原理
一.定义 Web Service 不是框架也不是技术 而是解决远程调用.跨平台调用.跨语言调用问题的一种规范. 二.应用1.同一个公司新.旧系统的整合:比如CRM系统与OA.客服系统相互调用2.不同公 ...
- ASP.NET MVC Web API 学习笔记---第一个Web API程序
http://www.cnblogs.com/qingyuan/archive/2012/10/12/2720824.html GetListAll /api/Contact GetListBySex ...
- 【前端】移动端Web开发学习笔记【2】 & flex布局
上一篇:移动端Web开发学习笔记[1] meta标签 width设置的是layout viewport 的宽度 initial-scale=1.0 自带 width=device-width 最佳实践 ...
随机推荐
- iOS 隔离导航控制器
题外话:最近这两个月一直很闲,项目上基本没有啥大的需求.对于程序员来说,如果没有需求其实是一件很难受的事情,之前好多次在项目中没事找事,该优化的优化,该整理的整理.可能好多程序员都遇到过与我类似的情况 ...
- ReactiveCocoa入门教程——第一部分(转)
作为一个iOS开发者,你写的每一行代码几乎都是在响应某个事件,例如按钮的点击,收到网络消息,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation).但是这些事件都用不同的方式来处理 ...
- Linq 中的TakeWhile 和 SkipWhile
这两个概念容易搞混 理解了一番后 在这里写下便于记忆 SkipWhile 可以理解为如果条件满足 就一直跳过 知道不满足后 就取剩下的所有元素(后面的不会再判断) TakeWhile 可以理解为 ...
- 二维树状数组——SuperBrother打鼹鼠(Vijos1512)
树状数组(BIT)是一个查询和修改复杂度都为log(n)的数据结构,主要用于查询任意两位之间的所有元素之和,其编程简单,很容易被实现.而且可以很容易地扩展到二维.让我们来看一道很裸的二维树状数组题: ...
- leetcode Permutations II 无重全排列
作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4051169.html 题目链接:leetcode Permutations II 无重全排 ...
- Mac下修改默认的Java版本
今天在安装Elicpse IDE的时候,发现提示安装的Java版本不支持,于是在官方去下载了Jre最新版本并安装,在安装完过后再次打开Elicpse发现提示还是不正确,如果用Google查询到一些资料 ...
- Linux C 程序 基础语法(1)
1.Linux 下第一支C程序,控制台打印一句话. vi first.c //linux新建文件 #include<stdio.h> int main() { printf("w ...
- Keil 4 与Proteus 7.8联调
实验环境: windows 8.1 pro with Keil 4 and Proteus 7.8 both cracked. 步骤: 下载联调工具Vdmagdi,安装. keil下Option/De ...
- 把DataSet转换成JSON
/// <summary> /// dataTable转换成Json格式 /// </summary> /// <param name="dt"> ...
- CSS3制作hover下划线动画
1.前几天看到Hexo的next主题标题hover效果很炫,自己尝试写了一个,另一个是next的实现,照例先上图 2.实现小黑科技 <div> <a href="javas ...