[j2me]利用kSOAP让MIDP设备与WebService之间传递类对象[下]
[j2me]利用kSOAP让MIDP设备与
WebService之间传递类对象
| 编写者 | 日期 | 关键词 | 
| 郑昀@ultrapower | 2005-8-14 | J2me webservice soa ksoap serialization MIDP CLDC | 
第二小步,Web Service传递较为复杂的类
下面我们讲述如何在MIDP设备和Web Service之间传递较为复杂的类,比如这个类中不但有String类型成员变量,还有Vector之类的复杂类型。
从kSoap的FAQ上看,他们推荐使用KvmSerializable以及 ClassMap传递自定义类,但是我一直没有试验成功。
我还是按照能试验出来的办法讲述一下步骤吧:
大致思路就是,在服务器端将类实例按照一定规格(一个一个的成员变量写)序列化为byte[],将这个byte[]数组返回给kSOAP。kSOAP收到之后,再反序列化,将byte[]一段一段地读入类实例。
Web Service服务器端的做法
先来定义要传递的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类定义在附录中可以找到。
服务器端主要是序列化,所以我们来讲讲wsTeam的byte[] serialize()函数。
| 序列化 | 
|        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[]数组。
那么,Web Service可以这么提供:
| 服务器端 | 
| 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<count; i++)                {                      s.writeUTF(data[i]);               }        } … } | 
MIDP设备的做法
和前面的MIDlet代码差不多,只不过要我们的ClassMap出场了:
| 使用ClassMap | 
| ClassMap classMap = new ClassMap(); (new MarshalBase64()).register(classMap); HttpTransport tx = new HttpTransport(serviceUrl, methodName); tx.setClassMap( classMap ); tx.debug = true; | 
MarshalBase64类定义在附录中可以找到。
这样,后面才能将接收到的SoapObject强制转换为byte[]。
| 转换 | 
| Object Response = tx.call(request); System.out.println( tx.responseDump ); byte[] by = (byte[])Response; | 
然后,再调用
| 反序列化 | 
| wsTeam wc = wsTeam.deserialize(by); | 
这样,在无线设备上就得到了wsTeam类实例了。
wsTeam的deserialize是这么定义的:
| 反序列化 | 
| 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<arrayLength; i++)                {                      data[i] = s.readUTF();               }         }… } | 
通过上面的反序列化,我们就可以通过
for (int i=0; i<wc. wsvPersonName.size(); i++) 
{
      System.out.println("第" + i +"个人:" + 
                 wc. wsvPersonName.getStringAt(i));
}
来打印MIDlet上收到的类对象中的StringVector成员变量了。
小结
利用相同的办法,您还可以在无线设备和Web Service之间,传递各种各样的类对象,类里面也包含了各种类型的成员变量。
| 编写者 | 日期 | 关键词 | 
| 郑昀@ultrapower | 2005-8-19 | J2me webservice soa ksoap serialization MIDP CLDC | 
附录A:StringVector
| StringVector  | 
| /**  * Vector主要用来保存各种类型的对象(包括相同类型和不同类型的对象)。  * 但是在一些情况下使用会给程序带来性能上的影响。这主要是由Vector类的两个特点所决定的。  * 第一,Vector提供了线程的安全保护功能。即使Vector类中的许多方法同步。  * 但是如果你已经确认你的应用程序是单线程,这些方法的同步就完全不必要了。  * 第二,在Vector查找存储的各种对象时,常常要花很多的时间进行类型的匹配。  * 而当这些对象都是同一类型时,这些匹配就完全不必要了。  * 因此,有必要设计一个单线程的,保存特定类型对象的类或集合来替代Vector类  */ package com.ultrapower.helper; /**  * @author VictorZheng  *  */ public class StringVector  {        // 这儿的transient标示这个属性不需要自动序列化        private transient String[] data;         private int count;         public int size()        {               return count;        }        public StringVector()         {             // default size is 10               this(10);           }        public StringVector(int initialSize)         {                data = new String[initialSize];         }         public void add(String str)         {                //     ignore null strings                if(str == null) { return; }                ensureCapacity(count + 1);                data[count++] = str;         }         private void ensureCapacity(int minCapacity)         {                int oldCapacity = data.length;                if (minCapacity > oldCapacity)                {                       String oldData[] = data;                       int newCapacity = oldCapacity * 2;                       data = new String[newCapacity];                       System.arraycopy(oldData, 0, data, 0, count);                }         }         public void remove(String str)         {                if(str == null)                {                      return; // ignore null str                  }               for(int i = 0; i < count; i++)                {                       //     check for a match                       if(data[i].equals(str))                       {                              System.arraycopy(data,i+1,data,i,count-1); // copy data                              //     allow previously valid array element be gc'd                              data[--count] = null;                              return;                       }                }         }                public final String getStringAt(int index)         {                if(index < 0)                { return null; }                else if(index > count)                {                       return null; // index is > # strings                }                else                {                       return data[index]; // index is good                 }        }                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<count; i++)                {                      s.writeUTF(data[i]);               }        }                 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<arrayLength; i++)                {                      data[i] = s.readUTF();               }         } } | 
附录B:MarshalBase64
| MarshalBase64 | 
| /**  * @author VictorZheng  *  */ import java.io.IOException; import org.kobjects.serialization.ElementType; import org.ksoap.ClassMap; import org.ksoap.Marshal; import org.ksoap.Soap; import org.ksoap.SoapParser; import org.ksoap.SoapWriter; /** Base64 (de)serializer */ public class MarshalBase64 implements Marshal {     static byte [] BA_WORKAROUND = new byte [0];     public static Class BYTE_ARRAY_CLASS = BA_WORKAROUND.getClass ();             public Object readInstance (SoapParser parser,                             String namespace, String name,                             ElementType expected) throws IOException {        parser.parser.read (); // start tag        Object result = Base64.decode             (parser.parser.readText ());        parser.parser.read (); // end tag        return result;     }             public void writeInstance (SoapWriter writer,                              Object obj) throws IOException {        writer.writer.write (Base64.encode ((byte[]) obj));     }     public void register (ClassMap cm) {        cm.addMapping             (cm.xsd, "base64Binary",              MarshalBase64.BYTE_ARRAY_CLASS, this);           cm.addMapping             (Soap.ENC, "base64",              MarshalBase64.BYTE_ARRAY_CLASS, this);     } } | 
 
                    
                 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号