標籤:
PS:終於可以抽出時間寫寫部落格了,忙著學校的三周破實訓外加替考...三周了,沒怎麼學習...哎...
學習內容:
1.WebService 實現遠程方法的調用
什麼是WebService...
WebService顧名思義,就是Web服務,WebService的資料轉送格式是基於XML文檔規範的,資料資訊的傳輸就是以XML的形式來完成...由於XML不受平台和語言的限制,也正是由於這樣的原因使得WebService可以實現遠程調用,調用服務的語言可以是任意的.
什麼是SOAP協議...
SOAP協議被稱之為簡易物件存取通訊協定 (SOAP),它的作用是用來描述資訊的傳輸格式...一條SOAP訊息其實就是一個XML文檔,SOAP可以規定一條訊息是由誰進行發送的,並且由誰進行接收和處理,這就屬於SOAP的封裝,它基於XML的資料格式和Http的傳輸協議定義了一組標準的資料轉送對象...說白了就是基於Http協議完成XML資料資訊的傳遞...
什麼是WSDL...
如果說SOAP用來完成資料資訊的傳遞,那麼WSDL就是規定資料資訊以怎樣的方式進行傳遞,WSDL是WebService的描述語言,目的是描述WebService上的每一個函數,我們知道函數調用的前提是:需要知道函數的功能,以及函數調用需要傳遞的相關參數,還有傳回值,只有知道了這些點,我們才能夠對一個函數進行調用,那麼WSDL就是用來完成這個功能的,它基於XML文檔,是一個機器可以解析的一個標準文檔...其實就是一個描述應用函數的規範...
什麼是uddi...
uddi是WebService的第三大要素,它的功能是完成WebService的註冊和搜尋,搜尋其實就是在網路上的眾多方法去尋找我們需要的那個方法...註冊則是產生一個新的函數...
以上就是WebService的三大要素,可能有點蒙,總結來說就是,uddi完成調用服務的尋找,尋找到了調用函數時,在擷取WSDL之後,我們就可以對其進行調用,調用的過程中,傳遞的對象為SOAP封裝好的對象...
如何調用WebService才是主要的....
WebService的調用過程其實非常的簡單...我們只需要知道調用函數時需要傳遞的參數,以及函數對應的url就可以輕鬆完成遠程方法的調用...
調用WebService需要使用到一個ksoap2-android-assembly-3.0.0-jar-with-dependencies.jar的包...這個包的,我會在最後進行給出...
先附上一段代碼...這個用來調用某城市天氣情況的查詢的一個遠程方法...
package com.example.webservice_web;import java.io.IOException;import org.ksoap2.SoapEnvelope;import org.ksoap2.serialization.SoapObject;import org.ksoap2.serialization.SoapSerializationEnvelope;import org.ksoap2.transport.HttpTransportSE;import org.xmlpull.v1.XmlPullParserException;import android.os.Bundle;import android.app.Activity;import android.view.Menu;import android.view.View;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity implements View.OnClickListener { String NAMESPACE="http://WebXml.com.cn/"; //命名空間.... String url="http://www.webxml.com.cn/webservices/weatherwebservice.asmx"; //方法的url.. String METHOD_NAME="getWeatherbyCityName"; //需要調用的方法名... String SOAP_ACTION="http://WebXml.com.cn/getWeatherbyCityName"; //一般為命名空間+方法名稱... /** * 上面這四種屬性,我們可以通過方法的相關服務資訊找到,相關資訊其實就是WSDL文檔..其中包含了上述資訊的內容... * 通過WSDL明確了方法調用時需要傳遞的相關參數,我們就可以調用這個遠程方法了... * */ String weatherToday; SoapObject detail; //接收函數的傳回值... String weatherNow; String weatherWillBe; private TextView tv; private EditText et; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et=(EditText) findViewById(R.id.et); findViewById(R.id.bt).setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void onClick(View v) { // TODO Auto-generated method stub switch(v.getId()){ case R.id.bt: tv=(TextView) findViewById(R.id.tv); SoapObject rpc=new SoapObject(NAMESPACE, METHOD_NAME); String cityname=et.getText().toString(); rpc.addProperty("theCityName", cityname);//添加參數..目的為了調用服務端提供的方法... /* * 執行個體化SoapSerializationEnvelope對象... * */ SoapSerializationEnvelope envelope=new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.bodyOut=rpc; envelope.dotNet=true; envelope.setOutputSoapObject(rpc);//設定輸出的參數為rpc HttpTransportSE ht=new HttpTransportSE(url); ht.debug=true; try { // Toast.makeText(getBaseContext(), "aa", Toast.LENGTH_LONG).show(); ht.call(SOAP_ACTION, envelope); Toast.makeText(getBaseContext(), "bb", Toast.LENGTH_LONG).show(); detail=(SoapObject) envelope.getResponse(); String date=detail.getProperty(6).toString(); weatherToday="\n天氣:"+date.split(" ")[1]; weatherToday=weatherToday+"\n氣溫:"+detail.getProperty(5).toString(); weatherToday=weatherToday+"\n風力:"+detail.getProperty(7).toString(); weatherNow=detail.getProperty(8).toString(); weatherWillBe=detail.getProperty(9).toString(); tv.setText(et.getText().toString()+weatherToday); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (XmlPullParserException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }}
很簡單的一段代碼,但是有很多要說的地方...WebService的調用首先需要知道SOAP_ACTION,URL,Method,NAMESPACE...url我們可以直接擷取的到...至於其他三個相關資訊,我們可以通過查看WSDL文檔直接就會擷取到...那麼知道了這些資訊之後,我們才能夠定義SOAP對象...SOAP把傳遞的參數,需要調用的方法,定義發送源和接收源...把這些資訊封裝在SOAP對象中,以資料流的形式發送到伺服器,伺服器在擷取到這些資料之後,完成方法的調用,然後把返回的資料資訊仍然以流的形式返回給用戶端...這個用戶端對返回的資訊進行接收,那麼整體就完成了遠程方法的調用...下面說一下整體的實現過程...
首先我們需要執行個體化一個SoapObject...執行個體化SoapObject對象需要調用new函數產生...下面是調用的源碼過程...通過傳遞命名空間和方法名來執行個體化一個SoapObject對象..
/** * Creates a new <code>SoapObject</code> instance. * * @param namespace the namespace for the soap object * @param name the name of the soap object */ public SoapObject(String namespace, String name) { this.namespace = namespace; this.name = name; }
那麼執行個體化一個對象之後我們需要向這個對象中加入屬性值,調用addProperty()方法...其實目的就是為了傳遞參數...下面是源碼的調用過程...
/** * Adds a property (parameter) to the object. This is essentially a sub element. * * @param name The name of the property * @param value the value of the property */ //源碼的意思就是為這個SoapObject對象配置兩個屬性,一個是名字屬性,一個是值屬性... public SoapObject addProperty(String name, Object value) { PropertyInfo propertyInfo = new PropertyInfo(); propertyInfo.name = name; propertyInfo.type = value == null ? PropertyInfo.OBJECT_CLASS : value.getClass(); propertyInfo.value = value; return addProperty(propertyInfo); }
上面的源碼我們可以看到,這裡的屬性添加是通過執行個體化PropertyInfo對象,然後再次調用addProperty()函數..(註:兩次調用的函數名字一樣,但是方法卻是不一樣的...)這裡解釋一下PorpertyInfo對象的作用...PorpertyInfo是一個類,這個類的作用其實就是對所有屬性資訊的一個儲存...(這裡屬性資訊大家可能並不清楚...其實就是對Object,Integer,String)等基本類型進行儲存,儲存的方式通過getClass()...擷取每一個類的相關資訊,用於賦值...其實不難理解,我們在調用addProperty()傳遞參數時,需要有參數的名字和值,那麼自然也要有參數的屬性,否則在擷取SoapObject對象中的參數時,就無法知道傳遞的參數到底是什麼屬性...這樣PropertyInfo的name,value,type就被附上了初值...最後通過調用addProperty方法..這裡的addProperty(propertyInfo)傳遞的已經轉化成了PorpertyInfo對象了...
/** * Adds a property (parameter) to the object. This is essentially a sub element. * * @param propertyInfo designated retainer of desired property */ public SoapObject addProperty(PropertyInfo propertyInfo) { properties.addElement(propertyInfo); return this; }
這裡調用properties.addElement()方法...addElement()方法...傳遞的參數是(E Object),這裡的E,其實是Vector類型...Vector想必大家都清楚,是一個動態對象數組,通過動態添加對象...這樣Vector通過遍曆的方式,將所有的屬性對象都儲存了起來...
/** * Adds the specified object at the end of this vector. * * @param object * the object to add to the vector. */ public synchronized void addElement(E object) { if (elementCount == elementData.length) { growByOne(); } elementData[elementCount++] = object; modCount++; }
那麼儲存了封裝所有參數的SoapObject對象..自然需要進行傳遞給遠程方法...完成調用....這裡遠程方法的調用需要執行個體化SoapSerializationEnvelope對象...被稱之為序列化後的對象...序列化的含義其實就是把一個類或者對象轉化成流的形式,這樣方便進行傳輸和儲存,序列化後的類或對象無需人為進行處理,如果沒有進行序列化,我們需要人為的定義儲存,轉寄的格式,還有轉化成流都需要我們人為去書寫..這樣會相當的複雜...並且在還原序列化同時,一般的運行環境都會自動進行類和對象的還原..如果人為進行還原的話...仍然會非常的複雜...這樣通過序列化上面的SoapObject對象...就可以指定SoapObject對象傳輸的方式是以流的方式進行傳輸了...這裡調用下面方法...
SoapSerializationEnvelope envelope=new SoapSerializationEnvelope(SoapEnvelope.VER11);下面是源碼過程....這裡執行個體化對象需要指定WebService的版本資訊...
public SoapSerializationEnvelope(int version) { super(version); addMapping(enc, ARRAY_MAPPING_NAME, PropertyInfo.VECTOR_CLASS); DEFAULT_MARSHAL.register(this); }
這裡調用了addMapping方法將儲存了PropertyInfo的對象數組以索引值對的形式儲存在HashTable中...最後通過register方法將儲存好的對象完成序列化封裝的註冊...完成了封裝註冊之後...還需要設定相關的屬性...這裡完成相關屬性的設定...表示封裝的對象為我們先前定義的SoapObject對象...設定訪問的伺服器為.Net伺服器...設定最後輸出的對象仍然為SoapObject對象...
envelope.bodyOut=object; envelope.dotNet=true; envelope.setOutputSoapObject(object);
封裝好了所有的對象之後,就需要使用Http進行Url的串連了...通過HttptransportSE完成WSDL地址的串連...最後使用call方法完成該方法的調用...這樣就完成了遠程方法的調用,如果函數沒有返回資料,那麼我們就不需要進行擷取了...只需要完成資料資訊的上傳就可以了..如果有返回資料,我們還需要定義一個SoapObject來完成返回資料的接收...通過返回的資料資訊擷取我們需要的相關資訊並顯示在自己的應用程式中,這樣就完成了遠程方法的調用...
HttpTransportSE ht=new HttpTransportSE(url); ht.debug=true; try { ht.call(SOAP_ACTION, envelope);
detail=(SoapObject) envelope.getResponse(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (XmlPullParserException e) { // TODO Auto-generated catch block e.printStackTrace(); }
就如同剛開始的代碼,最後返回的是一個SoapObject對象,我們接收到這個對象之後就可以擷取一些我們想要的資料資訊了...
(註:使用網路服務需要設定許可權... <uses-permission android:name="android.permission.INTERNET"/>)....
這樣就完成了遠程方法的調用,實現了不同平台的應用程式之間完成通訊...實現了Web服務的無縫串連...
Android 學習筆記之WebService實現遠程調用+內部原理分析...