Google為ndroid平台開發Web Service提供了支持,提供了Ksoap2-android相關架包
1.下載該夾包可以直接登錄http://code.google.com/p/ksoap2-android/,現在該站點已經提供了直接的下載,只要點擊下載鏈接就可以下載了;
我現在的是ksoap2-android-assembly-2.6.5-jar-with-dependencies.jar
2.好了,現在我們就可以進行新建項目來進行測試了,首先我們先建立java服務端,這里的一些前期准備我就不說了(比如與spring的整合等示例),
如果有不清楚的可以去看博客 http://www.cnblogs.com/shenliang123/archive/2012/04/16/2451580.html
由於這里重點是android客戶端,java服務器端就直接給代碼了
Interface:(這里提供了兩個方法,一個傳遞的是簡單字符串,另一個傳遞的是符合對象+集合)
package xidian.sl.service.webService; import javax.jws.WebParam; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.Style; import xidian.sl.service.impl.webService.StudentList; @WebService @SOAPBinding(style = Style.RPC) public interface TestService { public String getUser(@WebParam(name = "name")String name); public StudentList getStuList(); }
implement:
package xidian.sl.service.impl.webService; import java.util.ArrayList; import java.util.List; import javax.jws.WebService; import xidian.sl.entity.Students; import xidian.sl.service.webService.TestService; @WebService(endpointInterface = "xidian.sl.service.webService.TestService") public class TestServiceImpl implements TestService { @Override public String getUser(String name) { System.out.println("客戶端傳遞的名字為 = "+name); return name; } @Override public StudentList getStuList() { System.out.println("該方法被調用"); List<Students> stuList = new ArrayList<Students>(); //第一個學生 Students stu1 = new Students(); stu1.setStuName("沈浪"); stu1.setStuNum("1006010054"); stu1.setStuSex("男"); stuList.add(stu1); //第二個學生 Students stu2 = new Students(); stu2.setStuName("香香"); stu2.setStuNum("1006010043"); stu2.setStuSex("女"); stuList.add(stu2); //將List集合封裝成一個對象才能在webService中進行傳遞 StudentList studentList = new StudentList(); studentList.setStuList(stuList); return studentList; } }
list的封裝對象
package xidian.sl.service.impl.webService; import java.util.List; import xidian.sl.entity.Students; public class StudentList { private List<Students> stuList; public List<Students> getStuList() { return stuList; } public void setStuList(List<Students> stuList) { this.stuList = stuList; } }
然后在srping的整合配置文件中進行如下配置即可(默認web.xml中已經進行配置)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <!-- 這些xml文件在cxf-2.5.0.jar的META-INF目錄下--> <!--<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> 警告提示已經廢棄了cxf-extension-soap.xml文件--> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <!-- 這里配置服務接口,后面描述 id:指在spring配置的bean的ID. Implementor:指明具體的實現類. Address:指明這個web service的相對地址 --> <!-- 測試 --> <bean id="testServiceImpl" class="xidian.sl.service.impl.webService.TestServiceImpl" > </bean> <jaxws:endpoint id="testService" implementor="#testServiceImpl" address="/test" /> <!-- 開啟tomcat服務器 ,訪問http://localhost:8080/WebExam/services/test?wsdl http://localhost:8080/WebExam是本項目的訪問地址 services是由於web.xml配置所得,test是由於Spring配置文件中的address屬性所得 --> </beans>
3.到此服務器端的已經建立完全,我們可以測試下:開啟tomcat,然后在瀏覽器中輸入http://localhost:8090/WebExam/services/test?wsdl可以查看wsdl
現在我們就可以開始建立android客戶端了
新建一個項目后導入ksoap2-android-assembly-2.6.5-jar-with-dependencies.jar,這里要特別注意:導入包的方式不要選擇項目右鍵---->build path---->
add external archives...,如果使用這種方式表面上好像是導入了包,但還是沒有辦法引用到,然后啟動項目后一直會報:
我們還是選擇和開發web一樣的方式,就是在項目下新建lib或者libs文件夾,然后將jar直接復制到該文件夾中,IDE會幫助直接引入的:
這樣就正確無誤了,不再會報類無法引用到了
android中通過webservice調用服務器端其實還是很簡單的,只要按部就班的按照下面步驟進行即可:
(1)創建HttpTransportSE對象,該對象用於調用WebService操作
HttpTransportSE ht = new HttpTransportSE(SERVICE_URL);
(2)創建SoapSerializationEnvelope對象
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
(3)創建SoapObject對象,創建該對象時需要傳入所要調用的Web Service的命名空間和WebService方法名
SoapObject request = new SoapObject(SERVICE_NS, methodName);
(4)如果有參數傳給Web Service服務器端,調用SoapObject對象的addProperty(String name, Object value)方法來設置參數,該方法的name參數指定參數名
注意:參數名不一定要與服務端的方法中的參數名相同,只要對應順序相同即可;value參數指定參數值
request.addProperty("name", "1006010054");
(5)調用SoapSerializationEnvelope的setOutputSoapObject()方法,或者直接對bodyOut屬性賦值,將前兩步創建的SoapObject對象設為SoapSerializationEnvelope
的傳出SOAP消息體
envelope.bodyOut = request;
(6)調用對象的call()方法,並以SoapSerializationEnvelope作為參數調用遠程的web service
ht.call(null, envelope);
(7)掉用完成后,訪問SoapSerializationEnvelope對象的bodyIn屬性,該屬性返回一個SoapObject對象,該對象就代表Web service的返回消息,解析該對象,即可獲得
調用web service的返回值
SoapObject result = (SoapObject) envelope.bodyIn;
String name = result.getProperty(0).toString();
下面給書具體的實例:
mian.xml很簡單就是兩個編輯框:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <EditText android:id="@+id/editText1" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" > <requestFocus /> </EditText> <EditText android:id="@+id/editText2" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" /> </LinearLayout>
Activity:(該Activity調用了服務器端返回普通字符串的方法)
package xidian.sl.android.webservice; import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; import android.app.Activity; import android.os.Bundle; import android.widget.EditText; public class WebServiceSimpleDemo extends Activity{ final static String SERVICE_NS = "http://webService.service.sl.xidian/"; final static String SERVICE_URL = "http://192.168.1.103:8090/WebExam/services/test"; private EditText txt1; private EditText txt2; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); txt1 = (EditText) findViewById(R.id.editText1); txt2 = (EditText) findViewById(R.id.editText2); //調用的方法 String methodName = "getUser"; //創建httpTransportSE傳輸對象 HttpTransportSE ht = new HttpTransportSE(SERVICE_URL); ht.debug = true; //使用soap1.1協議創建Envelop對象 SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); //實例化SoapObject對象 SoapObject request = new SoapObject(SERVICE_NS, methodName); /** * 設置參數,參數名不一定需要跟調用的服務器端的參數名相同,只需要對應的順序相同即可 * */ request.addProperty("name", "1006010054"); //將SoapObject對象設置為SoapSerializationEnvelope對象的傳出SOAP消息 envelope.bodyOut = request; try{ //調用webService ht.call(null, envelope); //txt1.setText("看看"+envelope.getResponse()); if(envelope.getResponse() != null){ txt2.setText("有返回"); SoapObject result = (SoapObject) envelope.bodyIn; String name = result.getProperty(0).toString(); txt1.setText("返回值 = "+name); }else{ txt2.setText("無返回"); } }catch (Exception e) { e.printStackTrace(); } } }
在AndroidManifest.xml進行Activity的注冊和並添加訪問網絡的權限
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="xidian.sl.android.webservice" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="10" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".WebServiceSimpleDemo" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <!-- 聲明該應用自身所擁有的權限 --> <uses-permission android:name="android.permission.INTERNET" /> </manifest>
運行后的結果如圖所示:
下面我們來試着調用回傳符合對象的方法:
activity:
package xidian.sl.android.webservice; import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; import android.app.Activity; import android.os.Bundle; import android.widget.EditText; public class WebServiceComplexDemo extends Activity{ final static String SERVICE_NS = "http://webService.service.sl.xidian/"; final static String SERVICE_URL = "http://192.168.1.103:8090/WebExam/services/test"; private EditText txt1; private EditText txt2; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); txt1 = (EditText) findViewById(R.id.editText1); txt2 = (EditText) findViewById(R.id.editText2); //調用的方法 String methodName = "getStuList"; //創建httpTransportSE傳輸對象 HttpTransportSE ht = new HttpTransportSE(SERVICE_URL); ht.debug = true; //使用soap1.1協議創建Envelop對象 SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); //實例化SoapObject對象 SoapObject request = new SoapObject(SERVICE_NS, methodName); /** * 設置參數,參數名不一定需要跟調用的服務器端的參數名相同,只需要對應的順序相同即可 * */ //request.addProperty("name", "1006010054"); //將SoapObject對象設置為SoapSerializationEnvelope對象的傳出SOAP消息 envelope.bodyOut = request; try{ //調用webService ht.call(null, envelope); txt2.setText("回傳的值 :"+envelope.getResponse()); if(envelope.getResponse() != null){ SoapObject result = (SoapObject) envelope.bodyIn; SoapObject soapChilds = (SoapObject)result.getProperty(0); StringBuffer sb = new StringBuffer(); for(int i=0; i <soapChilds.getPropertyCount(); i++){ SoapObject soapChildsChilds = (SoapObject)soapChilds.getProperty(i); sb.append("姓名["+i+"] = "+soapChildsChilds.getProperty(0).toString()+"\n"); sb.append("學號["+i+"] = "+soapChildsChilds.getProperty(1).toString()+"\n"); sb.append("性別["+i+"] = "+soapChildsChilds.getProperty(2).toString()+"\n"+"\n"); } txt1.setText(sb.toString()); }else{ txt1.setText("無返回"); } }catch (Exception e) { e.printStackTrace(); } } }
區別就是對於返回值的處理上,使用幾次getPropert()方法,這里主要看返回值的層次,看下面的結果應該就能明白了,根據括號的層次來進行確定