Web Services是由企业发布的完成其特定商务需求的在线应用服务,其他公司或应用软件能够通过Internet来访问并使用这项在线服务。
用简单点的话说,就是系统对外的接口!
它是一种构建应用程序的普遍模型,可以在任何支持网络通信的操作系统中实施运行;它是一种新的web webservice应用程序分支,是自包含、自描述、模块化的应用,可以发布、定位、通过web调用。WebService是一个应用组件,它逻辑性的为其他应用程序提供数据与服务.各应用程序通过网络协议和规定的一些标准数据格式(Http,XML,Soap)来访问WebService,通过WebService内部执行得到所需结果.Web Service可以执行从简单的请求到复杂商务处理的任何功能。一旦部署以后,其他WebService应用程序可以发现并调用它部署的服务。
关键的技术和规则
技术和规则
在构建和使用Web Service时,主要用到以下几个关键的技术和规则:
1.XML:描述数据的标准方法.
2.SOAP:简单对象访问协议.
3.WSDL:Web服务描述语言.
4.UDDI(Universal Description, Discovery and Integration):通用描述、发现与集成,它是一种独立于平台的,基于XML语言的用于在互联网上描述商务的协议。
相关
实际上,WebService的主要目标是跨平台的可互操作性。为了达到这一目标,WebService完全基于XML(可扩展标记语言)、XSD(XMLSchema)等独立于平台、独立于软件供应商的标准,是创建可互操作的、分布式应用程序的新平台。由此可以看出,在以下三种情况下,使用WebService会带来极大的好处。
长项一:跨防火墙的通信
如果应用程序有成千上万的用户,而且分布在世界各地,那么客户端和服务器之间的通信将是一个棘手的问题。因为客户端和服务器之间通常会有防火墙或者代理服务器。在这种情况下,使用DCOM就不是那么简单,通常也不便于把客户端程序发布到数量如此庞大的每一个用户手中。传统的做法是,选择用浏览器作为客户端,写下一大堆ASP页面,把应用程序的中间层暴露给最终用户。这样做的结果是开发难度大,程序很难维护。
举个例子,在应用程序里加入一个新页面,必须先建立好用户界面(Web页面),并在这个页面后面,包含相应商业逻辑的中间层组件,还要再建立至少一个ASP页面,用来接受用户输入的信息,调用中间层组件,把结果格式化为HTML形式,最后还要把“结果页”送回浏览器。要是客户端代码不再如此依赖于HTML表单,客户端的编程就简单多了。
如果中间层组件换成WebService的话,就可以从用户界面直接调用中间层组件,从而省掉建立ASP页面的那一步。要调用WebService,可以直接使用MicrosoftSOAPToolkit或.NET这样的SOAP客户端,也可以使用自己开发的SOAP客户端,然后把它和应用程序连接起来。不仅缩短了开发周期,还减少了代码复杂度,并能够增强应用程序的可维护性。同时,应用程序也不再需要在每次调用中间层组件时,都跳转到相应的“结果页”。
从经验来看,在一个用户界面和中间层有较多交互的应用程序中,使用WebService这种结构,可以节省花在用户界面编程上20%的开发时间。另外,这样一个由WebService组成的中间层,完全可以在应用程序集成或其它场合下重用。最后,通过WebService把应用程序的逻辑和数据“暴露”出来,还可以让其它平台上的客户重用这些应用程序。
长项二:应用程序集成
企业级的应用程序开发者都知道,企业里经常都要把用不同语言写成的、在不同平台上运行的各种程序集成起来,而这种集成将花费很大的开发力量。应用程序经常需要从运行在IBM主机上的程序中获取数据;或者把数据发送到主机或UNIX应用程序中去。即使在同一个平台上,不同软件厂商生产的各种软件也常常需要集成起来。通过WebService,应用程序可以用标准的方法把功能和数据“暴露”出来,供其它应用程序使用。
例如,有一个订单登录程序,用于登录从客户来的新订单,包括客户信息、发货地址、数量、价格和付款方式等内容;还有一个订单执行程序,用于实际货物发送的管理。这两个程序来自不同软件厂商。一份新订单进来之后,订单登录程序需要通知订单执行程序发送货物。通过在订单执行程序上面增加一层WebService,订单执行程序可以把“AddOrder”函数“暴露”出来。这样,每当有新订单到来时,订单登录程序就可以调用这个函数来发送货物了。
长项三:B2B的集成
用WebService集成应用程序,可以使公司内部的商务处理更加自动化。但当交易跨越供应商和客户、突破公司的界限时会怎么样呢?跨公司的商务交易集成通常叫做B2B集成。
WebService是B2B集成成功的关键。通过WebService,公司可以把关键的商务应用“暴露”给指定的供应商和客户。例如,把电子下单系统和电子发票系统“暴露”出来,客户就可以以电子的方式发送订单,供应商则可以以电子的方式发送原料采购发票。当然,这并不是一个新的概念,EDI(电子文档交换)早就是这样了。但是,WebService的实现要比EDI简单得多,而且WebService运行在Internet上,在世界任何地方都可轻易实现,其运行成本就相对较低。不过,WebService并不像EDI那样,是文档交换或B2B集成的完整解决方案。WebService只是B2B集成的一个关键部分,还需要许多其它的部分才能实现集成。
用WebService来实现B2B集成的最大好处在于可以轻易实现互操作性。只要把商务逻辑“暴露”出来,成为WebService,就可以让任何指定的合作伙伴调用这些商务逻辑,而不管他们的系统在什么平台上运行,使用什么开发语言。这样就大大减少了花在B2B集成上的时间和成本,让许多原本无法承受EDI的中小企业也能实现B2B集成。
长项四:软件和数据重用
软件重用是一个很大的主题,重用的形式很多,重用的程度有大有小。最基本的形式是源代码模块或者类一级的重用,另一种形式是二进制形式的组件重用。
图2用WebService集成各种应用中的功能,为用户提供一个统一的界面
当前,像表格控件或用户界面控件这样的可重用软件组件,在市场上都占有很大的份额。但这类软件的重用有一个很大的限制,就是重用仅限于代码,数据不能重用。原因在于,发布组件甚至源代码都比较容易,但要发布数据就没那么容易,除非是不会经常变化的静态数据。
WebService在允许重用代码的同时,可以重用代码背后的数据。使用WebService,再也不必像以前那样,要先从第三方购买、安装软件组件,再从应用程序中调用这些组件;只需要直接调用远端的WebService就可以了。举个例子,要在应用程序中确认用户输入的地址,只需把这个地址直接发送给相应的WebService,这个WebService就会帮你查阅街道地址、城市、省区和邮政编码等信息,确认这个地址是否在相应的邮政编码区域。WebService的提供商可以按时间或使用次数来对这项服务进行收费。这样的服务要通过组件重用来实现是不可能的,那样的话你必须下载并安装好包含街道地址、城市、省区和邮政编码等信息的数据库,而且这个数据库还是不能实时更新的。
另一种软件重用的情况是,把好几个应用程序的功能集成起来。例如,要建立一个局域网上的门户站点应用,让用户既可以查询联邦快递包裹,查看股市行情,又可以管理自己的日程安排,还可以在线购买电影票。现在Web上有很多应用程序供应商,都在其应用中实现了这些功能。一旦他们把这些功能都通过WebService“暴露”出来,就可以非常容易地把所有这些功能都集成到你的门户站点中,为用户提供一个统一的、友好的界面。
将来,许多应用程序都会利用WebService,把当前基于组件的应用程序结构扩展为组件/WebService的混合结构,可以在应用程序中使用第三方的WebService提供的功能,也可以把自己的应用程序功能通过WebService提供给别人。两种情况下,都可以重用代码和代码背后的数据。
从以上论述可以看出,WebService在通过Web进行互操作或远程调用的时候是最有用的。不过,也有一些情况,WebService根本不能带来任何好处。
短处一:单机应用程序
目前,企业和个人还使用着很多桌面应用程序。其中一些只需要与本机上的其它程序通信。在这种情况下,最好就不要用WebService,只要用本地的API就可以了。COM非常适合于在这种情况下工作,因为它既小又快。运行在同一台服务器上的服务器软件也是这样。最好直接用COM或其它本地的API来进行应用程序间的调用。当然WebService也能用在这些场合,但那样不仅消耗太大,而且不会带来任何好处。
短处二:局域网的同构应用程序
在许多应用中,所有的程序都是用VB或VC开发的,都在Windows平台下使用COM,都运行在同一个局域网上。例如,有两个服务器应用程序需要相互通信,或者有一个Win32或WinForm的客户程序要连接局域网上另一个服务器的程序。在这些程序里,使用DCOM会比SOAP/HTTP有效得多。与此相类似,如果一个.NET程序要连接到局域网上的另一个.NET程序,应该使用.NETremoting。有趣的是,在.NETremoting中,也可以指定使用SOAP/HTTP来进行WebService调用。不过最好还是直接通过TCP进行RPC调用,那样会有效得多。
总之,只要从应用程序结构的角度看,有别的方法比WebService更有效、更可行,那就不要用WebService
RPC
RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息的到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。
目前,有多种 RPC 模式和执行。最初由 Sun 公司提出。IETF ONC 宪章重新修订了 Sun 版本,使得 ONC RPC 协议成为 IETF 标准协议。现在使用最普遍的模式和执行是开放式软件基础的分布式计算环境(DCE)。
工作原理
运行时,一次客户机对服务器的RPC调用,其内部操作大致有如下十步:
1.调用客户端句柄;执行传送参数
2.调用本地系统内核发送网络消息
3.消息传送到远程主机
4.服务器句柄得到消息并取得参数
5.执行远程过程
6.执行的过程将结果返回服务器句柄
7.服务器句柄返回结果,调用远程系统内核
8.消息传回本地主机
9.客户句柄由内核接收消息
10.客户接收句柄返回的数据
一、 Web Service概述
1.动机
1) 今天,万维网的主要用途是交互式的访问文档和应用程序;
2) 大多数时候,这些访问是通过浏览器、音频播放器或其它交互式的前-后端系统;
3) W3C: “假如万维网支持应用程序间的交互,Web在能力及应用范围上能得到引人注目的增长”
2.理念:构建应用程序的时候通过发现以及调用网络上现在的应用去实现某些功能;
二、 技术基础
Web services = XML + HTTP
XML:通用数据描述语言;
HTTP:被浏览器和Web servers广泛支持的一种传输协议;
三、 What is web service
1) 在互联网上,通过基于标准的互联网协议(例如HTTP、SMTP)访问的一段业务逻辑。或者叫Web服务组件。
2) 承诺在一个分布式环境中,不同的平台的,不同语言的应用和应用组件之间能够互操作。
3) Web service是自我包含、自我描述、模块化的程序,它能发布、定位以及通过Web调用;
4) 一旦一个web service被布署,其它应用程序即可发现和调用这个服务。
5) 技术上来说,Web Service也是一种远程方法调用
1. 自我包含
1) 在客户端,无须附加的软件;
2) 只须XML和HTTP协议客户端支持即可开始;
3) 在服务器端,仅需要一个Web服务器和servlet引擎;
4) 对于Web service使一个既存的系统重新可用而无须写一行代码是可行的;
2. 自我描述
1) 无论是客户端还是服务器端除了格式和请求内容以及响应信息外无须关注任何事情;
2) 信息格式定义通过消息传输;
3) 无额外的无素贮藏库或代码产生工具需要;
3. 模块化的程序
1) Web services标准框架提供了一个组件模型;
2) Web services是一种技术,用于部署和提供Web上的商业功能访问;
3) J2EE、CORBA和其它标准是实现这些Web services的技术;
4. 发布、定位以及通过Web调用所需的一些额外的标准:
SOAP:Simple Object Access Protocol
也可理解为 service-oriented architecture protocol,基于RPC和通讯协议的XML。
WSDL:Web Service Description Language, 一个描述性的接口和协议绑定语言。
UDDI:Universal Description, Discovery and Integration,一种注册机制,用于查找Web service描述。
5. 语言无关和互操作性
1) 客户端和服务器端能在不同环境下被实现;
2) 既存的环境为了实现 Web service 无须进行改动;
3) 但是在现在,我们假设Java是Web service客户端和服务器端的实现语言;
6. 基于开放的标准
1) XML和HTTP是Web services的技术基础;
2) 很大部分Web service技术使用开源项目构建;
3) 因此,供应商无关以及互操作性是这时的现实目标。
7. Web services是动态的
通过使用Web Services,动态电子商务变得很现实。
因为,使用UDDI和WSDL,Web service描述和发现可以自动进行。
8. Web services是组合的、简单的
Web services能组合成更复杂的Web services,无论是使用工作流技术或是调用更底层的Web services。
9. 基于成熟技术构建
1) XML + HTML
2) 和其它分布式计算框架相比,有很多相同点也有很多基础性的不同。
例如,传输协议基于文本而非二进制。
四、 Web Service可以解决的问题
1) 异构应用系统之间的集成
异构程序定位:使用URI标志软件程序
传输协议:HTTP、FTP、SMTP等公共协议
数据格式:XML
接口描述:XML
2) 不同公司之间的系统集成
公共的互联网协议HTTP、FTP、SMTP
3) 需要集成的系统之间有防火墙
使用公共的网络协议HTTP、FTP、SMTP
传统的做法是,选择用浏览器作为客户端(大量跳转页面和控制程序)
新的做法(Ajax,Web Service)
区别于web应用
web application: 人(浏览器)与应用的交互
web service: 应用与应用的交互
4) 代码重用的问题
使用HTTP等服务,无需下载或安装服务程序的代码
Web service的好处.
专注于核心商业逻辑,使用Web service应用于非核心商业逻辑从而以一个很低的成本快速发布新的IT解决方案;
通过使用Web service封装以前软件系统到当前系统中可保护既有投资;
以最少的费用将用户和伙伴的商业系统结合到一块;
1.好处——促进协同工作能力
1) service provider和service requester之间的沟通设计为平台和语言无关;
2) 这个交互需要一份WSDL文档,这份文档定义了接口以及描述了相应的服务,连同网络协议在一起(通常是HTTP);
2.好处——
1) 当service requester 使用service broker寻找service provider,这种发现是自动发生的。
2) 一旦requester和provider相互找到,provider的WSDL文档用于将requester和服务绑定到一块。
3) 这意味着requester、provider和broker一块创建的系统是自我设置、自我适应以及强健的。
3.好处——通过封装降低了复杂性
1) service requester和provider只关心必要的接口;
2) service requester并不关心service provider如何实现服务;
3) 这些细节都在requester和provider方封装好,这种封装对于降低复杂性非常重要;
4.好处——给遗留系统以新的生机
1) 对于一个遗留系统、产生一个SOAP包装,然后产生一个WSDL文档将应用程序作为一个web service;
2) 这意味着遗留系统能用于新的方面;
3) 此外,与遗留系统相联系的基础设施能封装成一系列的服务;
五、 Web Service的特点
1) 基于XML,异构应用集成容易
2) 基于消息的(HTTP和SOAP消息)
松散耦合的(调用服务代码时无需下载和安装)
编程语言独立的(使用HTTP等协议,通信更加简单,使用XML的数据格式,程序更易识别)
提供异步和同步的能力(异步功能提高访问性能)
能动态装配和集成(可以使用更多服务)
通过互联网进行访问
3) 基于工业标准的(W3C的 WSDL, SOAP, UDDI)
六、 Web Service角色
1) service provider 创建web service并发布它的接口和访问信息到服务登记处;
2) service broker (也称为service registry)
有责任使Web service接口和实现访问信息对任何潜在的service requestor可用;
3) service requestor
为了使用Web service,使用各种查找操作在broker登记处定义入口以及绑定到service provider。
Service provider子角色
1) WSDL规范由二部分组成:服务接口和服务实现;
2) 服务接口提供者和服务实现者是service provider的子角色;
3) 二个角色可以,但非必须被同一个事务承担;
七、 Web services架构体系
1) 通过 service provider 部署到Web上;
2) 提供的功能使用WSDL描述;
3) service broker 帮助 service provider 和 service requestor 能互相找到对方;
4) service requestor 使用 UDDI API从service broker 处寻找它所需要的服务;
5) 当service broker 返回查找的结果,service requestor 可使用这些结果绑定到一个特定服务;
6) Web service 描述由service provider创建和发布;
7) 由service broker 组织和查找;
由service requester 定位和调用;
八、 Web services组件
前面显示了Web service中用到的三种主要的组件:
1) Service provider: 提供服务并使这些服务可用;
2) Service broker: 为service provider和service requestor配对;
3) Service requester: 使用service broker查找Web service,然后调用这些服务去创建应用程序;
九、 Web service操作
1) 发布/取消发布
发布服务至登记处;
移除这些登记的条款
service provider联系
service broker发布/取消服务
2) 查找操作由service requestor和service broker共同完成:
service requestor描述他们查找的服务种类;
service broker递交最匹配的请求结果。
3) 绑定发生在service requestor和service provider间
他们会协议好以便requestor能访问和调用service provider提供的服务。
六、 SOA架构(Service-Oriented Architecture)
面向服务的体系结构(Service-Oriented Architecture,SOA)是一个分布式组件模型,用来将现有的应用集成
1) 把组件都看做网络服务
将现有的应用、组件、业务逻辑发布为服务
对服务的要求:与平台无关(硬件,操作系统,语言);基于 internet 的服务,采用公共的网络协议
2) SOA系统原型的一个典型例子是通用对象请求代理体系结构
(Common Object Request Broker Architecture,CORBA)
3) 现在的SOA以XML为基础的,也就是Web Service
Web服务是技术规范,而SOA是设计原则,Web服务是实现SOA的方式之一
part2. Web Service关键技术 ---- SOAP协议
-----------------------------------------------------
一、 What is SOAP(Simple Object Access Protocol) ——简单对象访问协议
1) SOAP是一个网络中立的、轻量级的协议,用于交换两个远端应用程序的信息;
2) SOAP是一个基于XML的协议,由三部分组成:
envelope: 定义了一个框架,该框架用于描述信息内容以及处理说明;
一系列的编码规则:用于表现系统定义的数据类型实例;
一个协定:用于表现远端处理调用和响应
3) SOAP使用XML技术定义了一个可扩展的消息框架,底层可以通过各种协议进行数据交换(主要HTTP、FTP、SMTP)
4) SOAP定义为与特定的编程模型和实现语句无关(只要它能处理XML信息)
是一个与协议无关的传输器, 用和许多协议共同使用(这里我们描述如何和HTTP一起使用SOAP);
5) SOAP是分布式环境下交换结构化信息的规范;
6) SOAP代表了SOA中三种主要行动者
(service provider、service requestor、service broker)间主要的沟通方式;
7) 它的设计目标是应该简单以及可扩展;
1.SOAP VS JRMP、IIOP
SOAP:传递基于XML的文本数据(基于文本的协议易识别和理解,例如HTTP)
JRMP、IIOP:传递字节数据
2.SOAP1.2 是 W3C 推荐标准
W3C(万维网联盟)组织是一个制定网络标准的非赢利组织,像 HTML、XHTML、CSS、XML 的标准都是由W3C来定制
3.defines1:
SOPA信封 定义消息结构:一个信封内包含一个消息头和一个消息体
协议绑定框架 定义了一组规则把SOAP消息绑定到其他的底层协议
参看:http://www.w3.org/TR/soap12-part1/
4.defines2:
Data modle for SOAP
定义SOAP消息中的XML数据,和具体编程实现的数据类型的对应关系(如:XML转换成Java数据类型)
Binding to Http
定义了如何将SOPA消息绑定到HTTP协议
参看:http://www.w3.org/TR/soap12-part2/
5.需要知道SOAP的细节吗?
需要:了解细节有助于你构建更好的应用(如提高效率和性能:这要求对XML和底层通信协议的了解)
无需:一般情况你应该使用一些高层的API(如JAX-WS)构建应用,SOAP的实现细节对开发者透明
二、 SOAP信封
1) 一条 SOAP 消息就是一个普通的 XML 文档,包含下列元素:
必需的 Envelope 元素,可把此 XML 文档标识为一条 SOAP 消息
可选的 Header 元素,包含头部信息
必需的 Body 元素,包含所有的调用和响应信息
包含可选的 Fault 元素,提供有关在处理此消息所发生错误的信息
2) 所有以上的元素均被声明于针对 SOAP 封装的默认命名空间中:
http://www.w3.org/2001/12/soap-envelope
以及针对 SOAP 编码和数据类型的encodingStyle属性:
http://www.w3.org/2001/12/soap-encoding
1. SOAP消息 语法规则:
必须用 XML 来编码
必须使用 SOAP Envelope 命名空间
必须使用 SOAP Encoding 命名空间
不能包含 DTD 引用
不能包含 XML 处理指令
2. 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>
三、 信息格式
1) 一个SOAP信息是一个envelope,该envelope包含零至多个header以及一个body元素;
2) 这个envelope是XML文档的根元素;
3) envelope为以下内容提供了了一个容器:
控制信息; 消息的收件人; 消息本身;
4) header包含控制信息,例如服务属性;
5) body包含消息标签以及它的参数;
四、 编码规则
1) 编码规则定义了一系列机制用于交换程序自定义数据类型的实例;
2) SOAP基于XML schema描述符(XSD)定义了一个与编程语言无关的数据类型schema,
根据这个模型为所有定义的数据类型加上这个编码规则;
五、 RPC代表
1) RPC代表是适用于表现远端过程调用以及相关响应消息的一个协定;
2) 作为远端方法中的参数,我们通常使用相关的简单数据结构。当然,也可以传输更复杂的数据。
3) 这个协定仅被SOAP执行,并非SOAP标准的一部分。
4) 这个转换的使用是可选的,假如没有使用RPC转换,会话是纯粹面向消息的;
六、 URN
1) URN代表统一资源名称(unified resource name);
2) URN唯一地识别给客户端的服务;
3) 在单个SOAP服务器的所有部署的服务中,它必须是唯一的,通过一个合适的网络地址确定;
4) 一个URN被编码为一个通用资源标识符(URI);
5) 我们通过使用格式:urn:UniqueServiceID
七、 SOAP envelope
1) envelope是表示为下列结构的XML文档的根元素: [message payload]
2) 一个SOAP消息有零至多个header和一个body;
3) SOAP envelope同样定义了结构化信息的名域空间;
4) 整个SOAP消息(header和body)都封装在envelope内;
5) 注意消息body使用一个服务特定的名域空间,类似于urn:NextMessage;
6) 这个名域空间不同于SOAP-ENV, 这个名域空间被envelope所使用,由SOAP规范所定义;
7) 因此在创建消息体的时候,这个应用程序能使用它自己的域特定词汇;
八、 SOAP Header
1) header是envelope中可选的元素,假如出现的话,这个元素必须是SOAP envelope中第一个出现的子元素;
2) 所有header元素的子元素称为header条款;
3) header也能装载认证数据,数字签名,编码信息以及传输设置;
4) header也能装载客户端或项目-指定控制以及协议的扩展;header的定义并不取决于body。
1.可选的,用于扩展SOAP消息,例如:
调用的上下文 目前的应用模式基本上停留在远程过程/对象的调用上,
基于多次协调调用或者遵循上下文的调用模式尚很少使用,这其实是受简单的SOAP消息的制约
安全认证 保存用户标识及密码信息或者其他鉴定证书
事务控制 利用SOAP Header条目进行事务控制
其他高级语义功能
2.SOAP Header由一些Header条目组成
<env:Header xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<auth:authentication xmlns:auth="http://example.org/authentication"
env:role="authentication:signin_service" env:mustUnderstand="1" relay="" >
<auth:userID>testuserid</auth:userID>
<auth:password></auth:password>
<auth:redirection>http://example.com/service/</auth:redirection>
</auth:authentication>
</env:Header>
3.role属性:(next|none|ultimateReceiver)
指定这个条目必须被哪种角色处理
4.mustUnderstand:(true|false)
处理节点必须被处理,如果处理节点理解不了,必须返回一个SOAP Fault. (此时relay无意义)
5.relay:(true|false)
处理节点理解的条目,将会保留,并转发给下一个SOAP节点处理
九、 SOAP Body
必须的,包含传递给最终的节点的实际信息
1) SOAP body元素提供了一种机制用以交换信息;
2) body元素是SOAP envelope元素的下一级元素;
3) 假如存在header元素,body元素应该紧跟header元素之后。否则它应该紧跟envelope元素之后。
4) 所有body元素的下一级子元素称为body的条目,这些条目各自独立;
5) 在大多数简单的情况下,基本SOAP消息的body组成:
一个消息名称;
一个服务实例的引用;
6) 在Apache SOAP中,一个服务实例为它的URN所标识。这个引用编码为名域空间的属性。
7) 一至多个参数里装载着值和可选的类型引用;
典型的body元素使用包括用相应的参数调用RPC、返回结果及错误报告;
9) 消息可以包括几乎任何XML结构,除了DTD及处理说明。
<soap:Body xmlns:m="http://www.example.org/stock">
<m:GetStockPrice>
<m:StockName>IBM</m:StockName>
</m:GetStockPrice>
</soap:Body>
十、 SOAP Fault
可选的,元素用于存留 SOAP 消息的错误和状态信息。必须出现在SOAP Body中
<soap:Body xmlns:m="http://www.example.org/stock">
<soap:Fault>
<faultcode>MustUnderstand</faultcode>
<faultstring>
一个或多个必须的soap头未被理解
</faultstring>
</soap:Fault
</soap:Body>
<faultcode> 供识别故障的代码
<faultstring> 可供人阅读的有关故障的说明
<faultactor> 有关是谁引发故障的信息
<detail> 存留涉及 Body 元素的应用程序专用错误信息
faultcode的值:
VersionMismatch: SOAP Envelope 元素的无效命名空间被发现
MustUnderstand: Header 元素的一个直接子元素(带有设置为 "1" 的 mustUnderstand 属性)无法被理解。
Client: 消息被不正确地构成,或包含了不正确的信息。
Server: 服务器有问题,因此无法处理进行下去。
十一、SOAP HTTP Binding
HTTP + XML = SOAP
SOAP 请求可能是 HTTP POST 或 HTTP GET 请求。
HTTP POST 请求规定至少两个 HTTP 头:Content-Type 和 Content-Length。
1. SOAP请求
POST /soapsamples/servlet/rpcrouter HTTP/1.0
Host: localhost
Content-Type:
text/xml:charset=utf-8
Content-Length: 460
SOAPAction: "" IBM
1) SOAP请求表明getQuote方法从以下地址调用:http://localhost/soapsamples/servlet/rpcrouter
2) SOAP协议并没有指定如何处理请求,服务提供者可运行一个CGI脚本,调用servlet或执行其它产生对应响应的处理;
3) 响应包含于一个XML文档格式的表单内,该表单包含了处理的结果,在我们这个范例中是IBM的股价;
2. SOAP响应
HTTP/1.1 200 OK
Server: IBM HTTP SERVER/1.3.19 Apache/1.3.20 (Win32)
Content-Length: 479
Connection: close
Content-Type: text/xml; charset = utf-8
Content-Language: en 108.53
1) 结果所位于的元素名称在请求方法名后加后缀“Response”,
例请求方法名为:getQuote, 响应方法名为:getQuoteResponse。
3. Http响应状态
1) 1XX——information
2) 2XX——success
3) 3XX——redirection
4) 4XX——client error
5) 5XX——sever error
part3. Web Service关键技术 --- WSDL
-----------------------------------------------------
1. What is WSDL(Web Service Description Language) ——Web服务描述语言
WSDL既是机器可阅读的,又是人可阅读的,这将是一个很大的好处。
一些最新的开发工具既能根据你的Web service生成WSDL文档,又能导入WSDL文档,生成调用相应Web service的代码
1) WSDL是以XML为基础的接口定义语言,它提供了一种分类和描述Web service的方式;
描述Web服务 和说明如何与Web服务通信的XML语言
2) WSDL定义了 Web service的接口,包括:
a. 操作方式(单向、通知、请求-响应);
b. 定义了Web service的消息;
c. 数据类型(XML schema);
Web service访问协议(SOAP over HTTP);
Web service联系的终点(Web service URL);
符合要求的服务端应用程序必须支持这些接口,客户端用户能从这份文档中得知如何访问一个服务。
2. WSDL文档结构
<definitions>
<types> definition of types........ </types>
<message> definition of a message.... </message>
<portType> definition of a port....... </portType> //代表interface:接口
<binding> definition of a binding.... </binding>
<service> service of a binding.... </service>
</definitions>
总体上可以分为两大部分:
1)抽象定义
定义要交换的数据格式(数据类型/参数/返回值/方法声明)
types 定义数据类型,使用XML Schema作为类型系统
messages 定义要交换的数据,数据类型是types中定义的数据类型。对应方法的参数
包括若干个part,每个part 都对应types中定义一个元素。对应方法的一个参数
porttype(接口) 包含若干 operation;定义一个服务,对应Java的接口
包含一些operation,operation对应Java的方法
operation 都包含一个input 和 output 消息(messages中定义)
2)具体描述
定义要采用的互操作协议(soap)、传输协议(http,ftp,smtp 等)、声明服务的访问地址
binding 针对 porttype 定义协议绑定和数据格式的细节:
首先是定义消息风格(style) 和 传输协议(transport)
然后是对操作的输入输出的 消息编码方式(use)
service 包含若干 port
port 定义了一个通信端点,代表 binding(不同协议)到 address 的映射
使用XFire开发Web Service
XFire是一个开源的Web Service框架
operation的四种类型:
单向: 端点接收请求消息
请求/应答: 端点接收请求消息,然后返回一个响应消息
通知: 断点发送一个消息
要求/响应: 端点发送请求消息,然后接收一个响应消息
SOAP的两种消息风格
style=[document|rpc]
document: 客户端使用 XML 模式调用约定。优点:更松散的客户端和服务器端耦合性,跨平台互操作性更好
分两种: bared(裸露); wrapped,模拟rpc(包装的)
rpc: 客户端使用远程过程调用约定。 优点:对开发人员更加简单.
binding的传输协议
transport="http://schemas.xmlsoap.org/soap/http"
transport="http://schemas.xmlsoap.org/soap/smtp"
binding中消息的编码方式
user=[literal|encoded]
literal: 使用types定义的数据类型
encoded: 使用soap定义好的数据类型,不能使用自定义数据类型
可能的style/user组合
1. style="rpc" and use="encoded"
2. style="rpc" and use="literal"
3. style="document" and use="encoded"
4. style="document" and use="literal"
其中WS-I组织只支持(user=literal)格式;(user=encoded不被支持)
WS-I(Web Services Interoperability Organization) Web服务协同组织
尽量使用第4种: style="document" and use="literal"
part4. Web Service关键技术 --- UDDI
-----------------------------------------------------
一、 What is UDDI (Universal Description Discovery and Integration)
1) 即统一描述、发现和集成协议。
2) UDDI提供了一种发布和查找Web服务的方式,使贸易伙伴彼此发现对方和查询对方。
3) UDDI提供了一个全球的、平台无关的、开放式框架,使得商业应用能:
相互查找;
定义它们通过Web交互的方式;
在一个全球注册场所共享信息;
4) 在Web上存在三种开放的UDDI注册场所, 由IBM、Microsoft 和HP发起;
5) 注册是免费的,在任一注册处注册的内容被其它注册处所复制;
6) 在UDDI商业注册处提供的信息由三部分组成:
“白皮书”:(白页 White pages)包括地址、联系以及标识符、产品信息;
“黄皮书”:(黄页 Yellow pages)包括基于标准分类学的各产业分类;
“绿皮书”:(绿页 Green pages)所提供的service的详细信息;
7) Web service provider 和 requester 使用SOAP API和UDDI注册处交流;
预想的结构:发布者--注册服务--使用者
不是必须的,公共的注册服务目前还没有被广泛接受
UDDI的数据结构
1. businessEntity. 白页信息,公司的信息
2. businessService.黄页信息,Web服务的分类信息
3. bindingTemplate. 绿页信息,Web服务的技术信息,包括如何调用Web服务的信息
4. tModels. 调用细节信息,包含WSDL文档的引用。
XFire动态客户端
-----------------------------------------------------
第一步:引入 XFire相关的类库
Core Libraries
JAXB Libraries
HTTP Client Libraries
第二步:
Client client = new Client(new URL("WSDL文档URL")); //创建一个动态客户端
Object[] results = client.invoke("test", new Object[] { "Juliet" }); //调用方法
System.out.println( results[0]);
XFire动态客户端2
Service srvcModel = new ObjectServiceFactory().create(MathService.class);
XFireProxyFactory factory = new XFireProxyFactory(XFireFactory.newInstance().getXFire());
// HelloWorld 服务名称
String helloWorldURL = "http://localhost:8081/Hello/services/HelloWorld";
IHelloWorld srvc = (IHelloWorld) factory.create(srvcModel, helloWorldURL);
System.out.println("结果 :" + srvc.example("tarena"));
WebService学习,开发总结
基本概念:
1,什么是 Web 服务?
Web 是使应用程序可以以与平台和编程语言无关的方式进行相互通信的一项技术。Web 服务是一个软件接口,它描述了一组可以在网络上通过标准化的 XML 消息传递访问的操作。它使用基于 XML 语言的协议来描述要执行的操作或者要与另一个 Web 服务交换的数据。一组以这种方式交互的 Web 服务在面向服务的体系结构(Service-Oriented Architecture,SOA)中定义了特殊的 Web 服务应用程序。
2, 什么是SOAP?
SOAP (Simple Object Access Protocol )简单对象访问协议是在分散或分布式的环境中交换信息并执行远程过程调用的轻量级协议,是一个基于XML的协议。使用SOAP,不用考虑任何特定的传输协议(最常用的还是HTTP协议),可以允许任何类型的对象或代码,在任何平台上,以任何一种语言相互通信。
SOAP 包括四个部分: SOAP 封装 (envelop) ,封装定义了一个描述消息中的内容是什么,是谁发送的,谁应当接受并处理它以及如何处理它们的框架; SOAP 编码规则( encoding rules ),用于表示应用程序需要使用的数据类型的实例; SOAP RPC 表示 (RPC representation) ,表示远程过程调用和应答的协定; SOAP 绑定( binding ),使用底层协议交换信息。
应用中比较关注的是 envelop ,由一个或多个 Header 和一个 Body 组成。
SOAP 在可互操作的基础 Web 服务协议栈 中的位置 :
3, 什么是Axis?
Axis 本质上就是一个SOAP引擎 ( Apache Axis is an implementation of the SOAP ), 提供创建服务器端、客户端和网关SOAP操作的基本框架。但Axis并不完全是一个SOAP引擎,它还包括:
是一个独立的SOAP服务器。
是一个嵌入Servlet引擎(例如Tomcat)的服务器。
支持WSDL。
提供转化WSDL为Java类的工具。
提供例子程序。
提供TCP/IP数据包监视工具。
4, Axis 相比Soap v2的优点:
Axis 是第三代Apache SOAP的实现,从2000年起,SOAP v2开发小组开始讨论如何让Axis更加灵活、可配置,以及能够处理SOAP和来自W3C的各种XML标准。通过不断地讨论和代码编写,Axis目前相比SOAP V2取得了如下成果:
速度提高。 Axis通过基于事件的SAX对XML文档进行处理,从而在速度和效率上比Apache SOAP有所提高。
灵活性提高。
稳定性提高。
提供面向组件的部署。
提供一个简洁的传输抽象框架。其核心引擎完全于传输方式独立。从而使基于何种协议传输的选择更加灵活。
支持WSDL。包括WSDL和客户端代码生成等。
5, 什么是WSDL?
WSDL ( Web Service Description Language ) Web 服务器描述语言是用 XML 文档来描述 Web 服务的标准,是 Web 服务的接口定义语言,由 Ariba 、 Intel 、 IBM 、 MS 等共同提出,通过 WSDL ,可描述 Web 服务的三个基本属性:
·服务做些什么——服务所提供的操作(方法)
·如何访问服务——和服务交互的数据格式以及必要协议
·服务位于何处——协议相关的地址,如 URL
WSDL 文档以端口集合的形式来描述 Web 服务, WSDL 服务描述包含对一组操作和消息的一个抽象定义,绑定到这些操作和消息的一个具体协议,和这个绑定的一个网络端点规范。
WSDL 在Web 服务概念性协议栈 中的位置:
6, 什么是WSDD?
WSDD 就是 WEB 服务分布描述( Web Service Deployment Descriptor ) , 它定义了 WEB 服务的接口,如服务名、提供的方法、方法的参数等信息。
7, 什么是UDDI?
UDDI 就是统一描述、发现和集成( Universal Description, Discovery, and Integration )。 UDDI 用于集中存放和查找 WSDL 描述文件,起着目录服务器的作用。
Web 服务中的角色、操作和构件 :
服务提供者。从企业的角度看,这是服务的所有者。从体系结构的角度看,这是托管访问服务的平台。
服务请求者。从企业的角度看,这是要求满足特定功能的企业。从体系结构的角度看,这是寻找并调用服务,或启动与服务的交互的应用程序。服务请求者角色可以由浏览器来担当,由人或无用户界面的程序(例如,另外一个 Web 服务)来控制它。
服务注册中心。这是可搜索的服务描述注册中心,服务提供者在此发布他们的服务描述。在静态绑定开发或动态绑定执行期间,服务请求者查找服务并获得服务的绑定信息(在服务描述中)。对于静态绑定的服务请求者,服务注册中心是体系结构中的可选角色,因为服务提供者可以把描述直接发送给服务请求者。同样,服务请求者可以从服务注册中心以外的其它来源得到服务描述,例如本地文件、FTP 站点、Web 站点、广告和服务发现(Advertisement and Discovery of Services,ADS)或发现 Web 服务(Discovery of Web Services,DISCO)。
8, AXIS 的几种服务类型:
AXIS 有四种 service styles ,分别是: RPC, Document, Wrapped, 和 Message 。最常用的就是 RPC 和 Message 。
RPC : 在 AXIS 中是一个默认选项。当你部署的时候使用下列两种方式: 或则 ,它遵循 SOAP RPC 和编码规则。每个 RPC 都包括一个表示名称的外部接点和一些表示参数的内部接点。 AXIS 会根据规则将一个 XML ( WSDL 文件)文件转化成一个 JAVA 对象,并对对想赋上在文件中描述的值。也可以根据规则将一个 JAVA 对象转化成 XML 文件。
Document
适合于老的 XML schema 。
Wrapped
和 DOCUMENT 一样,适合于老的 XML schema 。
在大多书情况下,你不许要担心是 DOCUMENT 服务还是 WRAPPED 服务。
Message
以这种方式部署的话,会使 AXIS 失去意义,它使你的代码真正的用 XML 形式,而不需要转化成 JAVA 对象。以这种方式部署的有以下四种服务方法:
public Element [] method(Element [] bodies);
public SOAPBodyElement [] method (SOAPBodyElement [] bodies);
public Document method(Document body);
public void method(SOAPEnvelope req, SOAPEnvelope resp);
几种服务类型的主要区别:
基于 RPC( 远程过程调用 ) 方式,这也是 Web 服务最常用的方式。面向消息 / 文档的的类型跟 RPC 不同的是它提供了一个更底层的抽象,要求更多的编程工作。客户端可以传入任何的 XML 文档,得到的响应不一定是 SOAPEnvelope ,可以返回任何它所需要的东西,甚至不返回。虽然这对开发者来说非常的灵活,但是这种通讯类型在实际的应用中并不常见。面向消息 / 文档的 Web 服务主要适合于下面几种情况,比如批量处理,基于表单的数据导入,有需要返回非 XML 数据时, Web 服务器实现中要求直接访问传输层等等
二, 开发,部署Web服务:
首先下载并安装 tomcat4.x. 及以上版本
然后到 Axis 主页下载,现在最新版本是 1.3 final, 我们使用的是1.2.1 final版,将解压的axis中的webapps目录下的axis拷贝到tomcat安装路径下的webapp下,将解压的axis下lib下的jar文件拷贝到tomcat安装目录下commonlib下,并把他们加入到你的系统路径中。
然后启动 tomcat ,
打开 IE ,输入: http://localhost:8080/axis ,如果出现 axis 主页,说明安装 axis 成功。
部署 web 服务 在 axis 下部署 web 服务有以下两种方式:
1. 即时部署 (Instance Deployment) 利用 JWS 文件
只需要将 .java 文件拷贝到 axis 目录下,并将文件后缀改为 .jws 即可。
访问部署后的 wsdl 文件只需键入: http://localhost:8080/axis/filename.jws?wsdl
以下是 WSDL 的一个例子:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://service.kernel.gamebase.com" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://service.kernel.gamebase.com" xmlns:intf="http://service.kernel.gamebase.com" xmlns:tns1="http://vo.service.kernel.gamebase.com" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types> // 描述消息中复杂数据类型的使用
<schema targetNamespace="http://vo.service.kernel.gamebase.com" xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://service.kernel.gamebase.com"/>
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="UserGameGrade">// 定义复杂类型
<sequence>
<element name="MClassID" nillable="true" type="xsd:string"/>
<element name="gameID" nillable="true" type="xsd:string"/>
<element name="gradeType" type="xsd:int"/>
......
</sequence>
</complexType>
</schema>
......
</wsdl:types>
<wsdl:message name="getGameGradeRankResponse">// 定义操作的输出参数
<wsdl:part name="getGameGradeRankReturn" type="tns1:GameGradeRank"/>
</wsdl:message>
<wsdl:message name="getGameGradeRankRequest">// 定义操作的输入参数
<wsdl:part name="in0" type="xsd:string"/>
<wsdl:part name="in1" type="xsd:int"/>
<wsdl:part name="in2" type="xsd:int"/>
</wsdl:message>
......
<wsdl:portType name="GameGradeService"> // WSDL: portType 元素中定义了 Web 服务的操作。
<wsdl:operation name="getGameGradeRank" parameterOrder="in0 in1 in2"> // 操作定义了输入和输出数据流中可以出现的 XML 消息
<wsdl:input message="impl:getGameGradeRankRequest" name="getGameGradeRankRequest"/>
<wsdl:output message="impl:getGameGradeRankResponse" name="getGameGradeRankResponse"/>
</wsdl:operation>
<wsdl:operation name="getUserGameGradeRank" parameterOrder="in0 in1 in2 in3 in4">
<wsdl:input message="impl:getUserGameGradeRankRequest" name="getUserGameGradeRankRequest"/>
<wsdl:output message="impl:getUserGameGradeRankResponse" name="getUserGameGradeRankResponse"/>
</wsdl:operation>
......
</wsdl:portType>
<wsdl:binding name="GameGradeServiceSoapBinding" type="impl:GameGradeService">// 描述特定服务接口( WSDL: portType )的协议、数据格式、安全性和其它属性
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getGameGradeRank">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="getGameGradeRankRequest">
<wsdlsoap:body namespace="http://service.kernel.gamebase.com" use="literal"/>
</wsdl:input>
<wsdl:output name="getGameGradeRankResponse">
<wsdlsoap:body namespace="http://service.kernel.gamebase.com" use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="GameGradeServiceService">// 定义服务:名字, 访问点 ,位置
<wsdl:port binding="impl:GameGradeServiceSoapBinding" name="GameGradeService">
<wsdlsoap:address location="http://localhost:8080/gamebase/services/GameGradeService"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions> 2 .定制部署 (Custom Deployment) 利用部署描述符 wsdd
以下是部署描述符的一个例子: <deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="GameGradeService" type="" provider="java:RPC"
style="rpc" use="encoded"> // 服务名字,服务类型及服务提供者
<parameter name="scope" value="Request"/>
<parameter name="className" value="/blog/com.gamebase.kernel.service.ServiceImpl"/>// 实现该服务的具体类
<parameter name="allowedMethods" value="*"/>
<namespace>http://service.kernel.gamebase.com</namespace>
<typeMapping xmlns:ns1="http://vo.service.kernel.gamebase.com" // 类型映射
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
qname="ns1:GameGradeRank"//Qualified Name (特定名字)
languageSpecificType="java:com.gamebase.kernel.service.vo.GameGradeRank"
serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"// 指定序列化工厂
deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory" // 反序列化工厂 name="GameGradeRank"/>
………
</service>
</deployment>
访问部署后的wsdl文件只需键入
http://localhost:8080/axis /services/ GameGradeService
三, 在IDE下开发Web服务:
1, 在Jubilder下开发WebService:
使用Jbuilder集成开发环境,能够根据服务接口类生成web服务描述文件,web服务部署描述文件及客户端代码,这样能够节省我们大部分时间(开发,配置),且减少出错机率。
Jbuilder 在以前的版本,如jbuilder8(可能更低版本)就支持Axis,我用的是Jbuilder2006,不过大体步骤都是相同。
在开始前,我们有个服务接口GameGradeService类,服务接口实现类ServiceImpl类及相关附属类。我们要实现该服务接口。
2.1 ,打开Jbuilder,新建一个工程,如testWebService
2.2 ,新建一个名为webService的WebService Server (file>new:WebServices:Axis WebServices Server Configuration)
2.3, 在出现的Web Services Designers可视化界面,点击“create Service”,选择“java Service”
2.4 ,配置新创建的java Service,点击JavaService1,配置Service Name为GameGradeService,服务接口为我们有的那个服务接口GameGradeService,实现类为我们实现改接口的类ServiceImpl。
2.5 ,然后编译该工程,能够生成web服务部署文件,web服务描述文件,如果你选择了生成客户端代码的话,它也能生成相应的客户端代码。
2.6 ,启动该服务,访问 :http://localhost:8080/webService/services/GameGradeService?wsdl ,如果出现该服务的描述文档,说明发布成功。
2.7 ,执行自动生成的客户端代码进行测试,发现测试成功。
2.8 ,你可以用webService的webServices Client来根据wsdl只生成客户端代码。
a, 新建一个名为webServiceClient的WebService Client(file>new:WebServices:Axis WebServices Client Configuration)
b, 在出现的Web Services Designers可视化界面,点击“create Service”,选择“import from url”
c, 配置新创建的java Service,点击JavaService1,配置Service Name为GameGradeService,Input WSDL file 为给定的wsdl。
d, 然后编译该工程
2, 在eclipse下开发WebService:
Eclipse3.1 及相关插件已经能够很好的支持webService开发。
右键点击wsdl文件,选择webServices,有以下功能:发布wsdl文件,生成客户端代码等。
右键 点击服务接口文件,选择webServices,有以下功能:生成web Service等。
同时eclipse提供了友好的界面操作,如测试的时候,提供界面让你输入参数,而不必该改程序。
四, 开发过程中的问题:
在使用 AXIS 开发WEB服务的时候,会遇到很多问题。比如:XML解析器出现的异常、客户端程序找不到可用的Web服务、序列化/反序列化等。
XML 解析器出现的异常主要是由于类型映射的问题导致的,用到那个Bean就把那个bean映射进去就可以避免该问题。
客户端程序找不到可用的Web服务主要是由于客户端对服务提供者的url及服务名字输入有错,这一般是由于手写客户端代码造成的。
序列化/反序列化问题,没有对传输中的某个Bean类型映射相应的序列化/反序列化工厂,或者是复杂类型中,没有实现自定义的序列化/反序列化工厂。
以上是开发过程中主要遇到的几类问题,在以后的开发过程中,一定还会需要遇到更多的问题。
五, 其他相关知识:
1 ,java类与wsdl相互生成工具:
Axis 提供了”WSDL2Java”工具,可以利用wsdl描述来产生服务的Java代理和框架(proxy and skeletons)。
Axis 提供了”Java2WSDL”工具,可以由java类生成wsdl文件。
2, 序列化与反序列化:
序列化/反序列化器在英文中的对应翻译是Serializer/Deserializer,一个序列化器的功能是遵循一定的映射规则和编码风格,将一种类型的JAVA对象通过某种特定的机制,转换成为XML描述的形式;反序列化器的功能是序列化器所做工作的逆操作,两者相辅相成,成对出现。Axis中的序列化/反序列化器采用设计范式中的工厂模式,每一个Serializer唯一对应一个SerializerFactory;每一个Deserializer唯一对应一个DeserializerFactory。
Axis 已经为开发者提供了丰富的序列化/反序列化器,对于java的基本数据类型,绝大部分常用的容器类(比如数组类型,Vector类型等)都提供了实现,特别是提供了对W3C的DOM对象(比如Document, Element等)和符合Bean规范的JAVA对象提供了功能完善的序列化/反序列化器,但对于一些特殊类型的对象,需要通过Web服务进行传递,我们不得不开发自己的序列化/反序列化器。
3 ,Axis与Spring的结合:
Axis 与spring结合,需要提供一些额外工作,即将实现web服务接口的Bean与web服务部署中服务类如何关联。 如下:
<service name="GameService" type="" provider="Handler" style="rpc">
<parameter name="handlerClass" value="/blog/com.workingmouse.webservice.axis.SpringBeanRPCProvider"/>
<parameter name="springBean" value="gameInfoService"/>
<parameter name="springBeanClass" value="/blog/com.gamebase.kernel.service.GameService"/>
<parameter name="scope" value="Request"/>
<parameter name="allowedMethods" value="*"/>
.......
</service>
参数handlerClass的值是处理Bean与wsdd文件中服务类的关联。
参数springBean的值表示实现接口GameService注册的Bean的名字。
参数springBeanClass的值表示接口GameService的类。
1.使用HttpClient
用到的jar文件:commons-httpclient-3.1.jar
方法:
预先定义好Soap请求数据,可以借助于XMLSpy Professional软件来做这一步生成。
Java代码
String soapRequestData = "<?xml version=/"1.0/" encoding=/"utf-8/"?>" +
"<soap12:Envelope xmlns:xsi=/"http://www.w3.org/2001/XMLSchema-instance/" xmlns:xsd=/"http://www.w3.org/2001/XMLSchema/" xmlns:soap12=/"http://www.w3.org/2003/05/soap-envelope/">" +
"<soap12:Body>" +
" <getCountryCityByIp xmlns=/"http://WebXml.com.cn//">" +
" <theIpAddress>219.137.167.157</theIpAddress>" +
" </getCountryCityByIp>" +
" </soap12:Body>" +
"</soap12:Envelope>";
然后定义一个PostMethod,这时需要指定web服务的Url;
PostMethod postMethod = new PostMethod(“http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx”);
然后把Soap请求数据添加到PostMethod中
byte[] b = soapRequestData.getBytes("utf-8");
InputStream is = new ByteArrayInputStream(b,0,b.length);
RequestEntity re = new InputStreamRequestEntity(is,b.length,"application/soap+xml; charset=utf-8");
postMethod.setRequestEntity(re);
最后生成一个HttpClient对象,并发出postMethod请求
HttpClient httpClient = new HttpClient();
statusCode = httpClient.executeMethod(postMethod);
String soapRequestData = postMethod.getResponseBodyAsString();
soapRequestData就是调用web服务的Soap响应数据,是xml格式的,可以通过解析soapRequestData来获得调用web服务的返回值。
2.使用Xfire
用到的jar文件xfire-all-1.2.4.jar, jdom-1.0.jar
方法:
定义一个Client对象,指定web服务的wsdl的地址
Client c = new Client(new URL(“http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx?wsdl”));
调用Client对象的invoke方法,指定web服务的方法名,和参数,返回值是一个Object型的数组。
下面代码调用getVersionTime方法,这个方法没有参数用所以后一个参数使用new Object[0]。
Object[] results = c.invoke(“getVersionTime”, new Object[0]);
3.使用axis2
下载axis2-1.4
方法:
打开控制台,进入axis2-1.4/bin目录
Java代码
wsdl2java.bat -uri http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx?wsdl -p ws.clinet.axis2
上述命令执行完后,会在当前目录下生成一个src目录,在src/ ws/ clinet/ axis2目录里生成XXXXCallbackHandler.java和XXXXStub.java两个文件。
wsdl2java 会根据wsdl文件生成web服务的调用接口,参数类,返回值的类。
在调用webservice的时候直接实例化一个XXXXStub的对象,然后调用web服务的方法就可以了。
4. 总结
针对某种工具搭建的Web Service服务可能有与其对应的更简单的调用方法,在这里没有做描述,上述的调用web服务的方法是通用的。
上述三种方法中使用httpclient应该是比较灵活,但是开发效率低,难度大,使用Xfire和axis2比较容易,开发速度快,但是axis2通用性不好,有的web服务用axis2不好用。httpclient和Xfire通用性比较好,鉴于以上特点推荐使用Xfire。
Js 调用 WebService心得总结
页面:
<INPUT type="button" value="Button" onclick="getdata()"><br>
<span id="div1" class="list"></span>
<script language=javascript>
setInterval(getdata,1000); //动态定时调用
</script>
脚本:
<SCRIPT ID="clientEventHandlersJS" LANGUAGE="javascript">
function getdata()
{
var index=0;
docSubmit =new ActiveXObject("Microsoft.XMLDOM");
docSubmit.async = false;
docSubmit.load("http://localhost/WebApplication1/Service1.asmx/GetData?maxval=5");
docSubmit.loadXML(docSubmit.xml.replace(/</g,"<").replace(/>/g,">"));
var s="";
nodeList=docSubmit.documentElement.getElementsByTagName("ds");
for (i=0;i<nodeList.length;i++)
{
s=s+nodeList(i).selectSingleNode("KeShimch").text+'<br>';
}
div1.innerHtml ="";
div1.innerHTML=s;
div1.style.visibility="visible";
}
</script>
//如果返回是个字符串:
<SCRIPT ID="clientEventHandlersJS" LANGUAGE="javascript">
function chang()
{
docSubmit =new ActiveXObject("Microsoft.XMLDOM");
docSubmit.async = false;
docSubmit.load("http://localhost/Advertisement/ADService.asmx/GetADCode?ADID=1");
var s=docSubmit.documentElement.text;
window.alert(s);
td_AD.innerHTML=s;
}
//setInterval(chang,2000);//间隔执行
</script>
注意:
在fromework1.0和1.1是有区别的,
在1.1的 machine.config (C:\WINNT\Microsoft.NET\Framework\v1.1.4322\CONFIG),默认webservice去除了post,get方法
你可在你的 machine.config 中加上 或者 只在 webServices 项目的 Web.config 的<system.web>里加上:
<webServices>
<protocols>
<add name="HttpPost" />
<add name="HttpGet" />
</protocols>
</webServices>
否则,在ie地址栏输入 webServices 访问地址串时,提示:请求格式无法识别。
还有
docSubmit = new ActiveXObject("MSXML2.DOMDocument"); //1.0
换成
docSubmit =new ActiveXObject("Microsoft.XMLDOM"); //1.1
--------------------------
web服务方法:
[WebMethod]
public string GetData(string maxval)
{
BaseClass.DbManagerSql dbm=new BaseClass.DbManagerSql();
string strSql="select * from s_KeShi where Keshidm>"+maxval;
DataSet ds=dbm.Query(strSql);
return ds.GetXml();
}
返回的xml数据:
<?xml version="1.0" encoding="utf-8" ?>
<string xmlns="http://tempuri.org/">
<NewDataSet>
<ds> <KeShidm>6</KeShidm> <KeShimch>财务部</KeShimch> </ds>
<ds> <KeShidm>7</KeShidm> <KeShimch>政工部</KeShimch> </ds>
<ds> <KeShidm>8</KeShidm> <KeShimch>安质部</KeShimch> </ds>
<ds> <KeShidm>9</KeShidm> <KeShimch>电管部</KeShimch> </ds>
<ds> <KeShidm>10</KeShidm> <KeShimch>运输公司</KeShimch> </ds>
<ds> <KeShidm>11</KeShidm> <KeShimch>局长</KeShimch> </ds>
<ds> <KeShidm>202</KeShidm> <KeShimch>变电站</KeShimch></ds>
</NewDataSet>
</string>
一、利用jdk web服务api实现,这里使用基于 SOAP message 的 Web 服务首先建立一个Web services EndPoint
Java代码
package Hello;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.xml.ws.Endpoint;
@WebService
public class Hello {
@WebMethod
public String hello(String name) {
return "Hello, " + name + "“n";
}
public static void main(String[] args) {
// create and publish an endpoint
Hello hello = new Hello();
Endpoint endpoint = Endpoint.publish("http://localhost:8080/hello", hello);
}
}
package Hello;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.xml.ws.Endpoint;
@WebService
public class Hello {
@WebMethod
public String hello(String name) {
return "Hello, " + name + "“n";
}
public static void main(String[] args) {
// create and publish an endpoint
Hello hello = new Hello();
Endpoint endpoint = Endpoint.publish("http://localhost:8080/hello", hello);
}
}
2.使用 apt 编译 Hello.java(例:apt -d [存放编译后的文件目录] Hello.java ) ,会生成 jaws目录
3.使用java Hello.Hello运行,然后将浏览器指向http://localhost:8080/hello?wsdl就会出现下列显示
4.使用wsimport 生成客户端
使用如下:wsimport -p . -keep http://localhost:8080/hello?wsdl
5.客户端程序
Java代码
class HelloClient{
public static void main(String args[]) {
HelloService service = new HelloService();
Hello helloProxy = service.getHelloPort();
String hello = helloProxy.hello("你好");
System.out.println(hello);
}
}
class HelloClient{
public static void main(String args[]) {
HelloService service = new HelloService();
Hello helloProxy = service.getHelloPort();
String hello = helloProxy.hello("你好");
System.out.println(hello);
}
}
二、使用xfire,我这里使用的是myeclipse集成的xfire进行测试的
利用xfire开发WebService,可以有三种方法
1一种是从javabean 中生成;
2 一种是从wsdl文件中生成;
3 还有一种是自己建立webservice
步骤如下
用myeclipse建立webservice工程,目录结构如下
首先建立webservice接口,
代码如下
Java代码
package com.myeclipse.wsExample;
//Generated by MyEclipse
public interface IHelloWorldService {
public String example(String message);
}
package com.myeclipse.wsExample;
//Generated by MyEclipse
public interface IHelloWorldService {
public String example(String message);
}
Java代码
package com.myeclipse.wsExample;
//Generated by MyEclipse
public class HelloWorldServiceImpl implements IHelloWorldService {
public String example(String message) {
return message;
}
}
package com.myeclipse.wsExample;
//Generated by MyEclipse
public class HelloWorldServiceImpl implements IHelloWorldService {
public String example(String message) {
return message;
}
}
修改service.xml 文件,加入以下代码
Xml代码
<service>
<name>HelloWorldService</name>
<serviceClass>
com.myeclipse.wsExample.IHelloWorldService
</serviceClass>
<implementationClass>
com.myeclipse.wsExample.HelloWorldServiceImpl
</implementationClass>
<style>wrapped</style>
<use>literal</use>
<scope>application</scope>
</service>
<service>
<name>HelloWorldService</name>
<serviceClass>
com.myeclipse.wsExample.IHelloWorldService
</serviceClass>
<implementationClass>
com.myeclipse.wsExample.HelloWorldServiceImpl
</implementationClass>
<style>wrapped</style>
<use>literal</use>
<scope>application</scope>
</service>
把整个项目部署到tomcat服务器中 ,打开浏览器,输入http://localhost:8989/HelloWorld/services/HelloWorldService?wsdl
客户端实现如下
Java代码
package com.myeclipse.wsExample.client;
import java.net.MalformedURLException;
import java.net.URL;
import org.codehaus.xfire.XFireFactory;
import org.codehaus.xfire.client.Client;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;
import com.myeclipse.wsExample.IHelloWorldService;
public class HelloWorldClient {
public static void main(String[] args) throws MalformedURLException, Exception {
// TODO Auto-generated method stub
Service s=new ObjectServiceFactory().create(IHelloWorldService.class);
XFireProxyFactory xf=new XFireProxyFactory(XFireFactory.newInstance().getXFire());
String url="http://localhost:8989/HelloWorld/services/HelloWorldService";
try
{
IHelloWorldService hs=(IHelloWorldService) xf.create(s,url);
String st=hs.example("zhangjin");
System.out.print(st);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
package com.myeclipse.wsExample.client;
import java.net.MalformedURLException;
import java.net.URL;
import org.codehaus.xfire.XFireFactory;
import org.codehaus.xfire.client.Client;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;
import com.myeclipse.wsExample.IHelloWorldService;
public class HelloWorldClient {
public static void main(String[] args) throws MalformedURLException, Exception {
// TODO Auto-generated method stub
Service s=new ObjectServiceFactory().create(IHelloWorldService.class);
XFireProxyFactory xf=new XFireProxyFactory(XFireFactory.newInstance().getXFire());
String url="http://localhost:8989/HelloWorld/services/HelloWorldService";
try
{
IHelloWorldService hs=(IHelloWorldService) xf.create(s,url);
String st=hs.example("zhangjin");
System.out.print(st);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
这里再说点题外话,有时候我们知道一个wsdl地址,比如想用java客户端引用.net 做得webservice,使用myeclipse引用,但是却出现无法通过验证的错误,这时我们可以直接在类中引用,步骤如下
Java代码
public static void main(String[] args) throws MalformedURLException, Exception {
// TODO Auto-generated method stub
Service s=new ObjectServiceFactory().create(IHelloWorldService.class);
XFireProxyFactory xf=new XFireProxyFactory(XFireFactory.newInstance().getXFire());
//远程调用.net开发的webservice
Client c=new Client(new URL("http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx?wsdl"));
Object[] o=c.invoke("qqCheckOnline", new String[]{"531086641","591284436"});
//调用.net本机开发的webservice
Client c1=new Client(new URL("http://localhost/zj/Service.asmx?wsdl"));
Object[] o1=c1.invoke("HelloWorld",new String[]{});
}
public static void main(String[] args) throws MalformedURLException, Exception {
// TODO Auto-generated method stub
Service s=new ObjectServiceFactory().create(IHelloWorldService.class);
XFireProxyFactory xf=new XFireProxyFactory(XFireFactory.newInstance().getXFire());
//远程调用.net开发的webservice
Client c=new Client(new URL("http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx?wsdl"));
Object[] o=c.invoke("qqCheckOnline", new String[]{"531086641","591284436"});
//调用.net本机开发的webservice
Client c1=new Client(new URL("http://localhost/zj/Service.asmx?wsdl"));
Object[] o1=c1.invoke("HelloWorld",new String[]{});
}
WebService使用的一些总结
什么是WebService:
这个不用我在这里废话,网上的资料一搜一大把,如果你没有接触过这方面的知识,你可以先去网上查一下。这里我只想说一下我印象比较深刻的几点:
WebService是基于soap协议的。说实话这个知识刚开始我理解的并不是很到位。这也在很长的时间局限了我在代码过程中的思维。我会在后面一个关于天气预报的实例中进行详细介绍的。总之,所有的webService请求、应答都是建立在soap协议的基础上的,而soap传输数据的载体是xml。关于soap协议的介绍,在W3C上有很详细的教程。
WSDL是WebService的描述语言,它定义了Web Service做什么,怎么做和查询的信息。在验证一个WebService是否好用的时候,我们通常会选则在浏览器中输入http://…….*?wsdl。如果显示出一个xml文件,我们就认为这是好用的,反之就是不可用的。在项目刚刚开始的时候,我也是这么天真的认为的,因为教程上都是这么演示的。但事实并非如此,就如同以下调用天气预报的wsdl。如果你在浏览器中输入http://fhs.6617.com/getweather.asmx?WSDL,它是不显示的,但事实证明这个webservice服务时可以使用的(你可以通过http://fhs.6617.com/getweather.asmx?WSDL生成本地代理类)。这也一直是初学WebService者的一个误区。之所以不能通过浏览器访问,可能原因是服务发布者,或者服务器做了一些限制,就如同互联网上很多服务器,我们可以访问却ping不同一样,服务者做了一些限制。(我的猜测)
怎样使用WebService
是不是调用WebService时,必须要得到wsdl?必须要生成本地代理类?
在回答这个问题,之前,我想先介绍一下网上一些资源:有很多热心的人,收集了很多常用的WebService,如:http://lqixv.javaeye.com/blog/308407。其中罗列的每一种服务,作者都提供了三种连接:Endpoint Disco WSDL 。其实这就是隐约的告诉我们调用webservice服务的三种途径。
就如同我们的项目,客户端在调用电信WebService上行发短信时,是通过 wsdl生成本地代理类方式实行的。而在接收状态报告下行时,采用的是 Endpoint方式(客户端不需要生成本地代理类,只需要知道Endpoint地址)。
所以wsdl很重要,但并不是必须的,前提你能通过api,规范文档等获取你需要的地址、命名空间的相关信息。
如何调用wsdl生成本地代理类:
通过wsdl生成本地代理类,有很多方式,既可以通过wsdl2java命令手动生成,也可以通过eclipse的axis2插件、xfire插件等。但是通过项目的实践,觉得尽量还是通过axis2的wsdl2java的命令生成,会省去很多麻烦。比如说,如果你拥有很多的wsdl文件,他们又是相互联系的,这样你通过eclipse的插件生成时,会出现错误。因为它只能一下加载一个wsdl文件。这个问题在项目初期,让我吃了很多的苦头。。。。。
Axis2是一个比较常用的WebService引擎,大家可以通过到http://ws.apache.org/axis2/下载,其中其中axis2-1.4.1-bin.zip文件中包含了Axis2中所有的jar文件,以及命令工具, axis2-1.4.1-war.zip文件则用于将WebService发布到Web容器中,网上有很多axis2教程,在这里不再多说。
天气预报调用实例:
下面的一个实例是调用天气预报的一个例子,没有采用wsdl生成本地代理类的方式,采用的是通过http请求直接访问服务端点的方法:
步骤是:
1、利用soap向webservice endpoint进行请求,取回请求结果
2、通过dom4J解析返回的xml流,得到所要的信息。
通过这个例子相信大家,会对”webserviice是基于soap协议”的这句话有更深刻的理解,另外在使用dom4J解析xml返回流的过程中,遇到了些麻烦,需要额外引入jaxen-1.1.1.jar包,否则程序会报org/jaxen/JaxenException的错误。并且在XML包含命名空间时,定位元素,需要按照xpath语法来写。
下面是类的源代码:
代码
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* 类作用调用webservice得到天气预报服务
* @author qsw-Myonlystar 2010-1-13上午09:59:45
*/
public class Weather {
/**
* 获取soap请求头,并替换其中的标志符号为用户的输入符号
* @param city 用户输入城市名
* @return 用户将要发送给服务器的soap请求
*/
private static String getSoapRequest(String city) {
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
+ "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
+ "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+ "<soap:Body> <getWeatherbyCityName xmlns=\"http://WebXml.com.cn/\">"
+ "<theCityName>" + city
+ "</theCityName> </getWeatherbyCityName>"
+ "</soap:Body></soap:Envelope>");
return sb.toString();
}
/**
* 用户把SOAP请求发送给服务器端,并返回服务器点返回的输入流
* @param city 用户输入的城市名称
* @return 服务器端返回的输入流,供客户端读取
* @throws Exception
*/
public static InputStream getSoapInputStream(String city) throws Exception {
try {
String soap = getSoapRequest(city);
if (soap == null) {
return null;
}
URL url = new URL(
"http://www.webxml.com.cn/WebServices/WeatherWebService.asmx");
URLConnection conn = url.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Length", Integer.toString(soap
.length()));
conn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
conn.setRequestProperty("SOAPAction",
"http://WebXml.com.cn/getWeatherbyCityName");
OutputStream os = conn.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "utf-8");
osw.write(soap);
osw.flush();
osw.close();
InputStream is = conn.getInputStream();
//System.out.println(is.toString());
return is;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 通过dom4j对服务器端返回的XML进行解析
* @param city 用户输入的城市名称
* @return 符串 用,分割
*/
public static String getWeather(String city) {
Document document=null;
SAXReader reader = new SAXReader();
String s="";
Map map=new HashMap();
map.put("design", "http://WebXml.com.cn/");
reader.getDocumentFactory().setXPathNamespaceURIs(map);
try {
InputStream is = getSoapInputStream(city);//得到输入流
document=reader.read(is);//将输入流转化为document
String t=document.asXML();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
List nodes = document.selectNodes("//design:string");
for (Iterator it = nodes.iterator(); it.hasNext();) {
Element elm = (Element) it.next();
String text=elm.getText();
//System.out.println("fsffs"+text);
s=s+elm.getText()+"\n";
}
return s;
}
/**
* 测试函数
* @param args
*/
public static void main(String args[]){
Weather w=new Weather();
System.out.println(w.getWeather("泰安"));
}
}
另外向大家推荐一个比较好的网站,http://www.webxml.com.cn/zh_cn/index.aspx。上面又很多好的webservice可以供我们调用。
Jquery ajax调用webservice总结
jquery ajax调用webservice(C#)要注意的几个事项:
1、web.config里需要配置2个地方
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</httpHandlers>
在<system.web></system.web>之间加入
<webServices>
<protocols>
<add name="HttpPost" />
<add name="HttpGet" />
</protocols>
</webServices>
2.正确地编写webserivce的代码
/// <summary>
/// UserValidate 的摘要说明
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。
[System.Web.Script.Services.ScriptService]
public class UserValidate : System.Web.Services.WebService
{
DFHon.Content.Common.rootPublic rp = new DFHon.Content.Common.rootPublic();
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string ValidateUserLogState()
{
string result = "";
HttpCookie cookie = HttpContext.Current.Request.Cookies["DHFonMenberInfo"];
if (cookie != null)
{
string username = System.Web.HttpUtility.UrlDecode(cookie["MenberName"]);
int ipoint = 0;
int gpoint = 0;
try
{
DataTable dt = UserBll.ExecuteUserAllInfo(username);
if (dt.Rows.Count > 0)
{
ipoint = int.Parse(dt.Rows[0]["iPoint"].ToString());
gpoint = int.Parse(dt.Rows[0]["gPoint"].ToString());
}
}
catch
{ }
result = "{'user':{'id':'" + cookie["UserId"] + "','name':'" + username + "','message':'" + rp.getUserMsg(DFHon.Global.CurrentCookie.UserName) + "','ipoint':'" + ipoint.ToString() + "','gpoint':'" + gpoint.ToString() + "'}}";
}
else
{
result = "{'user':{'id':'0','name':'','message':'0','ipoint':'0','gpoint':'0'}}";
}
return result;
}
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string UserLogin(string userName, string userPwd)
{
string returnVal = "";
try
{
GlobalUserInfo info;
DFHon.Content.UserLogin _UserLogin = new DFHon.Content.UserLogin();
EnumLoginState state = _UserLogin.PersonLogin(HttpUtility.UrlDecode(userName), userPwd, out info);
if (state == EnumLoginState.Succeed)
{
DFHon.Global.CurrentCookie.Set(info);
DFHon.API.PDO.DiscuzNT.PassportLogin.UserLogin(Server.UrlDecode(userName), userPwd, -1);
int ipoint = 0;
int gpoint = 0;
DataTable dt = UserBll.ExecuteUserAllInfo(userName);
if (dt.Rows.Count > 0)
{
ipoint = int.Parse(dt.Rows[0]["iPoint"].ToString());
gpoint = int.Parse(dt.Rows[0]["gPoint"].ToString());
}
returnVal = "{'user':{'id':'" + info.UserId.ToString() + "','name':'" + info.UserName + "','message':'" + rp.getUserMsg(userName) + "','ipoint':'" + ipoint.ToString() + "','gpoint':'" + gpoint.ToString() + "'}}";
}
else
{
int ids = 0;//状态:-2用户被锁定 -1用户名密码错误
switch (state)
{
case EnumLoginState.Err_Locked:
ids = -2;
break;
case EnumLoginState.Err_UserNameOrPwdError:
ids = -1;
break;
default:
break;
}
returnVal = "{'user':{'id':'" + ids + "','name':'','message':'0','ipoint':'0','gpoint':'0'}}";
}
}
catch
{
returnVal = "{'user':{'id':'0','name':'','message':'0','ipoint':'0','gpoint':'0'}}";
}
return returnVal;
}
[WebMethod]
public string UserLogout()
{
if (HttpContext.Current.Request.Cookies["DHFonMenberInfo"] != null)
{
HttpCookie cookie = new HttpCookie("DHFonMenberInfo");
cookie.Expires = System.DateTime.Now.AddDays(-1);
cookie.Domain = DFHon.Config.BaseConfig.getV("weblogin");
HttpContext.Current.Response.AppendCookie(cookie);
}
return "1";
}
DFHon.Content.user UserBll = new DFHon.Content.user();
[WebMethod]
public string ValidateUserEmail(string email)
{
string result = "0";//返回的结果 -2邮箱为空 -1邮箱格式不正确 0邮箱存在 1填写正确
if (string.IsNullOrEmpty(email))
{
result = "-2";//邮箱为空
}
else if (!IsValidEmail(email))
{
result = "-1";//邮箱格式不正确
}
else if (UserBll.sel_useremail(email) > 0)
{
result = "0";//邮箱存在
}
else
{
result = "1";//可以注册
}
return result;
}
[WebMethod]
public string ValidateUserName(string username)
{
string result = "0";//返回值:-1用户名长度为2-16;0用户名存在;1可以注册
if (username == "" || username == null || username.Length < 2 || username.Length > 16)
{
result = "-1";
}
else if (UserBll.sel_username(username) != 0)
{
result = "0";
}
else
{
result = "1";
}
return result;
}
public bool IsValidEmail(string strIn)
{ // Return true if strIn is in valid e-mail format.
return System.Text.RegularExpressions.Regex.IsMatch(strIn, @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
}
}
3、前台JQuery代码
<script>
$(function() {
$("#userloging").show();
//登录框处理开始
//加载登录状态
$.ajax({
type: "POST", //访问WebService使用Post方式请求
contentType: "application/json;charset=utf-8", //WebService 会返回Json类型
url: "/API/Service/UserValidate.asmx/ValidateUserLogState", //调用WebService
data: "{}", //Email参数
dataType: 'json',
beforeSend: function(x) { x.setRequestHeader("Content-Type", "application/json; charset=utf-8"); },
error: function(x, e) { },
success: function(response) { //回调函数,result,返回值
$("#userloging").hide();
var json = eval('(' + response.d + ')');
var userid = json.user.id;
if (userid > 0) {
$("#spanusername").html(json.user.name);
$("#spanmessagenum").html(json.user.message);
$("#userloginsucced").show();
$("#userloginbox").hide();
}
}
});
//登录
$("#userlogbutton").click(function() {
var username = $("#username").val();
var userpwd = $("#userpassword").val();
if (username != "" && userpwd != "") {
$("#userloging").show();
$.ajax({
type: "POST", //访问WebService使用Post方式请求
contentType: "application/json;charset=utf-8", //WebService 会返回Json类型
url: "/API/Service/UserValidate.asmx/UserLogin", //调用WebService
data: "{userName:'" + username + "',userPwd:'" + userpwd + "'}", //Email参数
dataType: 'json',
beforeSend: function(x) { x.setRequestHeader("Content-Type", "application/json; charset=utf-8"); },
error: function(x, e) {
},
success: function(result) { //回调函数,result,返回值
$("#userloging").hide();
var json = eval('(' + result.d + ')');
var userid = json.user.id;
if (userid > 0) {
$("#spanusername").html(json.user.name);
$("#spanmessagenum").html(json.user.message);
$("#userloginsucced").show();
$("#userloginbox").hide();
}
else {
switch (userid) {
case -2:
alert("用户被锁定!请30分钟后再登录!");
$("#username").focus();
break;
case -1:
alert("用户名或密码错误!请核对您的用户名和密码!");
$("#userpassword").focus();
break;
default:
alert("登录失败!请核对您的用户名和密码之后重试!");
$("#userpassword").focus();
break;
}
}
}
});
}
else if (username == "") {
alert("用户名不能为空!");
$("#username").focus();
}
else if (userpwd == "") {
alert("密码不能为空!");
$("#userpassword").focus();
}
});
//退出
$("#logout").click(function() {
$("#userloging").show();
$.ajax({
type: "POST", //访问WebService使用Post方式请求
contentType: "application/json;utf-8", //WebService 会返回Json类型
url: "/API/Service/UserValidate.asmx/UserLogout", //调用WebService
data: "{}", //Email参数
dataType: 'json',
beforeSend: function(x) { x.setRequestHeader("Content-Type", "application/json; charset=utf-8"); },
success: function(result) { //回调函数,result,返回值
$("#userloging").hide();
if (result.d > 0) {
$("#userloginsucced").hide();
$("#userloginbox").show();
}
}
});
}); //登录框处理结束
});
</script>
webservice:
wsdl(Web Services Description Language):xml文档,用来说明一组 SOAP 消息以及
如何交换这些消息
UDDI (Universal Description, Discovery, and Integration) 是一个主要针对Web服
务供应商和使用者的新项目。在用户能够调用Web服务之前,必须确定这个服务内包含哪
些商务方法,找到被调用的接口定义,还要在服务端来编制软件,UDDI是一种根据描述文
档来引导系统查找相应服务的机制。UDDI利用SOAP消息机制(标准的XML/HTTP)来发布,
编辑,浏览以及查找注册信息。它采用XML格式来封装各种不同类型的数据,并且发送到
注册中心或者由注册中心来返回需要的数据。
webservice优势:
(1)可以跨防火墙进行通信 如果中间件换成webservice的话,可以从用户界面直接接
调用中间层组件,这样可以省去建立动态页面。要调用Web Service,可以直接使用
Microsoft SOAP Toolkit或.net这样的SOAP客户端,也可以使用自己开发的SOAP客户端,
然后把它和应用程序连接起来。不仅缩短了开发周期,还减少了代码复杂度,并能够增强
应用程序的可维护性。
(2)应用程序集成。 即把在不同平台编写的应用程序统一集成起来,传统方法会花费
大量的精力;而通过Web Service,应用程序可以用标准的方法把功能和数据“暴露”出
来,供其它应用程序使用。
XML Web services 提供了在松耦合环境中使用标准协议(HTTP、XML、SOAP 和 WSDL
)交换消息的能力。消息可以是结构化的、带类型的,也可以是松散定义的。
(3)BtoB集成。通过Web Service,公司可以只需把关键的商务应用“暴露”给指定的
供应商和客户,就可以了,Web Service运行在Internet上,在世界任何地方都可轻易实
现,其运行成本就相对较低。
Web Service只是B2B集成的一个关键部分,还需要许多其它的部分才能实现集成。
用Web Service来实现B2B集成的最大好处在于可以轻易实现互操作性。只要把商务逻辑“
暴露”出来,成为Web Service,就可以让任何指定的合作伙伴调用这些商务逻辑,而不
管他们的系统在什么平台上运行,使用什么开发语言。这样就大大减少了花在B2B集成上
的时间和成本。
(4)软件和数据重用。
Web Service在允许重用代码的同时,可以重用代码背后的数据。使用Web Service
,再也不必像以前那样,要先从第三方购买、安装软件组件,再从应用程序中调用这些组
件;只需要直接调用远端的Web Service就可以了。另一种软件重用的情况是,把好几个
应用程序的功能集成起来,通过Web Service “暴露”出来,就可以非常容易地把所有这
些功能都集成到你的门户站点中,为用户提供一个统一的、友好的界面。 可以在应用程
序中使用第三方的Web Service 提供的功能,也可以把自己的应用程序功能通过Web
Service 提供给别人。两种情况下,都可以重用代码和代码背后的数据。
WebService的缺点:
(1)单机应用程序
目前,企业和个人还使用着很多桌面应用程序。其中一些只需要与本机上的其它程序
通信。在这种情况下,最好就不要用Web Service,只要用本地的API就可以了。COM非常
适合于在这种情况下工作,因为它既小又快。运行在同一台服务器上的服务器软件也是这
样。当然Web Service 也能用在这些场合,但那样不仅消耗太大,而且不会带来任何好处。
(2)局域网的一些应用程序
在许多应用中,所有的程序都是在Windows平台下使用COM,都运行在同一个局域网上。在
这些程序里,使用DCOM会比SOAP/HTTP有效得多。与此相类似,如果一个.net程序要连接
到局域网上的另一个.net程序,应该使用.net Remoting。其实在.net Remoting中,也可
以指定使用SOAP/HTTP来进行Web Service 调用。不过最好还是直接通过TCP进行RPC调用
,那样会有效得多。