Presentation is loading. Please wait.

Presentation is loading. Please wait.

第 五 讲 Web 服务.

Similar presentations


Presentation on theme: "第 五 讲 Web 服务."— Presentation transcript:

1 第 五 讲 Web 服务

2 内 容 一、Web 服务简介 二、SOAP 三、WSDL 四、支持Web 服务的J2EE应用

3 一、Web 服务简介 2000年 Microsoft 等提出“Web Services” Web服务(Web Services)
是基于 XML 和 HTTP 的一种服务 服务访问协议: SOAP 服务的描述: WSDL 服务查找与发现: UDDI

4 SOAP (Simple Object Access Protocol)
XML-based (text) 协议 支持远程通信 平台中立 WSDL (Web Services Definition Language) 接口描述 UDDI (Universal Description, Discovery, and Integration) 用于Web Services注册 用于发现Web Services

5 基本结构: 服务信息注册库 查找 注册 请求/应答 客户/服务请求者 服务提供者

6 提供了软件模块之间一种松耦合的交互方式 根据需求通过网络对松散耦合的粗粒度应用组件进行分布式部署、组合和使用 服务层是SOA的基础,可以直接被应用调用,从而 有效控制系统中与软件代理的人为依赖性 SOA的几个关键特性:一种粗粒度、松耦合服务架构,服务之间通过简单、精确定义适配器进行通讯,不涉及 底层编程适配器和通讯模型

7 RPC vs. Document RPC Document 耦合密切些 仅仅是调用 耦合松散些 需要额外的设计工作 相对脆弱
对应用修改适应性好 没有序列化/反序列化问题 需要额外的设计工作 需要解释客户消息内容,然后进行相应操作

8 考虑 Web Services的几个理由 业务上 技术上 管理上 需要与外部客户通信 应用需要与 其它语言编写的 客户程序通信
客户在防火墙之外 管理上 管理托管 web service 应用

9 什么时候不要使用Web Services 客户程序与应用使用相同语言编写 通信开销大
序列化或者远程访问开销大 Web Services/XML 处理开销大 “Don’t Use XML to Communicate Unless You Really, Really Have To” – Floyd Marinescu, The Middleware Company 永远记住:Web Services/XML 是用于集成的

10 典型的 Web 服务支持平台 Apache Axis (Apache eXtensible Interaction System)
是Apache WebService项目中的子项目 最初起源于IBM的"SOAP4J“ 最早的一批用于构造基于SOAP应用的Framework JBoss, WAS等重要的应用服务器都集成它

11 服务器端AXIS 句柄链处理架构 用户配置一系列的 handler,构成 handler chain
AXIS 依次调用 handler 处理消息(含 context) 类似于 interceptor(截取器)

12 客户端AXIS 句柄链处理架构

13 AXIS的子系统

14 二、SOAP 1、SOAP概述 2、数据表示 3、消息格式 4、协议映射

15 1、SOAP概述 许多程序通过使用远程过程调用(RPC) 在诸如 DCOM 与 CORBA 等对象之间进行通信
防火墙和代理服务器通常会阻止此类流量 通过 HTTP 在应用程序间通信是更好的方法 因为 HTTP 得到了所有的因特网浏览器及服务器的支持 SOAP 就是被创造出来完成这个任务的

16 2000年5月,UserLand、Ariba、Commerce One、Compaq、Developmentor、HP、IBM、IONA、Lotus、Microsoft 以及 SAP 向 W3C 提交了 SOAP 因特网协议 期望此协议能够通过使用因特网标准(HTTP 以及 XML)把图形用户界面桌面应用程序连接到因特网服务器 首个关于 SOAP 的公共工作草案由 W3C 在 2001 年 12 月发布 SOAP 1.2 于 2003 年 6 月 被发布为 W3C 推荐标准

17 简单对象访问协议(SOAP) 是网络环境中交换信息的简单协议 为网络环境下软件之间结构化、类型化信息的交换 提供了一种基于XML的机制 它可以广泛地用于基于消息的系统和基于RPC的系统 SOAP被设计为可以与各种其它协议结合使用 但目前SOAP主要和HTTP及HTTP扩展框架相结合

18 简单地讲,SOAP= HTTP+RPC+ XML
以RPC作为一致性的调用途径 以XML作为数据传送的格式 SOAP的设计原则是: 简单、易于扩展 SOAP的设计忽略了如下几方面的功能: (1)分布式垃圾回收 (2)消息的批处理 (3)对象引用 (4)对象激活

19 2、数据表示 SOAP的数据表示完全不同于以往互操作协议的表示方法 以往的互操作协议都将调用语句编排为 二进制的字节流的形式
SOAP采用XML作为自己的数据表示方法 XML是与HTML类似的基于文本的标记语言 SOAP将调用语句编排为文本式的字符流的形式

20 3、消息格式 SOAP消息是一个XML文档 包括: 一个必需的SOAP封装 一个可选的SOAP头 一个必需的SOAP体

21 (1)SOAP封装 SOAP封装定义了描述信息和如何处理信息的框架 用于指定用XMLSchema来描述XML数据的编码规则
封装可以包含名域声明和附加属性 如果包含附加属性,这些属性必须限定名字域 类似的,“Envelope”可以包含附加子元素 这些也必须限定名字域且跟在SOAP体元素之后

22 (2)SOAP消息头 SOAP消息头是SOAP消息的可选部分 用来扩展其它诸如安全、事务等服务的重要机制

23 (3)SOAP体 SOAP体在SOAP消息中必须出现 且必须是SOAP封装元素的直接子元素 SOAP体可以包括多个条目

24 SOAP自然地遵循HTTP的请求/应答消息模型
表示通信状态信息的HTTP状态码的语义 例如,2xx状态码表示 这个包含了SOAP组件的客户请求 已经被成功的收到、理解和接受 下页的代码是一个使用POST的SOAP HTTP例子 该消息通过HTTP发出一条请求 “获取股票代码为ABC的最新交易价格”

25 POST /StockQuote HTTP/1.1
Host: Content-Type: text/xml; charset="utf-8" Content-Length: nnnn SOAPAction: "Some-URI" <SOAP-ENV:Envelope xmlns:SOAP-ENV=" SOAP-ENV:encodingStyle=" <SOAP-ENV:Header> <t:Transaction xmlns:t="some-URI" SOAP-ENV:mustUnderstand="1"> 5 </t:Transaction> </SOAP-ENV:Header> <SOAP-ENV:Body> <m:GetLastTradePrice xmlns:m="Some-URI"> <symbol>ABC</symbol> </m:GetLastTradePrice> </SOAP-ENV:Body> </SOAP-ENV:Envelope>

26 与其它协议的比较 1、互操作开销不同 IIOP、JRMP使用二进制的字节流形式编排消息 (CDR、XDR)
SOAP采用字符型的XML编排消息 SOAP消息要比IIOP、JRMP消息长得多 SOAP的编排开销大、占用内存空间大 2、表达能力不同 SOAP易于学习、易于开发、易于调试 SOAP不支持消息的批处理、对象引用、对象激活等特性 降低了SOAP的表达能力 并使得基于SOAP的交互受到限制 而IIOP、JRMP等则不存在这种限制

27 3、适应能力不同 IIOP、JRMP严重制约于防火墙 防火墙一般由两个路由器与一个应用程序网关构成 路由器负责IP层的分组信息 列出可接受、禁止的源端和目标端等信息 应用程序网关在应用程序级进行控制 根据头信息字段、消息长度、消息内容等 决定传送还是丢弃消息 这是IIOP、JRMP的应用受到限制的核心因素之一 SOAP则基本不受其限制 4、适用环境不同 JRMP适用于使用JAVA的应用系统 IIOP、SOAP支持各种语言,因此适用面更广 IIOP适合于同一个防火墙内部之间的交互 而SOAP则适合于跨越防火墙的交互

28 三、WSDL 1、概述 2、文档结构 3、例子 4、向SOAP的映射

29 1、概述 WSDL(Web Services Description Language)是一个建议性标准
在Microsoft的SDL(Service Description Language和SCL(SOAP Contract Language)和IBM的NASSL(Network Accessible Service Specification Language)这两项技术的结合,形成了WSDL的基础 2000年9月25日IBM、Microsoft和Ariba提出WSDL1.0 2001年3月15日,他们提交的WSDL1.1成为W3C的Note 2002年7月9日提出 WSDL 1.2 2003年11月10日提出 WSDL 2.0

30 2、文档结构 WSDL 文档 类型 消息 端口类型 操作 绑定 操作 服务 端口 代表依赖关系 代表包含关系

31 (1)抽象定义 类型:独立于计算机和语言的类型定义 使用某一类型系统(例如XSD)进行数据类型定义的容器 用于描述被交换的消息
消息:对通信数据的一个抽象、类型化定义 一个消息包含多个逻辑部分 每一个都与某一个类型系统中的定义相关联 包含函数参数(输入与输出分开)或文档说明 端口类型:由一个或多个端点支持操作的抽象集合 每个操作对应于一个输入消息与一个输出消息 它引用消息节中的消息定义来说明函数基调 操作名称、输入参数和输出参数 等

32 (2)具体说明 绑定:为一个由特定端口类型定义的操作与消息 指定具体的协议及数据格式规范 服务:指定每个绑定的端口地址

33 3、例子 <?xml version="1.0" encoding="UTF-8" ?>
<definitions name="FooSample" <types> <schema targetNamespace=" xmlns=" xmlns:SOAP-ENC=" xmlns:wsdl=" elementFormDefault="qualified" > </schema> </types>  <message name="Simple.foo"> <part name="arg" type="xsd:int"/> </message> <message name="Simple.fooResponse"> <part name="result" type="xsd:int"/> <portType name="SimplePortType"> <operation name="foo" parameterOrder="arg" > <input message="wsdlns:Simple.foo"/> <output message="wsdlns:Simple.fooResponse"/> </operation> </portType> 

34 <binding name="SimpleBinding" type="wsdlns:SimplePortType">
<stk:binding preferredEncoding="UTF-8" /> <soap:binding style="rpc" transport=" <operation name="foo"> <soap:operation soapAction=" <input> <soap:body use="encoded" namespace=" encodingStyle=" /> </input> <output> <soap:body use="encoded" </output> </operation> </binding>  <service name="FOOSAMPLEService"> <port name="SimplePort" binding="wsdlns:SimpleBinding"> <soap:address location=" </port> </service> </definitions>

35 用OMG-IDL表示为: interface FooSample { long foo(long arg); }

36 4、向SOAP的映射 对应的SOAP请求消息为:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <SOAP-ENV:Envelope SOAP-ENV:encodingStyle=" xmlns:SOAP-ENV=" <SOAP-ENV:Body> <m:foo xmlns:m=" <arg> </arg> </m:foo> </SOAP-ENV:Body> </SOAP-ENV:Envelope>

37 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=" xmlns:SOAP-ENV=" <SOAP-ENV:Body> <SOAPSDK1:fooResponse mlns:SOAPSDK1=" <result> </result> </SOAPSDK1:fooResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>

38 与其它描述方法的比较 1、描述对象不同 有的以描述结构化程序的功能为主 例如 RPC-IDL 微软的-IDL 有的以描述对象的功能为主
例如 CORBA的IDL 有的以描述服务为主 例如 web service的WSDL

39 2、描述方式不同 有的以具体计算机语言的方式表达 例如SUN的Java Interface 有的以独立于具体的计算机语言
但十分类似于计算机语言的方式表达 例如:RPC-IDL 微软的-IDL CORBA的IDL 有的以XML为方式表达 例如:web service的WSDL

40 3、描述内容不同 有的仅描述接口的语法信息 例如:RPC-IDL 微软的-IDL CORBA的IDL 有的还包括与底层协议的绑定信息
例如:WSDL等 在CORBA中这部分信息包含在IOR中

41 四、支持Web 服务的J2EE应用 如何为 web 系统增加web services接口 下面模块可以暴露为 Web Services:
EJB POJO 后面的例子针对 EJB

42 JAX-RPC: Java API for XML-based RPC Java世界的 web service 编程模型规范
如何以类似 RPC 的方式调用 web service JAX—RPC的客户端编程模式有以下的三种: Static stub(静态的客户端存根调用) Dynamic proxy (部分动态的代理调用) Dynamic invocation interface (DII)(动态调用接口)

43 三种JAX—RPC的客户端编程模式

44 Static stub 1) 首先通过映射转换将服务描述的WSDL文档生成客户端的Java stub
2) 然后实例化服务的locator实例 3) 通过loacator获得服务在客户端的代理 4) 用客户端代理 去调用服务

45 package itso.test; import java.io.*; import java.util.*; import itso.test.*; public class WeatherForecastClient { public static void main(String [] args) { try{ WeatherForecastServiceLocator wsl = new WeatherForecastServiceLocator(); WeatherForecastService ws = (WeatherForecastService) wsl.getWeather(); String temperature = ws.getTemperature(); System.out.println(temperature); System.out.println("WeatherForecastClient completed"); } catch (Exception e) { e.printStackTrace(); }

46 Dynamic proxy 与Static stub 不同的是可以指定生成的客户端代理
import javax.xml.namespace.QName; import java.io.*; import java.util.*; public class WeatherForecastDynamicProxyClient { public static void main(String [] args){ try{ WeatherForecastServiceLocator wsl = new WeatherForecastServiceLocator(); QName qn = new QName(" WeatherForecast ws = (WeatherForecast) wsl.getPort(qn,WeatherForecast.class); String temperature = ws.getTemperature(); System.out.println(temperature); System.out.println("DynamicProxyJavaClient completed"); } catch (Exception e){ e.printStackTrace(); } }

47 一个汽车网站的例子 例子构成: 暴露对象: InventoryFacadeBean.findAllAvailableCars() JSPs
Controller Servlet Stateless Session Bean – InventoryFacadeBean Hibernate DAOs 暴露对象: InventoryFacadeBean.findAllAvailableCars()

48 服务端点接口 将业务方法暴露为Web Services 类似于服务器端的 stub 类似于 EJB Remote Interface
package com.jbossatwork.ws; /** * Service endpoint interface for InventoryFacade. */ public interface InventoryEndpoint extends java.rmi.Remote{ public com.jbossatwork.ws.CarDTOArray findAvailableCars() throws java.rmi.RemoteException; } // InventoryEndpoint.java

49 修改 ejb-jar.xml <enterprise-beans> … <session>
<display-name>InventoryFacadeSB</display-name> <ejb-name>InventoryFacade</ejb-name> <service-endpoint> com.jbossatwork.ws.InventoryEndpoint </service-endpoint> </session> </enterprise-beans>

50 webservices.xml 定义并注册 InventoryService Web Service
将Service Endpoint Interface class 绑定到InventoryFacadeBean EJB 告诉 J2EE app server 到哪里找WSDL 与JAX-RPC 映射文件(Mapping files, in EJB JAR file)

51 <?xml version="1.0" encoding="UTF-8"?>
<webservices xmlns=" xmlns:xsi=" xsi:schemaLocation=" version="1.1"> <webservice-description> <webservice-description-name> InventoryService </webservice-description-name> <wsdl-file>META-INF/wsdl/InventoryService.wsdl</wsdl-file> <jaxrpc-mapping-file> META-INF/inventory-mapping.xml </jaxrpc-mapping-file> <port-component> <port-component-name>Inventory</port-component-name> <wsdl-port>InventoryEndpointPort</wsdl-port> <service-endpoint-interface> com.jbossatwork.ws.InventoryEndpoint </service-endpoint-interface> <service-impl-bean> <ejb-link>InventoryFacade</ejb-link> </service-impl-bean> </port-component> </webservice-description> </webservices>

52 JAX-RPC 映射文件 帮助 JAX-RPC 编译器将Java 对象映射到WSDL 对象
复杂的Java 对象导致复杂的JAX-RPC 与WSDL 文件

53 <?xml version="1.0" encoding="UTF-8"?>
<java-wsdl-mapping xmlns=" xmlns:xsi=" xsi:schemaLocation=" version="1.1"> <package-mapping> <package-type>com.jbossatwork.ws</package-type> <namespaceURI> </package-mapping> <namespaceURI> <java-xml-type-mapping> <java-type>com.jbossatwork.dto.CarDTOArray</java-type> <root-type-qname xmlns:typeNS=" typeNS:CarDTOArray </root-type-qname> <qname-scope>complexType</qname-scope> <variable-mapping> <java-variable-name>cars</java-variable-name> <xml-element-name>cars</xml-element-name> </variable-mapping> </java-xml-type-mapping>

54 <java-xml-type-mapping>
<java-type>com.jbossatwork.dto.CarDTO</java-type> <root-type-qname xmlns:typeNS=" typeNS:CarDTO </root-type-qname> <qname-scope>complexType</qname-scope> <variable-mapping> <java-variable-name>id</java-variable-name> <xml-element-name>id</xml-element-name> </variable-mapping> <java-variable-name>make</java-variable-name> <xml-element-name>make</xml-element-name> <java-variable-name>model</java-variable-name> <xml-element-name>model</xml-element-name> <java-variable-name>modelYear</java-variable-name> <xml-element-name>modelYear</xml-element-name>

55 <variable-mapping>
<java-variable-name>status</java-variable-name> <xml-element-name>status</xml-element-name> </variable-mapping> </java-xml-type-mapping> <service-interface-mapping> <service-interface>com.jbossatwork.ws.InventoryService</service-interface> <wsdl-service-name xmlns:serviceNS=" serviceNS:InventoryService </wsdl-service-name> <port-mapping> <port-name>InventoryEndpointPort</port-name> <java-port-name>InventoryEndpointPort</java-port-name> </port-mapping> </service-interface-mapping>

56 <service-endpoint-interface-mapping>
com.jbossatwork.ws.InventoryEndpoint </service-endpoint-interface> <wsdl-port-type xmlns:portTypeNS=" portTypeNS:InventoryEndpoint </wsdl-port-type> <wsdl-binding xmlns:bindingNS=" bindingNS:InventoryEndpointBinding </wsdl-binding> <service-endpoint-method-mapping> <java-method-name>findAvailableCars</java-method-name> <wsdl-operation>findAvailableCars</wsdl-operation> <wsdl-return-value-mapping> <method-return-value>com.jbossatwork.dto.CarDTOArray</method-return-value> <wsdl-message xmlns:wsdlMsgNS=" wsdlMsgNS:InventoryEndpoint_findAvailableCarsResponse </wsdl-message> <wsdl-message-part-name>result</wsdl-message-part-name> </wsdl-return-value-mapping> </service-endpoint-method-mapping> </service-endpoint-interface-mapping> </java-wsdl-mapping>

57 WSDL File <?xml version="1.0" encoding="UTF-8"?>
<definitions name="InventoryService" targetNamespace=" xmlns:tns=" xmlns=" xmlns:xsd=" xmlns:ns2=" xmlns:soap=" <types> <schema targetNamespace=" xmlns:tns= xmlns:soap11-enc=" xmlns:xsi=" xmlns:wsdl=" xmlns=" <complexType name="CarDTOArray"> <sequence> <element name="cars" type="tns:CarDTO" nillable="true" minOccurs="0" maxOccurs="unbounded"/></sequence> </complexType>

58 <complexType name="CarDTO">
<sequence> <element name="id" type="int"/> <element name="make" type="string" nillable="true"/> <element name="model" type="string" nillable="true"/> <element name="modelYear" type="string" nillable="true"/> <element name="status" type="string" nillable="true"/> </sequence> </complexType> </schema> </types> <message name="InventoryEndpoint_findAvailableCars"/> <message name="InventoryEndpoint_findAvailableCarsResponse"> <part name="result" type="ns2:CarDTOArray"/></message> <portType name="InventoryEndpoint"> <operation name="findAvailableCars"> <input message="tns:InventoryEndpoint_findAvailableCars"/> <output message="tns:InventoryEndpoint_findAvailableCarsResponse"/> </operation> </portType>

59 <binding name="InventoryEndpointBinding" type="tns:InventoryEndpoint">
<soap:binding transport=" style="rpc"/> <operation name="findAvailableCars"> <soap:operation soapAction=""/> <input> <soap:body use="literal" namespace=" </input> <output> </output> </operation> </binding> <service name="InventoryService"> <port name="InventoryEndpointPort" binding="tns:InventoryEndpointBinding"> <soap:address location="REPLACE_WITH_ACTUAL_URL"/> </port> </service> </definitions>

60 修改 WSDL URL <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss PUBLIC "-//JBoss//DTD JBOSS 4.0//EN" " <jboss> <enterprise-beans> <session> <ejb-name>InventoryFacade</ejb-name> <port-component> <port-component-name>Inventory</port-component-name> <port-component-uri> jbossatwork-ws/InventoryService </port-component-uri> </port-component> </session> </enterprise-beans> </jboss>

61 修改 EJB /** * @ejb.bean * name="InventoryFacade" * … * view-type="all"
* … * view-type="all" * … * * name="Inventory" * wsdl-port="InventoryEndpointPort" * service-endpoint-interface="com.jbossatwork.ws.InventoryEndpoint" * service-endpoint-bean="com.jbossatwork.ejb.InventoryFacadeBean" * service-endpoint-class="com.jbossatwork.ws.InventoryEndpoint" */ public class InventoryFacadeBean implements SessionBean {

62 /** * view-type="all" * … * */ public CarDTOArray findAvailableCars() throws EJBException { CarDTOArray carDTOArray = new CarDTOArray(); CarDTO[] cars = (CarDTO[]) listAvailableCars().toArray(new CarDTO[0]); carDTOArray.setCars(cars); return carDTOArray; } * view-type="both" public List listAvailableCars() throws EJBException {

63 Web Services 与 Collections
WSDL/XSD 不懂 Java Collections package com.jbossatwork.dto; import java.io.Serializable; import com.jbossatwork.dto.CarDTO; public class CarDTOArray implements Serializable { private CarDTO[] cars; public CarDTOArray() {} public CarDTO[] getCars() { return cars; } public void setCars(CarDTO[] cars) { this.cars = cars;

64 EJB JAR 文件结构 META-INF/ com/jbossatwork/ws/ ejb-jar.xml jboss.xml
webservices.xml inventory-mapping.xml (JAX-RPC Mapping File) wsdl/ InventoryService.wsdl com/jbossatwork/ws/ InventoryEndpoint.class

65 客户端:产生 Web Service Proxy 代码
<path id="axis.classpath"> <fileset dir="${axis.lib.dir}"> <include name="**/*.jar"/> </fileset> </path> <target name="run-wsdl2java" description="Generates WS proxy code from WSDL"> <path id="wsdl2java.task.classpath"> <path refid="axis.classpath"/> <wsdl2java output="${gen.source.dir}" url="InventoryService.wsdl" verbose="true"> <mapping namespace=" package="com.jbossatwork.client"/> <mapping namespace=" </wsdl2java> </target>

66 客户代码( J2SE 1.4 ) package com.jbossatwork.client;
public class MyAxisClient { public static void main(String [] args) { try { System.out.println("Finding InventoryService ...\n"); InventoryService service = new InventoryServiceLocator(); System.out.println("Getting InventoryEndpoint ...\n"); InventoryEndpoint endpoint=service.getInventoryEndpointPort(); System.out.println("Getting Cars ..."); CarDTOArray carDTOArray = endpoint.findAvailableCars(); CarDTO[] cars = carDTOArray.getCars(); for (int i = 0; i < cars.length; ++i) { System.out.println( "Year = [" + cars[i].getModelYear() + "], Make = [" + cars[i].getMake() + "], Model = [" + ars[i].getModel() + "], status = [" + cars[i].getStatus() + "]"); } } catch(Exception e) { e.printStackTrace(); 客户代码( J2SE 1.4 )


Download ppt "第 五 讲 Web 服务."

Similar presentations


Ads by Google