本站首页    管理页面    写新日志    退出

The Neurotic Fishbowl

[web Server技术]axis序列化与反序列化
狂飙的蜗牛 发表于 2006/6/20 9:50:25

开发自己的序列化/反序列化器是一个激动人心的工作,但是却并不复杂,需要做的事情包括实现名成为org.apache.axis.encoding的包 中的SerializerFactory,Serializer,DeserializerFactory和Deserializer这四个接口。 下面将结合一个实例来讲解序列化/反序列化器的开发方法,希望读者能够一边参看本文提供的源代码一边学习。 JDOM作为一款比较"另类"的XML解析工具(因为它不符合W3C的DOM模型,自己另立一套)默默地占领着Java世界里的xml解析器的半壁江山,由于其简洁的设计和方便灵活的API调用,已经渐渐成为了许多开发人员在进行XML开发的首选。 但是Axis是建立在W3C的DOM模型的基础之上,师出名们正派,自然不屑与JDOM为伍。因此当开发人员想将自己已经写好的基于JDOM的应用模块采 用Web服务的方式发布的时候,不可避免的会遇到如何将JDOM模型下的对象如Document, Element等序列化的问题。 在软件工程师不会自己扩展Axis的序列化/反序列化器的时候,我们只能有两个办法达到这个目的,第一个就是更改以前应用模块内的API设计,使暴露的入 口参数和返回值参数都是W3C的对象类型,但这种做法并不现实,因为这一应用模块往往不是独立存在,牵一发将动全身,导致旧有系统架构的崩塌。 另一种做法就是为这个模块做一个代理类,它做的工作就对外接收或返回DOM模型的对象,对内转换成JDOM模型的对象,然后转发给应用模块,繁琐且效率低 下。当我们向Axis注入了针对于JDOM模型的序列化/反序列化器后,这一工作便可以由Axis代劳了。下面我们将逐个开发这四个类: JDomElementSerializerFactory JDomElementSerializerFactory是一个工厂类,需要通过某种机制注册到Axis引擎(具体方法见下面"服务器端应用篇"); Axis通过调用它,来实例化JDomElementSerializer。Axis 提供了BaseSerializerFactory,这个类是一个抽象类,并实现其中包含了一些可重用的代码。我们自己开发的工厂类只需简单继承这个类就 可以。构造函数中需要调用父类的构造函数将序列器类下面是它的源代码: package org.apache.axis.encoding.ser;public class JDomElementSerializerFactory extends BaseSerializerFactory { public JDomElementSerializerFactory() { super(JDomElementSerializer.class); }} JDomElementSerializer JDomElementSerializer实现 org.apache.axis.encoding.Serializer接口,其核心API是serialize(),我们需要在这个方法的内部完成对 JDOM模型的Element的序列化工作,序列化的结果要保存在入口参数传入的序列化上下文对象(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(); //创建一个JDOM的XML输出器 StringWriter sw=new StringWriter(); outputter.output(root,sw);//用支持W3C的DOM模型的Xerces解析器解析文本流 DOMParser parser=new DOMParser(); //创建一个DOM的XML解析器 try { parser.parse(new org.xml.sax.InputSource( new java.io.StringReader(sw.toString()))); }catch (Exception ex) { throw new java.io.IOException ("序列化时产生错误"); } //获取符合DOM模型的Element对象 org.w3c.dom.Element w3c_root = parser.getDocument().getDocumentElement(); //放入序列化上下文对象中 context.startElement(name, attributes); context.writeDOMElement(w3c_root); context.endElement(); } JDomElementDeserializerFactory 反序列化器的工厂类同序列化器的工厂类一样的设计,不再赘述。代码: package org.apache.axis.encoding.ser;public classJDomElementDeserializerFactory extends BaseDeserializerFactory { public JDomElementDeserializerFactory() { super(JDomElementDeserializer.class); }} JDomElementDeserializer 用过SAX解析XML的读者,对反序列化的实现比较容易理解,反序列化也采用了消息触发的机制,我们只需继承org.apache.axis.encoding.DeserializerImpl类,并覆盖其中的onEndElement方法: /** * 在元素结束触发反序列化的方法 * @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);//如果当前的消息元素本身需要反序列化 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, 转换成JDOM模型的Element value=db.build(ret); } } } } catch (Exception ex) { //错误,则记日志,并抛SAXException log.error(Messages.getMessage ("exception00"), ex); throw new SAXException(ex); } } 完成这四个类的编码,序列化/反序列化器的开发工作基本完成,下面将详细讲解使用及部署方法。 服务器端应用 为了简单起见,我们将一个很简单的类通过Web服务发布,类中只有一个名称为hello函数,函数的返回值为JDOM模型的Element。代码如下: package test;import org.jdom.*;import java.rmi.RemoteException;public class Sample1implements 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; }} 关于如何将一个类发布成Web服务,在此并不进行介绍,相信读者可以自己完成,我们只关注如何将序列化/反序列化器加入到我们的Web服务中。打开web服务的配置文件server-config.xml,编辑关于Sample1的服务的配置部分: <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.xmlsoap.org/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://jdom.org"/></service> 注意上面代码中的粗体字部分,是我们现在要添加的,它表述了如何将序列化反序列化器部署到Web服务中。 部署到Web Server 解压缩本文后面附带的源代码,根目录下有build.xml文件,读者需要正确安装配置好Apache Ant,然后运行 Ant make 编译后可生成压缩文件sample.war。将生成的war包部署到Tomcat4.1下, 启动Tomcat,本文默认的Tomcat监听的http端口为8080。后面的客户端测试程序也将通过连接这一端口访问此Web服务。如果读者的 Tomcat不在8080端口上工作,那么客户端程序也要进行相应的修改。最后启动Tomcat,这部分操作完成。 客户端应用 下面我们将编写客户端程序访问刚才部署的Web服务,讲解如何把我们编写的序列化/ 反序列化器加载到客户端应用程序中,下面是客户端调用的代码,注意斜体字部分,是关于序列化/反序列化器的注册过程(如果你的Web服务器不是工作在 8080端口,或采用了其他Web服务名,请自行更改下面程序中的url变量中的值),我们在test包下创建了一个名称为 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 ("错误:缺少参数"); System.exit(0); } //Web服务的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://jdom.org","Element"),new org.apache.axis.encoding.ser.JDomElementSerializerFactory(),new org.apache.axis.encoding.ser.JDomElementDeserializerFactory());//设置调用方法 call.setOperationName(new javax.xml.namespace.QName("http://test", "hello"));//Web服务调用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"为调用例程中API的入口参数 经过一次web通讯,一两秒后屏幕将显示运行结果: <root> <hello>hello,world!</hello></root> 至此我们完成了一次Web服务的访问过程。如果在程序执行过程中,我们用TCP Moniter之类的工具监视这一次访问中的在网络中流入流出的数据,可以看到客户端发起调用的xml数据流如下: POST /sample/services/Sample1 HTTP/1.0Content-Type: text/xml; charset=utf-8Accept: application/soap+xml, application/dime, multipart/related, text/*User-Agent: Axis/1.1Host: 127.0.0.1Cache-Control: no-cachePragma: no-cacheSOAPAction: ""Content-Length: 430<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <ns1:hello soapenv:encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://test"> <name xsi:type="xsd:string">world</name> </ns1:hello> </soapenv:Body></soapenv:Envelope> 服务器端返回的结果的XML输出流如下: HTTP/1.1 200 OKContent-Type: text/xml; charset=utf-8Date: Wed, 31 Mar 2004 06:42:18 GMTServer: Apache Coyote/1.0Connection: close<?xml version="1.0"encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv"http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <ns1:helloResponse soapenv:encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://test"> <ns1:helloReturn href="#id0"/> </ns1:helloResponse> <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:Element" xmlns:soapenc= "http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="http://jdom.org"> <root> <hello>hello,world!</hello> </root> </multiRef> </soapenv:Body></soapenv:Envelope> 结语 以上详细讲解了Axis的序列化/反序列化器的开发过程,相信读者已经从中学到了不少知识,并能够应用于自己的项目开发中去。通过掌握这一技术,我们将更为深刻的理解Axis的内部结构和Web服务的工作机理,让您真正驾驭Axis。

阅读全文(3021) | 回复(0) | 编辑 | 精华

 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)

 
 



The Neurotic Fishbowl

.: 公告


Bloginess

«September 2025»
123456
78910111213
14151617181920
21222324252627
282930

.: 我的分类(专题)

首页(31)
原创(9)
Ajax技术(1)
随笔(1)
web Server技术(6)


In the Bowl

.: 最新日志

NewsBar真的能赚钱吗?
学习蜡烛图
2009-02-19(汇市报道)
2009-2-18
正式进入汇市
jsp上传图片
一个MM搞笑的Google搜索记录
两头猪的精典对白
一个未婚男人的自述
寂寞而高贵的武士-----野蛮人(一)


.: 最新回复

回复:axis2安装步骤
回复:axis2安装步骤
回复:安装序列号集锦
回复:七大人物套装的背景知识
回复:一个未婚男人的自述
回复:2009-02-19


The Fishkeeper
blog名称:狂飙的蜗牛
日志总数:31
评论数量:19
留言数量:0
访问次数:158450
建立时间:2006年6月13日



Text Me

.: 留言板

签写新留言


Other Fish in the Sea

.: 链接


 pandaboss.bolg.sohu.com




站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.047 second(s), page refreshed 144757372 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号