Chinaunix首页 | 论坛 | 博客
  • 博客访问: 619676
  • 博文数量: 98
  • 博客积分: 10010
  • 博客等级: 上将
  • 技术积分: 1528
  • 用 户 组: 普通用户
  • 注册时间: 2007-08-28 16:20
文章分类

全部博文(98)

文章存档

2011年(1)

2010年(11)

2009年(44)

2008年(42)

我的朋友

分类:

2009-03-16 11:59:58

22webservice返回复杂描述的情况

kSOAP2处理webservice简单的string类型返回值是很容易的。那么如何处理像亚马逊网上书店这种webservice返回的复杂描述呢?

kSOAP2自带了一个例子来说明,下面我们就讲解一下。

关于亚马逊的查询书目的webservice,你可以通过

来获知定义。

我们要关注的是它的关键词查询请求的方法,它的定义是:

<operation name="KeywordSearchRequest">

     <soap:operation soapAction="" />

 <input>

<soap:body use="encoded"

encodingStyle= namespace="" />

     input>

<output>

<soap:body use="encoded"

encodingStyle= namespace="" />

        output>

      operation>

我们提交对包含指定关键词的书目查询,如果查询成功,将会返回一系列书名节点,每一本书都提供了作者、出版社、出版日期、价格等等信息。这些书名节点都在一个“Details”节点下。查询结果的总数放在TotalResults节点。每页10个结果,可以通过查看TotalPages节点来确定需要多少页。

那么,kSOAP2可以很简单地通过SoapObjectgetProperty方法来得到书详细信息的节点,存储入一个Vector对象中,如下所示:

HttpTransport ht = new HttpTransport("/onca/soap3");

ht.call(null, envelope);

SoapObject result = (SoapObject) envelope.getResult();

Vector resultVector = (Vector) result.getProperty("Details");

Vector对象中实际上还是存储了一组SoapObject对象,这里的每一个SoapObject对象对应于一本书的DOM对象。

那么如何得到每一本书的书名、价格呢?

for(int i = 0; i < resultVector.size(); i++){

       SoapObject detail = (SoapObject) resultVector.elementAt(i);

       System.out.println("书名>>"+(String) detail.getProperty("ProductName"));

System.out.println("日期>>"+(String) detail.getProperty("ReleaseDate"));

System.out.println("价格>>"+(String) detail.getProperty("ListPrice"));

}

这样就可以了。

需要注意的是,要测试这个工程,必须到亚马逊的 注册获取Access Key ID,也就是webservice方法中的“devtag”参数所需要的Developer-Tag

23webservice传递自定义复杂对象

下面我们讲述如何在MIDP设备和webservice之间传递自定义类,比如这个类中不但有String类型成员变量,还有Vector之类的复杂类型

大致思路就是,在服务器端将类实例按照一定规格(一个一个的成员变量写)序列化为byte[],将这个byte[]数组返回给kSOAP2kSOAP2收到之后反序列化,将byte[]一段一段地读入类实例。

231webservice服务器端的做法

我们先来定义要传递的wsTeam类:

类定义

public class wsTeam{

private String wsReturnCode;

private String wsPersonCount;

public StringVector  wsvPersonName;

public byte[] serialize();

public static wsTeam deserialize(byte[] data) ;

}

其中,StringVector类是另外一个自定义类,就是简单地把String[]封装了一下,便于操作。StringVector类定义在示范代码中可以找到。

服务器端主要是序列化,所以我们来讲讲wsTeamserialize()函数。

wsTeam的序列化函数

       public byte[] serialize() {

              ByteArrayOutputStream baos = new ByteArrayOutputStream();

              DataOutputStream dos = new DataOutputStream(baos);

 

              try

              {

                     dos.writeUTF(wsReturnCode);

                     dos.writeUTF(wsPersonCount);

                     wsvPersonName.writeObject(dos);

                     baos.close();

                     dos.close();

              }

              catch(Exception exc)

              {

                     exc.printStackTrace();

              }

 

              return baos.toByteArray();

       }

这样,类实例就可以把自己序列化为byte[]数组。

那么,webservice可以这么提供:

服务器端

public class SimpleKSoapWS {

   

    public SimpleKSoapWS () {

    }

   

    public byte[]  foo2(String username, String password) {

        wsTeam obj= new wsTeam ();

           return obj.serialize();

}

}

到了MIDP设备上,要能够从byte[]恢复出wsTeam类实例才行。

 

StringVector的序列化方法writeObject也很简单,先写入字符串数组的大小,然后再将每一个元素写入,如下所示:

StringVector的序列化

public class StringVector

{…

public synchronized void writeObject(java.io.DataOutputStream s)

       throws java.io.IOException 

       { 

              //     Write out array length

              s.writeInt(count); 

              //     Write out all elements in the proper order.  

              for (int i=0; i

              {

                     s.writeUTF(data[i]);

              }

       }

}

 

232MIDP设备的做法

和前面的MIDlet代码差不多,只不过要kSOAP2MarshalBase64出场了

kSOAP中,我们用Base64把二进制流编码为ASCII字符串,这样就可以通过XML/SOAP传输二进制数据了。

org.ksoap2.serialization.MarshalBase64的目的就是,把SOAP XML中的xsd:based64Binary元素序列化为Java字节数组(byete array)类型。类似的,kSOAP2还提供了MarshalDateMarshalHashtable类来把相应的元素序列化为JavaDateHashtable类型。

 

使用MarshalBase64

import org.ksoap2.serialization.MarshalBase64;

 

SoapObject request = new SoapObject(serviceNamespace, methodName );

 

SoapSerializationEnvelope envelope =

       new SoapSerializationEnvelope(SoapEnvelope.VER11);

envelope.bodyOut = request;

new MarshalBase64().register(envelope);

 

HttpTransport tx = new HttpTransport(serviceNamespace);

tx.debug = true;

 

tx.call(null, envelope);

Object Response = envelope.getResult();

将接收到的SoapObject强制转换为byte[]

转换

byte[] by = (byte[])Response;

System.out.println("succ convert!");

然后,再调用

反序列化

wsTeam wc = wsTeam.deserialize(by);

这样,在无线设备上就得到了wsTeam类实例了。

 

wsTeamdeserialize函数是这么定义的:

wsTeam的反序列化函数

public class StringVector

{…

       public static wsTeam deserialize(byte[] data) {

              ByteArrayInputStream bais = new ByteArrayInputStream(data);

              DataInputStream dis = new DataInputStream(bais);

              wsTeam wc = new wsTeam();

             

              try

              {

                     wc.wsReturnCode = dis.readUTF();

                     wc.wsPersonCount = dis.readUTF();

             

                     wc. wsvPersonName.readObject(dis);

      

                     bais.close();

                     dis.close();

              }

              catch(Exception exc)

             

                     exc.printStackTrace();

              }

 

              return wc;

       }

…}

StringVector的反序列化方法readObject也很简单,先读入字符串数组的大小,就自行新建一个同样大小的字符串数组,然后再将每一个元素写入这个数组,如下所示:

StringVector的反序列化

public class StringVector

{…

       public synchronized void readObject(java.io.DataInputStream s)

       throws java.io.IOException, ClassNotFoundException  

       {    

              //     Read in array length and allocate array  

              int arrayLength = s.readInt(); 

              data = new String[arrayLength]; 

              // 同步data的大小

              count = arrayLength;

              //     Read in all elements in the proper order. 

              for (int i=0; i

              {

                     data[i] = s.readUTF();

              }

       }…

}

 

通过上面的反序列化,我们就可以通过

for (int i=0; i

       System.out.println("" + i +"个人:" +

                     wc.wsvPersonName.getStringAt(i));

}

来打印MIDlet上收到的类对象中的StringVector成员变量了。

3.小结

利用kSOAP2提供的框架,你可以在无线设备和Internet webservice之间,既可以传递简单的数值,也可以传递各种各样的类对象。

阅读(2052) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~