用Java实现SOAP的XML文档网络传输及远程过程调用(RPC).doc_第1页
用Java实现SOAP的XML文档网络传输及远程过程调用(RPC).doc_第2页
用Java实现SOAP的XML文档网络传输及远程过程调用(RPC).doc_第3页
用Java实现SOAP的XML文档网络传输及远程过程调用(RPC).doc_第4页
用Java实现SOAP的XML文档网络传输及远程过程调用(RPC).doc_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

用Java实现基于SOAP的XML文档网络传输及远程过程调用(RPC)用Java实现基于SOAP的XML文档网络传输及远程过程调用(RPC)SOAP(Simple Object Access Protocol,简单对象访问协议) 是一种基于XML的,用于计算机之间交换信息的协议。SOAP能应用于各种消息接发系统,并能通过各种传输协议进行消息传递,但最初的侧重点是通过HTTP传输的远程过程调用。SOAP是Web service的一个重要组成部份,如果把Web service比喻成Internet,那么SOAP就可以比喻成TCP/IP。SOAP是一种协议而非具体产品,微软也有自己的SOAP实现产品,而Java下比较流行的SOAP实现产品就是Apache SOAP,不过它的下一个版本已经改名成AXIS了。 SOAP是用XML文件来做为数据转输的载体的,走HTTP的线路。一般企业的防火墙都开放HTTP的80端口,所以SOAP不会被防火墙阻断,这算是SOAP的一个优点。信息转输的双方都要求支持SOAP服务,因为XML文件发过去,则对方需要有SOAP服务来接收,然后对方会有反馈也是XML文件,这时你也需要安装SOAP服务来接收。 1. 环境配置 为了运行程序,我们首先必须配置好环境: 共要下载四个软件包,它们都是开源免费的。其中,前两个是Apache的,后两个是SUN网站的,如下所示: n SOAP:/ws/soap/version-2.3.1/ n Xerces:/dist/xerces-j/ n JavaMail:/products/javamail/downloads/index.html n JAF:/products/javabeans/glasgow/jaf.html 下载后将它们分别解压缩。分别在这四个包的解压目录中找到:xerces.jar、soap.jar、mail.jar、activation.jar(JAF的),则是四个jar文件是我们所需要的。 本机安装环境:WindowsXP(SP2) + JDK1.4.2_06 + Tomcat5.0.28 + SOAP2.3.1 配置步骤: 1、安装JDK和Tomcat。过程比较简单,这里不再详述。 2、将刚才所找到的四个jar文件复制到Tomcat的“Tomcat 5.0commonlib”目录下,这个目录是Tomcat的默认包目录,在这个目录中的所有包在Tomcat启动时都会被自动加载。 3、将 JDK1.4.2lib路径下的tools.jar也复制到Tomcat的“Tomcat 5.0commonlib”目录下。 4、将soap解压目录的webapps目录下的soap.war文件,复制到Tomcat的“Tomcat 5.0webapps”目录下,这个目录是Tomcat的WEB应用所在目录。重新启动Tomcat,Tomcat会自动将其解压,并配置好路径。可以尝试在浏览器中输入“http:/localhost:8080/soap/”, 看SOAP是否安装好。 5、注意在编写程序时,需要将所得到的四个jar文件路径设置到所使用的Java编程环境中,因为在程序中需要用到其中的类文件。具体步骤略。 6、重启Tomcat服务。这时Tomcat会将“Tomcat 5.0commonlib”目录下新加入的包加载到内存中。 到此,我们已经配置好了程序运行所需要的环境。 2. 基于SOAP的XML文档网络传输 SOAP规范主要定义了四个元素:SOAP信封规范,传输和协议绑定,编码规则和一个RPC协定。用于实现消息的网络传输。 n SOAP信封规范,SOAP信封规范对计算机间传递的数据如何封装定义了具体的规则。这包括应用特定的数据,如要调用的方法名,方法参数和返回值;还包括谁将处理封装内容,失败时如何编码错误消息等信息。 n 数据编码规则,为了交换数据,计算机必须在编码特定数据类型的规则上达成一致,SOAP也有自己的一套编码数据类型的约定。大部分约定都基于W3C XML Schema规范。 n RPC协定,SOAP能用于单向和双向等各种消息接发系统。SOAP为双向消息接发定义了一个简单的协定来进行远程过程调用和响应,这使得客户端应用可以指定远程方法名,获取任意多个参数并接受来自服务器的响应。 n 传输和协议绑定,提供了更底层协议传输SOAP封套的一套通用机制。 而以上四个部分统称为一个SOAP消息。我们先来看一篇XML文档是如何变成SOAP的。采用一个简单的购物订单文件PO.xml 。内容为: Joe Smith 14 Oak Park Bedford MA 01730 Candy Canes 444 1.68 I want candy! 其对应的SOAP消息为: POST /ServletTemp/HTTPReceive HTTP/1.0 Host: localhost Content-Type: text/xml; charset=utf-8 Content-Length: 939 SOAPAction: urn:oreilly-jaws-samples MeYou9999 Joe Smith 14 Oak Park Bedford MA 01730 Candy Canes 444 1.68 I want candy! 一个SOAP消息包括:SOAP封套,SOAP头(可选),SOAP主体。 我们首先将XML文档包装到一个SOAP体中,然后再把SOAP体包装到一个SOAP封套中,可以在封套中再添加一个SOAP头(不是必须),最后将SOAP封套绑定到一个协议中。我们来仔细分析一下代码。 n SOAP封套 SOAP封套的声明在XML标签的最外层,它表明了一个SOAP文档的边界。下面的封套标签显示了三个必要的属性,这些属性指明了封套中使用的名字空间和语法。 其中第一个属性:xmlns:SOAP-ENV=/soap/envelope/ 是一个名字空间声明,防止多个XML文件组合时发生标签名字的冲突。第二个属性声明了XML模式实例的名字空间。前缀xsi必须放在这个名字空间定义的所有元素和属性之前。最后一个属性是另外一个名字空间声明,它定义了XML Schema名字空间,这个名字空间下的元素用来指定xsi:type 属性的值(如xsd:string)。 n SOAP头 SOAP头和体在语法上非常类似。SOAP1.1和SOAP1.2都没有头里应该有些什么,它就是简单的存放一些指令,提供给接收消息的SOAP处理器。建立在SOAP之上的更高级协议(比如ebXML消息服务)就通过定义一些特殊元素来规范SOAP头的格式。另外当对RPC使用SOAP时,头部也可以用来表示一些底层信息。 MeYou9999 n SOAP主体 SOAP主体用来存放实际数据或消息的有效负载(本例中为XML文档),从而提供给最终的接受者使用或处理。 n SOAP协议绑定 当绑定到一个HTTP协议时,需要在SOAP封套前面添加HTTP头的信息。 POST /ServletTemp/HTTPReceive HTTP/1.0 Host: localhost Content-Type: text/xml; charset=utf-8 Content-Length: 939 SOAPAction: urn:oreilly-jaws-samples 在SOAP1.1中SOAPAction是HTTP绑定所必须的部分,它的目的是让那些路由或分派的信息知道该做些什么,即使它们根本不知道SOAP或者没有解析SOAP封套的方法。而在SOAP1.2中SOAPAction已变成可选的了。 n SOAP消息的发送与接收 我们已经看到了一个SOAP消息的各个组成块,接下来我们要了解消息是怎样被创建的,以及怎样在两个端点之间进行传输的。 SOAP的发送端的代码: package javaSoap01; import java.io.*; import java.util.*; public class GenericHTTPSoapClient Private static final StringDEFAULT_HOST_URL = http:/localhost:8080/ServletTemp/HTTPReceive; private static final String DEFAULT_DATA_FILENAME = ./PO.xml; private static final String URI = urn:oreilly-jaws-samples; private String m_hostURL; private String m_dataFileName; public GenericHTTPSoapClient(String hostURL, String dataFileName) throws Exception m_hostURL = hostURL; m_dataFileName = dataFileName; System.out.println(); System.out.println(_); System.out.println(Starting GenericHTTPSoapClient:); System.out.println( host url = + m_hostURL); System.out.println( data file = + m_dataFileName); System.out.println(_); System.out.println(); /实际的传送工作是由sendSOAPMessage()方法完成的 public void sendSOAPMessage() try / 首先读取XML文档,将其解析成DOM树。 FileReader fr = new FileReader (m_dataFileName); /通过调用Apache getXMlDocBuilder()方法得到一个解析器,它返回一个DocumentBuilder对象。 javax.xml.parsers.DocumentBuilder xdb = org.apache.soap.util.xml.XMLParserUtils.getXMLDocBuilder(); /通过解析器解析文档,得到一个Document对象。 org.w3c.dom.Document doc = xdb.parse (new org.xml.sax.InputSource (fr); if (doc = null) throw new org.apache.soap.SOAPException (org.apache.soap.Constants.FAULT_CODE_CLIENT, parsing error); / create a vector for collecting the header elements Vector headerElements = new Vector(); / Create a header element in a namespace org.w3c.dom.Element headerElement = doc.createElementNS(URI,jaws:MessageHeader); headerElement.setAttributeNS(URI,SOAP-ENV:mustUnderstand,1); / Create subnodes within the MessageHeader org.w3c.dom.Element ele = doc.createElement(From); org.w3c.dom.Text textNode = doc.createTextNode(Me); org.w3c.dom.Node tempNode = ele.appendChild(textNode); tempNode = headerElement.appendChild(ele); ele = doc.createElement(To); textNode = doc.createTextNode(You); tempNode = ele.appendChild(textNode); tempNode = headerElement.appendChild(ele); ele = doc.createElement(MessageId); textNode = doc.createTextNode(9999); tempNode = ele.appendChild(textNode); tempNode = headerElement.appendChild(ele); headerElements.add(headerElement); / create a vector for collecting the body elements Vector bodyElements = new Vector(); /获取顶层DOM元素,放到向量中。顶层节点的下层节点元素的创建和添加工作由DOM解析器负责。 bodyElements.add(doc.getDocumentElement (); /Create the SOAP envelope org.apache.soap.Envelope envelope = new org.apache.soap.Envelope(); /Add the SOAP header element to the envelope org.apache.soap.Header header = new org.apache.soap.Header(); header.setHeaderEntries(headerElements); envelope.setHeader(header); /Create the SOAP body element org.apache.soap.Body body = new org.apache.soap.Body(); body.setBodyEntries(bodyElements); /Add the SOAP body element to the envelope envelope.setBody(body); / Build the Message. org.apache.soap.messaging.Message msg = new org.apache.soap.messaging.Message(); msg.send (new .URL(m_hostURL), URI, envelope); System.out.println(Sent SOAP Message with Apache HTTP SOAP Client.); / 从传输中接受响应并将其打印到屏幕上 System.out.println(Waiting for response.); org.apache.soap.transport.SOAPTransport st = msg.getSOAPTransport (); BufferedReader br = st.receive (); String line = br.readLine(); if(line = null) System.out.println(HTTP POST was successful. n); else while (line != null) System.out.println (line); line = br.readLine(); catch(Exception e) e.printStackTrace(); public static void main(String args) /省略 在上述程序中,当我们构造好SOAP封套后,它需要被送到一个目的地去。在ApacheSOAP中,有一个Message对象来处理异步的单向传送。Message.send()方法有三个参数:一个URL,用于指明传送地点;一个URI,用于表示SOAPAction头的值;还有一个SOAP封套。SOAPActionURI实际上是绑定HTTP的一部分,用来指定当一个消息到达传送目的地的时候调用哪个函数或服务。 Message接口用于异步单向通信,Message.seng()函数的返回值为void型。但这并不妨碍它在双向同步会话中使用。当这个Message接口是基于一个双向传输协议(例如HTTP)实现的时候,SOAPTransport.receive()方法就能用来接收一个响应。在SOAPTransport是基于HTTP实现的情况下,receive()方法阻塞并等待一个错误(例如一个HTTP请求超时),或者一个正确的返回代码(例如“HTTP 1.0 200 OK”)。 SOAP接收端代码: public class HTTPReceive extends HttpServlet . /SOAP请求以HTTP POST形式接收 public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException System.out.println(Received request.); System.out.println(-); / Traverse the HTTP headers and show them on the screen for(Enumeration enum = request.getHeaderNames(); enum.hasMoreElements(); ) String header = (String)enum.nextElement(); String value = request.getHeader(header); System.out.println( + header + = + value); System.out.println(-); if(request.getContentLength() 0) try java.io.BufferedReader reader = request.getReader(); / 获取DocumentBuilder javax.xml.parsers.DocumentBuilder xdb = org.apache.soap.util.xml.XMLParserUtils.getXMLDocBuilder(); / 接下来我们将文件解析为一个DOM树,得到一个Document对象。 org.w3c.dom.Document doc = xdb.parse (new org.xml.sax.InputSource (reader); if (doc = null) / Error occured System.out.println(Doc is null!); throw new org.apache.soap.SOAPException (org.apache.soap.Constants.FAULT_CODE_CLIENT, parsing error); else /在接收端我们已经有了一个发送过来的SOAP封套。SOAP封套是SOAP文档的最外层元素,也是根元素。我们可以遍历这个DOM树从而直接得到封套以及它的子节点。通过调用unmarshall()方法从文件中得到一个Envelope实例。 org.apache.soap.Envelope env = org.apache.soap.Envelope.unmarshall(doc.getDocumentElement(); / 现在我们得到了一个封套,我们按照和前面相反的过程来操作它:从Envelope中取得BodyEntrys的向量Vector,然后从向量中取得Body。 org.apache.soap.Body body = env.getBody(); java.util.Vector bodyEntries = body.getBodyEntries(); java.io.StringWriter writer = new java.io.StringWriter(); for (java.util.Enumeration e = bodyEntries.elements(); e.hasMoreElements();) org.w3c.dom.Element el = (org.w3c.dom.Element)e.nextElement(); /在当前情况下,向量中只有一个条目:元素。从而我们也就得到了一个DOM对象。这个DOM对象和前面我们为建立PO.xml而建立的DOM对象完全一样。我们调用静态方法DOM2Writer.serializeAsXML()将PurchaseOrder元素及其子元素全部序列化为一个StringWriter对象。 org.apache.soap.util.xml.DOM2Writer.serializeAsXML(org.w3c.dom.Node)el, writer); System.out.println(writer.toString(); catch(Exception e) System.out.println(e); System.out.println(_); response.setContentType(text/xml); / Need this to prevent Apache SOAP from gacking n 带附件的SOAP消息 XML和SOAP能够很好的描述数据,但是许多应用程序的数据并不适合XML来描述,比如图像的二进制数据。SWA(SOAP With Attachments)可以解决这个问题。SWA把SOAP协议和MIME格式组合到一起,从而使SOAP消息可以包含任意的数据。这个模型和在email中包含附件的方法是一样的。 MIME协议允许在消息中包含任意多个数据块。每个数据块都被一个MIME头分开。在SWA中,整个消息包含多个MIME部分,第一部分(部分0)是SOAP封套,剩下的部分(1- n)都是附件。所有这些部分都包装在底层协议中。 构造带附件的SOAP:SOAP封套的创建和组装和以前一样,消息的创建议和以前一样。下面给出心田代码,它创建一个MimeBodyPart对象,然后我们从附件中读出文本作为它的内容体(假定附件为一个TXT文本文件)。 /创建消息 org.apache.soap.messaging.Message msg = new org.apache.soap.messaging.Message(); /添加附件 if(m_attachment != null) BufferedReader attachmentReader = new BufferedReader(new FileReader(m_attachment); StringBuffer buffer = new StringBuffer(); for(String line = attachmentReader.readLine(); line != null; line = attachmentReader.readLine() buffer.append(line); MimeBodyPart attachment = new MimeBodyPart(); attachment.setText(buffer.toString(); 接下来,我们需要让接收端能够引用附件。为了使接收端能够分析这个消息,我们在XML文档中添加了一个元素,它用the-attachment作为href的值。我们用这个值作为附件的content-id. attachment.setHeader(Content-ID, the-attachment); 最后,我们在消息中添加附件部分然后发送。Apache SOAP会知道你在消息中添加了附件,并且会正确的转化为消息格式: msg.addBodyPart(attachment); msg.send (new .URL(m_hostURL), URI, envelope); System.out.println(Sent SOAP Message with Apache HTTP SOAP Client.); 接收带附件的SOAP: /处理SOAP体 org.apache.soap.Body body = requestEnvelope.getBody(); java.util.Vector bodyEntries = body.getBodyEntries(); writer.write(nBody=n); for (java.util.Enumeration e = bodyEntries.elements(); e.hasMoreElements();) org.w3c.dom.Element el = (org.w3c.dom.Element)e.nextElement(); org.apache.soap.util.xml.DOM2Writer.serializeAsXML(org.w3c.dom.Node)el, writer); 我们通过XML文档中的元素来查找附件。首先我们通过名字查找attachment元素。然后我们取出href属性中的content-id的值。一旦我们得到了id,就能够使用SOAPContext对象中的getBodyPart()方法,通过content-id来查找MIME附件。 org.w3c.dom.Element attachmentEl = (org.w3c.dom.Element)el.getElementsByTagName(attachment).item(0); if (attachmentEl != null) writer.write(nAttachment=n); cid = attachmentEl.getAttribute(href).substring(4);/get rid of cid: writer.write(Content-ID = +cid+n); MimeBodyPart attachment = requestContext.getBodyPart(cid); try writer.write(The attachment is.n+attachment.getContent()+n); catch(Exception ex) throw new SOAPException(Constants.FAULT_CODE_SERVER, Error writing response, ex); else writer.write(The Content-ID is null!n); System.out.println(writer.toString(); 3. 基于SOAP的远程过程调用(RPC) SOAP-RPC使用SOAP底层结构定义了一个用来表示RPC以及RPC响应的模型。它并不要求一定要紧紧地绑定一个同步的请求/响应模型或者一个HTTP协议。实际上SOAP1.1和1.2规范都明确声明了SOAP-RPC的使用和协议的绑定是无关的。规范承认,当SOAP-RPC绑定到HTTP时,RPC调用就自动和HTTP请求相匹配,但是这个匹配纯粹是偶然的。因此真正重要的是SOAP定义了一个统一的模型,来表示RPC及其一个或多个返回值。RPC调用的基本要求是,体元素包含方法名和参数,并且参数可以通过存取方法来访问。SOAP还提供了对方法签名,头数据和代表目的地的URI进行编码的方法。 我们先来看一个SOAP-RPC的发送端内容: POST /soap/s

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论