乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Web Service深度編程——Axis序列化/反序列化器開發(fā)指南

       Elena 2006-05-16

      Web Service深度編程——Axis序列化/反序列化器開發(fā)指南

      作者:薛谷雨

      作者簡介

      薛谷雨是NORDSAN(北京)信息科技開發(fā)有限公司高級JAVA研發(fā)工程師,正致力于企業(yè)級異構(gòu)數(shù)據(jù)交換的服務(wù)器產(chǎn)品的研發(fā),在J2EE和WEB SERVICE方面有較為豐富的開發(fā)經(jīng)驗,你可以通過 rainight@126.com 與他取得聯(lián)系。

      前言

      Axis是Apache組織推出的SOAP引擎,Axis項目是Apache組織著名的SOAP項目的后繼項目。Axis為開發(fā)者提供了大量的序列化/反序列化器,能夠基本滿足大部分應(yīng)用。但在某些情況下,對特定的對象,現(xiàn)有的序列化/反序列化器不能勝任,于是只有開發(fā)人員自己實現(xiàn)專用于此對象的序列化/反序列化器插入到Axis中來完成序列化工作。考慮到Web Service是一門新興技術(shù),中文資料大多是泛泛的講解,關(guān)于序列化/反序列化器的開發(fā)鮮有較為深入的介紹,本文提供一份較為完整的開發(fā)指南,并提供了一個十分有用的實現(xiàn),即序列化JDOM模型的Element,使其可以通過Web 服務(wù)在網(wǎng)絡(luò)上傳輸,我想這一擴展是許多采用JDOM作為XML解析工具的開發(fā)人員都夢寐以求的功能。通過本文的介紹和實例,希望能起到拋磚引玉的作用,讀者在閱讀完本文之后可以輕松的實現(xiàn)針對于任何非符合BEAN規(guī)范的對象的序列化/反序列化器。

      本文所面對的讀者需要有一定的使用Axis做Web服務(wù)開發(fā)的開發(fā)經(jīng)驗,因此關(guān)于如何Axis的基礎(chǔ)知識并不在本文的介紹范圍,如果讀者對此感興趣,可以參考本文最后的參考資料部分,去相應(yīng)的網(wǎng)站進(jìn)行學(xué)習(xí)。

      序列化/反序列化器簡介

      序列化/反序列化器在英文中的對應(yīng)翻譯是Serializer/Deserializer,一個序列化器的功能是遵循一定的映射規(guī)則和編碼風(fēng)格,將一種類型的JAVA對象通過某種特定的機制,轉(zhuǎn)換成為XML描述的形式;反序列化器的功能是序列化器所做工作的逆操作,兩者相輔相成,成對出現(xiàn)。Axis中的序列化/反序列化器采用設(shè)計范式中的工廠模式,每一個Serializer唯一對應(yīng)一個SerializerFactory;每一個Deserializer唯一對應(yīng)一個DeserializerFactory。一種類型的JAVA對象具體要采用哪個序列化/反序列化器需要在提供Web服務(wù)的服務(wù)器和調(diào)用Web服務(wù)的客戶端分別配置,關(guān)于這一部分如何配置,我將在本文后面的內(nèi)容中進(jìn)行詳細(xì)介紹。Axis已經(jīng)為開發(fā)者提供了豐富的序列化/反序列化器,對于java的基本數(shù)據(jù)類型,絕大部分常用的容器類(比如數(shù)組類型,Vector類型等)都提供了實現(xiàn),特別是提供了對W3C的DOM對象(比如Document, Element等)和符合Bean規(guī)范的JAVA對象提供了功能完善的序列化/反序列化器,因此我們在需要的時候只要在配置文件中配置一下就可以直接使用。如果對象中包含其它類型的對象,比如Vector中包含一組Bean對象,Axis會自動疊代的調(diào)用序列化器,最終拼裝成唯一的XML表述。在還原成JAVA對象時,也遵循這樣的疊代操作逆向進(jìn)行。關(guān)于Axis到底內(nèi)置了哪些序列化/反序列化器,您可以參照Axis的API文檔中包org.apache.axis.encoding.ser下的類的名稱"望文生義"的了解一下,在以后的開發(fā)中做到心中有數(shù)。但對于一些特殊類型的對象(其實我們自己開發(fā)的很大一部分類都是這種特殊類型的對象,很少有絕對符合Bean規(guī)范的),需要通過Web服務(wù)進(jìn)行傳遞,我們不得不開發(fā)自己的序列化/反序列化器。

      開發(fā)篇

      開發(fā)自己的序列化/反序列化器是一個激動人心的工作,但是卻并不復(fù)雜,需要做的事情包括實現(xiàn)名成為org.apache.axis.encoding的包中的SerializerFactory,Serializer,DeserializerFactory和Deserializer這四個接口。下面我將結(jié)合一個實例來講解序列化/反序列化器的開發(fā)方法,希望讀者能夠一邊參看本文提供的源代碼一邊學(xué)習(xí)。

      JDOM作為一款比較"另類"的XML解析工具(因為它不符合W3C的DOM模型,自己另立一套)默默地占領(lǐng)著java世界里的xml解析器的半壁江山,由于其簡潔的設(shè)計和方便靈活的API調(diào)用,已經(jīng)漸漸成為了許多開發(fā)人員在進(jìn)行XML開發(fā)的首選。但是Axis是建立在W3C的DOM模型的基礎(chǔ)之上,師出名們正派,自然不屑與JDOM為伍。因此當(dāng)開發(fā)人員想將自己已經(jīng)寫好的基于JDOM的應(yīng)用模塊采用Web服務(wù)的方式發(fā)布的時候,不可避免的會遇到如何將JDOM模型下的對象如Document, Element等序列化的問題。在軟件工程師不會自己擴展Axis的序列化/反序列化器的時候,我們只能有兩個辦法達(dá)到這個目的,第一個就是更改以前應(yīng)用模塊內(nèi)的API設(shè)計,使暴露的入口參數(shù)和返回值參數(shù)都是W3C的對象類型,但這種做法并不現(xiàn)實,因為這一應(yīng)用模塊往往不是獨立存在,牽一發(fā)將動全身,導(dǎo)致舊有系統(tǒng)架構(gòu)的崩塌;另一種做法就是為這個模塊做一個代理類,它做的工作就對外接收或返回DOM模型的對象,對內(nèi)轉(zhuǎn)換成JDOM模型的對象,然后轉(zhuǎn)發(fā)給應(yīng)用模塊,繁瑣且效率低下。當(dāng)我們向Axis注入了針對于JDOM模型的序列化/反序列化器后,這一工作便可以由Axis代勞了。下面我們將逐個開發(fā)這四個類:

      JDomElementSerializerFactory

      JDomElementSerializerFactory是一個工廠類,需要通過某種機制注冊到Axis引擎(具體方法見下面"服務(wù)器端應(yīng)用篇");Axis通過調(diào)用它,來實例化JDomElementSerializer。Axis 提供了BaseSerializerFactory,這個類是一個抽象類,并實現(xiàn)其中包含了一些可重用的代碼。我們自己開發(fā)的工廠類只需簡單繼承這個類就可以。構(gòu)造函數(shù)中需要調(diào)用父類的構(gòu)造函數(shù)將序列器類下面是它的源代碼:

      package org.apache.axis.encoding.ser;
      public class JDomElementSerializerFactory
      extends BaseSerializerFactory {
      public JDomElementSerializerFactory() {
      super(JDomElementSerializer.class);
      }
      }
      

      JDomElementSerializer

      JDomElementSerializer實現(xiàn)org.apache.axis.encoding.Serializer接口,其核心API是serialize(),我們需要在這個方法的內(nèi)部完成對JDOM模型的Element的序列化工作,序列化的結(jié)果要保存在入口參數(shù)傳入的序列化上下文對象(SerializationContext)中:

      public void serialize(QName name, Attributes attributes, Object value,
      SerializationContext context) throws java.io.IOException {
      if (!(value instanceof Element))
      throw new IOException(
      Messages.getMessage("cant Serialize Object"));
      //獲取符合JDOM的Element對象
      Element root=(Element)value;
      //輸出到StringWriter
      XMLOutputter outputter=new XMLOutputter();//創(chuàng)建一個JDOM的XML輸出器
      StringWriter sw=new StringWriter();
      outputter.output(root,sw);
      //用支持W3C的DOM模型的Xerces解析器解析文本流
      DOMParser parser=new DOMParser();//創(chuàng)建一個DOM的XML解析器
      try {
      parser.parse(new org.xml.sax.InputSource(
      new java.io.StringReader(sw.toString())));
      }catch (Exception ex) {
      throw new java.io.IOException("序列化時產(chǎn)生錯誤");
      }
      //獲取符合DOM模型的Element對象
      org.w3c.dom.Element w3c_root =
      parser.getDocument().getDocumentElement();
      //放入序列化上下文對象中
      context.startElement(name, attributes);
      context.writeDOMElement(w3c_root);
      context.endElement();
      }
      

      JDomElementDeserializerFactory

      反序列化器的工廠類同序列化器的工廠類一樣的設(shè)計,在此不在贅述。代碼:

      package org.apache.axis.encoding.ser;
      public class JDomElementDeserializerFactory
      extends BaseDeserializerFactory {
      public JDomElementDeserializerFactory() {
      super(JDomElementDeserializer.class);
      }
      }
      

      JDomElementDeserializer

      用過SAX解析XML的讀者,對反序列化的實現(xiàn)比較容易理解,反序列化也采用了消息觸發(fā)的機制,我們只需繼承org.apache.axis.encoding.DeserializerImpl類,并覆蓋其中的onEndElement方法:

      /**
      * 在元素結(jié)束觸發(fā)反序列化的方法
      * @param namespace String 命名空間
      * @param localName String 本地名稱
      * @param context DeserializationContext 反序列化上下文
      * @throws SAXException
      */
      public void onEndElement(String namespace, String localName,
      DeserializationContext context) throws SAXException {
      try {
      //從反序列化上下文對象中獲取原始的消息元素
      MessageElement msgElem = context.getCurElement();
      if (msgElem != null) {
      MessageContext messageContext = context.getMessageContext();
      Boolean currentElement = (Boolean) messageContext.getProperty(
      DESERIALIZE_CURRENT_ELEMENT);
      //如果當(dāng)前的消息元素本身需要反序列化
      if (currentElement != null && currentElement.booleanValue()) {
      org.w3c.dom.Element element = msgElem.getAsDOM();
      org.jdom.input.DOMBuilder db=new org.jdom.input.DOMBuilder();
      value=db.build(element);
      messageContext.setProperty(DESERIALIZE_CURRENT_ELEMENT,
      Boolean.FALSE);
      return;
      }
      //反序列化消息元素中的消息體
      java.util.ArrayList children = msgElem.getChildren();
      if (children != null) {
      //取得消息體
      msgElem = (MessageElement) children.get(0);
      if (msgElem != null) {
      org.w3c.dom.Element ret = msgElem.getAsDOM();
      org.jdom.input.DOMBuilder db=new org.jdom.input.DOMBuilder();
      //用DOMBuilder將DOM模型的Element,轉(zhuǎn)換成JDOM模型的Element
      value=db.build(ret);
      }
      }
      }
      }
      catch (Exception ex) {
      //錯誤,則記日志,并拋SAXException
      log.error(Messages.getMessage("exception00"), ex);
      throw new SAXException(ex);
      }
      }
      

      完成這四個類的編碼,序列化/反序列化器的開發(fā)工作基本完成,下面將詳細(xì)講解使用及部署方法。

      服務(wù)器端應(yīng)用篇

      為了簡單起見,我們將一個很簡單的類通過Web服務(wù)發(fā)布,類中只有一個名稱為hello函數(shù),函數(shù)的返回值為JDOM模型的Element。代碼如下:

      package test;
      import org.jdom.*;
      import java.rmi.RemoteException;
      public class Sample1 implements java.rmi.Remote{
      public Sample1() {
      }
      public Element hello(String name){
      Element root=new Element("root");
      Element hello=new Element("hello");
      hello.setText("hello,"+name+"!");
      root.addContent(hello);
      return root;
      }
      }
      

      關(guān)于如何將一個類發(fā)布成Web服務(wù),在此并不進(jìn)行介紹,相信讀者可以自己完成,我們只關(guān)注如何將序列化/反序列化器加入到我們的Web服務(wù)中。打開web服務(wù)的配置文件server-config.xml,編輯關(guān)于Sample1的服務(wù)的配置部分:

      <service name="Sample1" type="" regenerateElement="true"
      provider="java:RPC" style="rpc" use="encoded">
      <parameter name="scope" value="Request" regenerateElement="false"/>
      <parameter name="className" value="test.Sample1" regenerateElement="false"/>
      <parameter name="allowedMethods" value="*" regenerateElement="false"/>
      <typeMapping
      encodingStyle="http://schemas./soap/encoding/"
      qname="ns1:Element"
      languageSpecificType="java:org.jdom.Element"
      serializer=
      "org.apache.axis.encoding.ser.JDomElementSerializerFactory"
      deserializer=
      "org.apache.axis.encoding.ser.JDomElementDeserializerFactory"
      name="Element" regenerateElement="true"
      xmlns:ns1="http://"/>
      </service>
      

      注意上面代碼中的粗體字部分,是我們現(xiàn)在要添加的,它表述了如何將序列化反序列化器部署到Web服務(wù)中。

      部署到Web Server

      解壓縮本文后面附帶的源代碼,根目錄下有build.xml文件,讀者需要正確安裝配置好Apache Ant,然后運行

      Ant make
      

      編譯后可生成壓縮文件sample.war。將生成的war包部署到Tomcat4.1下,啟動Tomcat,本文默認(rèn)的Tomcat監(jiān)聽的http端口為8080。后面的客戶端測試程序也將通過連接這一端口訪問此Web服務(wù)。如果讀者的Tomcat不在8080端口上工作,那么客戶端程序也要進(jìn)行相應(yīng)的修改。最后啟動Tomcat,這部分操作完成。

      客戶端應(yīng)用篇

      下面我們將編寫客戶端程序訪問剛才部署的Web服務(wù),講解如何把我們編寫的序列化/反序列化器加載到客戶端應(yīng)用程序中,下面是客戶端調(diào)用的代碼,注意斜體字部分,是關(guān)于序列化/反序列化器的注冊過程(如果你的Web服務(wù)器不是工作在8080端口,或采用了其他Web服務(wù)名,請自行更改下面程序中的url變量中的值),我們在test包下創(chuàng)建了一個名稱為 Client的類,代碼如下:

      package test;
      import org.apache.axis.client.Service;
      import org.apache.axis.client.Call;
      import org.apache.axis.utils.Options;
      import javax.xml.namespace.QName;
      public class Client {
      public Client() {
      }
      public static void main(String[] args) throws Exception{
      if(args.length<1){
      System.out.println("錯誤:缺少參數(shù)");
      System.exit(0);
      }
      //Web服務(wù)的URL
      String url="http://localhost:8080/sample/services/Sample1";
      Service service=new Service();
      Call call = (Call)service.createCall();
      call.setTargetEndpointAddress(url);
      //注冊序列化/反序列化器
      call.registerTypeMapping(org.jdom.Element.class,
      new QName("http://","Element"),
      new org.apache.axis.encoding.ser.JDomElementSerializerFactory(),
      new org.apache.axis.encoding.ser.JDomElementDeserializerFactory());
      //設(shè)置調(diào)用方法
      call.setOperationName(
      new javax.xml.namespace.QName("http://test", "hello"));
      //Web服務(wù)調(diào)用
      java.lang.Object _resp = call.invoke(new java.lang.Object[] {args[0]});
      //輸出到屏幕
      org.jdom.output.XMLOutputter out=new org.jdom.output.XMLOutputter();
      out.output( (org.jdom.Element) _resp, System.out);
      }
      }
      

      編譯后運行該程序,在控制臺窗口工程的根目錄下輸入

      run world  ( 其中"world"為調(diào)用例程中API的入口參數(shù))
      

      經(jīng)過一次web通訊,一兩秒后屏幕將顯示運行結(jié)果:

      <root>
      <hello>hello,world!</hello>
      </root>
      

      至此我們完成了一次Web服務(wù)的訪問過程。如果在程序執(zhí)行過程中,我們用TCP Moniter之類的工具監(jiān)視這一次訪問中的在網(wǎng)絡(luò)中流入流出的數(shù)據(jù),可以看到客戶端發(fā)起調(diào)用的xml數(shù)據(jù)流如下:

      POST /sample/services/Sample1 HTTP/1.0
      Content-Type: text/xml; charset=utf-8
      Accept: application/soap+xml,
      application/dime, multipart/related, text/*
      User-Agent: Axis/1.1
      Host: 127.0.0.1
      Cache-Control: no-cache
      Pragma: no-cache
      SOAPAction: ""
      Content-Length: 430
      <?xml version="1.0" encoding="UTF-8"?>
      <soapenv:Envelope xmlns:soapenv=
      "http://schemas./soap/envelope/"
      xmlns:xsd="http://www./2001/XMLSchema"
      xmlns:xsi="http://www./2001/XMLSchema-instance">
      <soapenv:Body>
      <ns1:hello soapenv:encodingStyle=
      "http://schemas./soap/encoding/"
      xmlns:ns1="http://test">
      <name xsi:type="xsd:string">world</name>
      </ns1:hello>
      </soapenv:Body>
      </soapenv:Envelope>
      

      服務(wù)器端返回的結(jié)果的XML輸出流如下:

      HTTP/1.1 200 OK
      Content-Type: text/xml; charset=utf-8
      Date: Wed, 31 Mar 2004 06:42:18 GMT
      Server: Apache Coyote/1.0
      Connection: close
      <?xml version="1.0" encoding="UTF-8"?>
      <soapenv:Envelope xmlns:soapenv
      "http://schemas./soap/envelope/"
      xmlns:xsd="http://www./2001/XMLSchema"
      xmlns:xsi="http://www./2001/XMLSchema-instance">
      <soapenv:Body>
      <ns1:helloResponse soapenv:encodingStyle=
      "http://schemas./soap/encoding/"
      xmlns:ns1="http://test">
      <ns1:helloReturn href="#id0"/>
      </ns1:helloResponse>
      <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle=
      "http://schemas./soap/encoding/"
      xsi:type="ns2:Element"
      xmlns:soapenc="http://schemas./soap/encoding/"
      xmlns:ns2="http://">
      <root>
      <hello>hello,world!</hello>
      </root>
      </multiRef>
      </soapenv:Body>
      </soapenv:Envelope>
      

      結(jié)語

      以上詳細(xì)講解了Axis的序列化/反序列化器的開發(fā)過程,相信讀者已經(jīng)從中學(xué)到了不少知識,并能夠應(yīng)用于自己的項目開發(fā)中去。通過掌握這一技術(shù),我們將更為深刻的理解Axis的內(nèi)部結(jié)構(gòu)和Web服務(wù)的工作機理,這些經(jīng)驗是市面上那些泛泛的講解JAVA Web服務(wù)的參考書上所學(xué)不到的。后續(xù)的文章還將向您展示一些在Java Web服務(wù)深度開發(fā)中的高級技術(shù),讓您真正駕馭Axis。

      參考資料

      • 附件中提供了本文中的全部源碼,它是一個完整的工程,可以參考學(xué)習(xí)。
      • 在apache的網(wǎng)站您可以獲得最新的Axis庫及其開發(fā)文檔:http://ws./axis/ 本文中提到的Tomcat Web服務(wù)器可以在這里免費獲得:http://jakarta./tomcat/index.html
      • 《IBM DEVELOPWORK》中一個關(guān)于web服務(wù)的教程《從JAVA類創(chuàng)建web服務(wù)》,是您快速掌握Web服務(wù)開發(fā)的很好教材,初學(xué)者可以進(jìn)行學(xué)習(xí)。
      • JDOM類庫可以去www.下載,CSDN上有一篇不錯的文章可以讓您快速掌握J(rèn)DOM的使用方法。http://www.csdn.net/develop/Read_Article.asp?Id=13806

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多