ksoap2- webservice(整理版)
?
1.概述 对于J2ME访问远端的Web Service,除了官方标准JSR 172,我们还有两种选择: l?????????kSOAP l?????????Wingfoot Wingfoot是由Wingfoot Software(www.wingfoot.com)出品的一款J2ME(CLDC/CDC) SOAP1.1的轻量级实现方案。 kSOAP是Enhydra.org的一个开源作品,是EnhydraME项目的一部分。基于Enhydra.org出品的开源通用XML解析器kXML,kSOAP完成了J2ME/MIDP平台上的SOAP解析和调用工作。 Stefan Haustein领导的kSOAP开发小组于2001年5月17日推出了Alhpa版本。之后又经过了一年的开发,2002年6月6日推出的kSOAP?1.2支持了SOAP1.2规范。2003年8月25日推出的kSOAP2,对SOAP序列化规范支持得更好了。 大多数人选择kSOAP的原因是,kSOAP虽然在2003年8月之后就不再维护了,但它是Open Source的,很容易加入增强特性,比如说默认情况下kSOAP2仅仅支持cmnet接入点,可以修改kSOAP2的HttpTransport.java代码增加对cmwap接入点的支持。
kSOAP2.0还有一个优点是,改进了对Microsoft dotNET的兼容。以前有很多人抱怨kSOAP调用dotNET编写的Web Service时遇到了不少的困扰。 本章节我们将使用kSOAP?2.0的例子来讲解。 为了使用kSOAP?2.0,必须还要下载工具包kXML2。
kXML2比kXML更小更快。 2.kSOAP2接口 让我们先熟悉一下即将用到的kSOAP2的常用接口。
SoapEnvelope对应于SOAP规范中的SOAP Envelope,封装了head和body对象。 SoapSerializationEnvelope是kSOAP2新增加的类,是对SoapEnvelope的扩展,对SOAP序列化(Serialization)格式规范提供了支持,能够对简单对象自动进行序列化(simple object serialization)。而kSOAP1.x则是通过org.kSOAP.ClassMap来做序列化的,不太好操作,也不利于扩展。 SoapObject让你自如地构造SOAP调用; HttpTransport为你屏蔽了Internet访问/请求和获取服务器SOAP的细节。 ? 下面我们通过一个最简单的webservice调用,来看看kSOAP是如何做到SOAP解析的: 2.1.kSOAP和Web Service之间传递String webservice传递String给MIDP是一件很简单的事情。首先在服务器端,不管你是用Microsft ASP.NET创建webservice,还是由Tomcat+AXIS1.2支撑的webservice,都可以这么编写主服务类:
kSOAP是如何调用这个webservice的呢? 首先要使用SoapObject,这是一个高度抽象化的类,完成SOAP调用。可以调用它的addProperty方法填写要调用的webservice方法的参数。如下面代码所示: SoapObject request??= new SoapObject(serviceNamespace,methodName); SoapObject构造函数的两个参数含义为: serviceNamespace –?你的webservice的命名空间,既可以是 http://localhost:8088/flickrBuddy/services/Buddycast这样的,也可以是 urn:PI/DevCentral/SoapService这样的; methodName –?你要调用方法的名字。 然后,按照webservice方法参数的顺序,依次调用 request.addProperty( "username","user" ); request.addProperty( "password","pass" ); 来填充webservice参数。
对于webservice方法返回String类型的情况,还用不着开发者做序列化(Serialization)定制工作。
然后要告诉SoapSerializationEnvelope把构造好的SoapObject封装进去: SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.bodyOut = request;
接下来就要声明 HttpTransport tx = new HttpTransport(serviceURL); ht.debug = true; HttpTransport构造函数的参数含义为: serviceURL –?要投递SOAP数据的目标地址,譬如说 http://soap.amazon.com/onca/soap3?。 HttpTransport是一个强大的辅助类,来完成Http-call transport process,它封装了网络请求的一切,你完全不用考虑序列化消息。我们通过设置它的debug属性为true来打开调试信息。 方法HttpTransport.call()自己就能够发送请求给服务器、接收服务器响应并序列化SOAP消息,如下所示: ht.call(null,envelope); HttpTransport的call方法的两个参数含义为: soapAction – SOAP?规范定义了一个名为?SOAPAction?的新?HTTP?标头,所有?SOAP HTTP?请求(即使是空的)都必须包含该标头。?SOAPAction?标头旨在表明该消息的意图。通常可以置此参数为null,这样HttpTransport就会设置HTTP标头SOAPAction为空字符串。 Envelope –?就是前面我们构造好的SoapSerializationEnvelope或SoapEnvelope对象。
调用call方法是一个同步过程,需要等待它返回。 返回之后,就可以调用SoapSerializationEnvelope的getResult方法来获取结果了: Object Response = envelope.getResult(); 如果HttpTransport的debug属性为true,那么此时就可以通过 System.out.println("Response dump>>"?+ tx.responseDump); 打印出HttpTransport的调试信息。尤其当前面call方法和getResult方法发生异常时,这个调试信息是非常有用的。 前面我们的webservice方法由于是返回string,所以得到这个string值就非常简单了: String sResponse = (String)Response;
综上所述,J2ME客户端的MIDlet按键事件函数这么写即可:
? 2.2.webservice返回复杂描述的情况 kSOAP2处理webservice简单的string类型返回值是很容易的。那么如何处理像亚马逊网上书店这种webservice返回的复杂描述呢? kSOAP2自带了一个例子来说明,下面我们就讲解一下。 关于亚马逊的查询书目的webservice,你可以通过 http://soap.amazon.com/schemas3/AmazonWebServices.wsdl 来获知定义。 我们要关注的是它的关键词查询请求的方法,它的定义是: <operation name="KeywordSearchRequest"> ?????<soap:operation?soapAction="http://soap.amazon.com" /> ?<input> <soap:body?use="encoded" encodingStyle=http://schemas.xmlsoap.org/soap/encoding/?namespace="http://soap.amazon.com" /> ?????</input> <output> <soap:body?use="encoded" encodingStyle=http://schemas.xmlsoap.org/soap/encoding/?namespace="http://soap.amazon.com" /> ????????</output> ??????</operation> 我们提交对包含指定关键词的书目查询,如果查询成功,将会返回一系列书名节点,每一本书都提供了作者、出版社、出版日期、价格等等信息。这些书名节点都在一个“Details”节点下。查询结果的总数放在TotalResults节点。每页10个结果,可以通过查看TotalPages节点来确定需要多少页。 那么,kSOAP2可以很简单地通过SoapObject的getProperty方法来得到书详细信息的节点,存储入一个Vector对象中,如下所示: HttpTransport ht = new HttpTransport("http://soap.amazon.com/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")); } 这样就可以了。 需要注意的是,要测试这个工程,必须到亚马逊的http://www.amazon.com/webservice?注册获取Access Key ID,也就是webservice方法中的“devtag”参数所需要的Developer-Tag。 2.3.webservice传递自定义复杂对象 下面我们讲述如何在MIDP设备和webservice之间传递自定义类,比如这个类中不但有String类型成员变量,还有Vector之类的复杂类型。 大致思路就是,在服务器端将类实例按照一定规格(一个一个的成员变量写)序列化为byte[],将这个byte[]数组返回给kSOAP2。kSOAP2收到之后,再反序列化,将byte[]一段一段地读入类实例。 2.3.1.webservice服务器端的做法 我们先来定义要传递的wsTeam类:
其中,StringVector类是另外一个自定义类,就是简单地把String[]封装了一下,便于操作。StringVector类定义在示范代码中可以找到。 服务器端主要是序列化,所以我们来讲讲wsTeam的serialize()函数。
这样,类实例就可以把自己序列化为byte[]数组。 那么,webservice可以这么提供:
到了MIDP设备上,要能够从byte[]恢复出wsTeam类实例才行。 ? StringVector的序列化方法writeObject也很简单,先写入字符串数组的大小,然后再将每一个元素写入,如下所示:
? 2.3.2.MIDP设备的做法 和前面的MIDlet代码差不多,只不过要kSOAP2的MarshalBase64出场了。 在kSOAP中,我们用Base64把二进制流编码为ASCII字符串,这样就可以通过XML/SOAP传输二进制数据了。 org.kSOAP2.serialization.MarshalBase64的目的就是,把SOAP XML中的xsd:based64Binary元素序列化为Java字节数组(byete array)类型。类似的,kSOAP2还提供了MarshalDate、MarshalHashtable类来把相应的元素序列化为Java的Date、Hashtable类型。 ?
将接收到的SoapObject强制转换为byte[]。
然后,再调用
这样,在无线设备上就得到了wsTeam类实例了。 ? wsTeam的deserialize函数是这么定义的:
StringVector的反序列化方法readObject也很简单,先读入字符串数组的大小,就自行新建一个同样大小的字符串数组,然后再将每一个元素写入这个数组,如下所示:
? 通过上面的反序列化,我们就可以通过 for (int i=0; i<wc.wsvPersonName.size(); i++) { ???????System.out.println("第" + i +"个人:" + ?????????????????????wc.wsvPersonName.getStringAt(i)); } 来打印MIDlet上收到的类对象中的StringVector成员变量了。 3.小结 利用kSOAP2提供的框架,你可以在无线设备和Internet webservice之间,既可以传递简单的数值,也可以传递各种各样的类对象。 public class Ksoap2_Content { ? ??try { ???soapObject = new SoapObject(NAMESPACE,METHOD_NAME); ??????????? ht.call(SOAP_ACTION,envelope); ??????????? soapObject = (SoapObject) envelope.bodyIn; ??return soapObject; ?} ? ? 完整的一个联网 类 评价答案
满意答案好评率:100%
android 利用ksoap2方式连接webservice(2010-04-16 16:36:25)转载标签:androidksoap2webserviceit 分类:Android
??? 利用J2SE的ksoap2标准,我也来做一个山寨版本的android连接webservice。因为soap封装的关系,android application在接收到数据后不能够正确的按照J2SE的标准来获取。 ??? 在运用之前,我们先要引导两个jar进入工程的buildpath ??? ??? 这两个jar包都可以在网上查到下载,引导完后再做一项准备工作。弄清楚已发布的webservice的地址,以及封装的方式。比如: webservice接口: http://192.168.0.2:8080/axis2/services/Manager?wsdl (顺便说明一下,在android当中,不能写localhost,必须写清楚PC机当前的网络IP) webservice封装: http://ws.apache.org/axis2 都了解了过后,说明已经做好准备了。 ??? 下面就介绍一下android如何获取webservice封装数据。。 引入ksoap2中以封装好的类 import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.AndroidHttpTransport; 在类中定义webservice的接口地址以及解析方式并且定义要调用的webservice中的函数 private static final String URL = " http://192.168.0.2:8080/axis2/services/Manager?wsdl"; private static final String NAMESPACE = " http://ws.apache.org/axis2"; private static final String METHOD_NAME = "GetMyFriends"; 这个信息我们可以在webservice中查到 <xs:element name="GetMyFriends"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" name="userId" type="xs:int"/> <xs:element minOccurs="0" name="password" nillable="true" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> 接下来开始做对webservice请求数据的工作,请求webservice函数以及封装要用的两个参数(userId和password) ??? SoapObject request = new SoapObject(NAMESPACE,METHOD_NAME); ??? request.addProperty("userId","123456"); ??? request.addProperty("password","test"); 之后我们给定义发送数据的 信封的 封装格式 SoapSerializationEnvelope envelope = new SoapSerializationEnvelope( SoapEnvelope.VER11 ); 发出请求 envelope.setOutputSoapObject(request); AndroidHttpTransport aht = new AndroidHttpTransport(URL); aht.call(null,envelope); 接着就可以定义一个SoapObject类型的实例去获取我们返回来的数据 SoapObject so = (SoapObject) envelope.bodyIn; 这里如果是返回来的数据只有一行并且只有一个值,比如验证函数,返回boolean类型的话,操作比较简单,String getReturn= so.getProperty("return");? 这个getReturn就是你要获取的值。 但是如果返回来是多行的值的话,这个方法就不行了,我们必须对返回来的信息做一些解析。我曾试过用J2SE的标准方式来获取,但是会报错,最主要的可能是他的方式在android当中不能使用。所以在这里我用了 正则表达式这种方式来进行数据的解析,我们先来看一下他返回的数据的结构是什么情况。 GetMyFriendsResponse{return=FriendsMessage{ permitList=anyType{nickName= 我爱罗; singnature=null; userId=2; }; permitList=anyType{nickName=jack; singnature=null; userId=1004; }; permitList=anyType{nickName=admin; singnature=leo_admin; userId=1001; };};} 简单看他很想Json结构,但是确不是。。。 就目前的解决方式,我只是通过规律来进行了正则表达式的解析:如解析上面的内容。 ??????????? //首先取得permitList(好友)的个数 ??????????? String testPattern = "permitList"; ??????????? int resultlength = result.length(); ??????????? cresult = cresult.replace(testPattern,""); ??????????? int lastlength = (resultlength - cresult.length()) / testPattern.length(); ?????????? ??????????? //取得每个permitList中的值。 ??????????? String LoginReturn="",pattern="nickName=.*?;s*singnature=.*?;s*userId=.*?;"; ??????????? //动态生成String 数组, 存储每个好友的信息 ??????????? String[] GetFinalReturn = new String[lastlength]; ??????????? for (int i=0;i<lastlength;i++){ ??????????????? LoginReturn = result.replaceFirst("^.*("+pattern+").*$","$1"); ??????????????? GetFinalReturn[i] = LoginReturn; ??????????????? result = result.replace(LoginReturn,""); ??????????? } 这个数组里面存储的格式就是nickName=admin; singnature=leo_admin; userId=1001; 这样以来,我们可以根据"="和";"两个符号之间做split操作就可以得到数据。 好了,到此连接webservice和解析返回来的数据的工作就做完了,虽然这个方式看起来很复杂,但是目前来说,用ksoap2方式来连接webservice暂时还没有找到更有效的解决方式。。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |