結(jié)合Retrofit使用post請求訪問WebService

背景

沒啥背景,實在是受夠了ksoap2這個jar包,而公司服務(wù)端是基于c#語言的.net開發(fā),不懂他們的技術(shù),而他們好像只能通過WebService與我們Android端進行數(shù)據(jù)交互(如果有前輩知道別的技術(shù),望指點!謝謝~).
Retrofit作為當(dāng)前最火的網(wǎng)絡(luò)請求框架.如果不去學(xué),永遠不會用.因此,我想把這個框架引入到公司項目里邊來,把ksoap2替換掉,用Retrofit來訪問WebService
既然有了想法,就要去做.網(wǎng)上關(guān)于Retrofit的講解一大堆,奈何關(guān)于使用Retrofit去訪問WebService的文章少之又少,并且各位前輩的經(jīng)驗都是基于自己公司的業(yè)務(wù)情況總結(jié)出來的,和我現(xiàn)在的情況多少有些出入,因此,我把各位前輩的經(jīng)驗綜合起來,寫了這篇文章,一來,總結(jié)下經(jīng)驗;二來,希望以后有朋友再遇到這種問題的時候,能少走些彎路.
首先將前輩的鏈接奉上:
Retrofit2+Okhttp3+Rxjava通過SOAP協(xié)議請求WebService
在WebService中使用Retrofit+RxJava
轉(zhuǎn)載----使用 Retrofit 操作 SOAP Web Service
也正是有了各位前輩總結(jié)的經(jīng)驗,才有了我今天這篇文章,向各位前輩致敬!
第一次寫文章,如有不妥之處,希望各位前輩指出!

工具準(zhǔn)備

  • FireFox(火狐瀏覽器)
  • RESTClient(火狐瀏覽器調(diào)試插件)

這里,我使用的是火狐瀏覽器+RESTClient去調(diào)試http請求.
因為每個公司定義的格式可能會不一樣.我們在封裝以及分析數(shù)據(jù)的時候需要與之對應(yīng).所以我們?nèi)フ{(diào)試分析http請求.弄清每次請求及響應(yīng)的格式.
關(guān)于soap,WebService以及http,各位前輩已經(jīng)分析的很透徹了,這里我就不多說了,如果想了解的話,可以去看下前輩總結(jié)的文章.下面,咱們正式開始.

開工

RESTClient界面

在火狐瀏覽器中安裝好RESTClient插件后,將其打開,界面應(yīng)該會和圖1類似,是空的,沒有任何數(shù)據(jù).為了方便分析,我又截取了圖2,明顯是一次成功請求后的界面,我先用圖2分析下整個界面,然后再告訴你,這些數(shù)據(jù)都是怎么填上去的.


圖1

在圖2中,我把一次請求分為了兩個部分,分別用綠線和藍線框了起來.其中,綠線內(nèi)是本次http請求發(fā)送的數(shù)據(jù),也就是我們作為Android端需要封裝的數(shù)據(jù),藍線內(nèi),就是本次請求服務(wù)端返回給我們的數(shù)據(jù),也就是我們需要解析的數(shù)據(jù).
我們先來分析下我們需要發(fā)送的數(shù)據(jù),如圖所示,我用紅線標(biāo)出了4個位置,它們分別表示什么意思呢?

  1. Method: 表示這次請求的請求方式,一般常用的有g(shù)et和post,這里當(dāng)然選post(因為WebService就是post請求的一種)
  2. URL: 表示這次請求的地址
  3. Headers: 請求頭
  4. Body: 請求體


    圖2

調(diào)試http請求

介紹完了RESTClient的界面,下面就正式開始http調(diào)試.
所謂調(diào)試,無非就是模擬一次http請求,我們把需要發(fā)送給服務(wù)端的數(shù)據(jù)填到Request(圖2綠線內(nèi))中,點擊send按鈕,然后Response(圖2藍線內(nèi))中顯示服務(wù)端返回給我們的數(shù)據(jù).我們就是分析這堆數(shù)據(jù)而已.那么問題來了,Request中的這些數(shù)據(jù),是從哪來的?
我另外打開了一個瀏覽器頁面,在地址欄中輸入想要調(diào)試的地址,如圖3所示,為了方便,我讓服務(wù)端同事把服務(wù)器部署到我的電腦上了,所以看到的地址ip是192.168.191.1,
剛剛在地址欄輸入的就是這次要調(diào)試的地址,因此,我把他填入到了RESTClient的URL中.
既然url確定了,那請求頭(Headers)和請求體(Body)又該填什么呢?別急,接著往下看.


圖3

這次我要調(diào)試的就是圖3中紅線內(nèi)的接口.名為AssetMaterialInfo,點擊這個接口,打開的界面如圖4所示.圖中有SOAP1.2請求和響應(yīng)示例,紅線標(biāo)注的是占位符,在模擬數(shù)據(jù)的時候需要將其替換為真實數(shù)據(jù).
而我們所需要的請求頭(Headers)和請求體(Body)就藏在請求示例中.為了方便分析,我單獨將請求示例截取了圖片,放在下邊,也就是圖5.


圖4

圖5中,紅線內(nèi)這兩行內(nèi)容,就是請求頭,藍線內(nèi)的就是請求體.請求體很簡單,我們只需要將藍線中內(nèi)容復(fù)制到RESTClient界面的Body中,然后把占位符替換掉就可以了(如圖2所示),請求頭怎么弄呢?
圖5

關(guān)于在RESTClient中添加請求頭,我舉一個例子(圖6),大家就都明白了.
在RESTClient界面中,點擊頂部Headers,再點擊CustomHeader,會打開圖7這個界面.
圖6

在圖7所示界面,Name欄中填入Content-Type,Value欄中填入text/xml; charset=utf-8,然后點擊Okay,我們就將一個請求頭添加到本次請求中了.

同理,將第二個請求頭也添加進來.我就不再演示了.


圖7

這樣,我們就將本次請求需要攜帶的數(shù)據(jù)都添加進來了.點擊SEND按鈕,就完成了本次請求.

開始寫Demo

拿到了http請求的數(shù)據(jù),我們就可以根據(jù)數(shù)據(jù)去寫我們的例子程序了,在我們Android端通過Retrofit使用post請求去訪問剛剛我們調(diào)試的WebService接口.
首先,在看下邊代碼之前,你要保證自己已經(jīng)基本了解了Retrofit框架.關(guān)于Retrofit不會介紹太多,因為它不是本篇文章的重點.


導(dǎo)包
compile'com.squareup.retrofit2:retrofit:2.0.1'
compile('com.squareup.retrofit2:converter-simplexml:2.1.0') {
        exclude group:'xpp3',module:'xpp3'
        exclude group:'stax',module:'stax-api'
        exclude group:'stax',module:'stax'
    }
請求體實例

對應(yīng)圖2中Request的Body部分,需要寫三個類來作為請求體.分別對應(yīng)請求體中的三個節(jié)點
根據(jù)由外到內(nèi)的層級關(guān)系,它們分別是(類名 <---> 節(jié)點名):

  • RequestEnvelope <---> soap:Envelope
  • RequestBody <---> soap:Body
  • RequestModel <---> AssetMaterialInfo

下面,我詳細介紹下這三個類.

@Root(name = "soap:Envelope")
@NamespaceList({
       @Namespace(reference = "http://www.w3.org/2001/XMLSchema-instance", prefix = "xsi"),
        @Namespace(reference = "http://www.w3.org/2001/XMLSchema", prefix = "xsd"),
        @Namespace(reference = "http://schemas.xmlsoap.org/soap/envelope/", prefix = "soap")
})
public class RequestEnvelope {
      @Element(name = "soap:Body", required = false)
      public RequestBody body;
}

RequestEnvelope類中,Root注解用來指定節(jié)點名稱,NamespaceList用來指定多個命名空間,Element用來指定子節(jié)點名稱.

@Root(name = "soap:Body", strict = false)
public class RequestBody {
    @Element(name = "AssetMaterialInfo", required = false)
    public RequestModel AssetMaterialInfo;
}

同理,RequestBody類中,Root注解用來指定節(jié)點名稱,Element注解用來指定子節(jié)點名稱,因為當(dāng)前節(jié)點沒有命名空間,因此不需要NamespaceList注解

@Root(name = "AssetMaterialInfo", strict = false)
@Namespace(reference = "http://tempuri.org/")
public class RequestModel {
    @Element(name = "date", required = false)
    public String date;
    @Element(name = "page", required = false)
    public int page;
}

RequestModel類中,Root注解用來指定節(jié)點名稱,因為當(dāng)前節(jié)點只有一個命名空間,因此使用Namespace注解而不是NamespaceList.Element注解指定子節(jié)點名稱,因為當(dāng)前節(jié)點有兩個子節(jié)點,因此這個類有兩個參數(shù),且都被Element注解修飾.
到這里,關(guān)于請求體的實體類,就創(chuàng)建好了.下面我們準(zhǔn)備響應(yīng)體的實體類.

響應(yīng)體實例

跟請求體類似,我們也是需要根據(jù)服務(wù)器響應(yīng)的xml文件格式來創(chuàng)建實體類.
通過分析xml格式,我們也需要創(chuàng)建三個實體類來分別對應(yīng)三個節(jié)點.它們的對應(yīng)關(guān)系如下(類名 <---> 節(jié)點名):

  • AssetResponseEnvelope <---> soap:Envelope
  • AssetResponseBody <---> Body
  • AssetResponseModel <---> AssetMaterialInfoResponse

為了與系統(tǒng)類名區(qū)分開,我為這三個類名添加了Asset前綴.

@Root(name = "soap:Envelope")
@NamespaceList({
        @Namespace(reference = "http://www.w3.org/2001/XMLSchema-instance/", prefix = "xsi"),
        @Namespace(reference = "http://www.w3.org/2001/XMLSchema/", prefix = "xsd"),
        @Namespace(reference = "http://schemas.xmlsoap.org/soap/envelope/", prefix = "soap")
})
public class AssetResponseEnvelope {
    @Element(name = "Body", required = false)
    public AssetResponseBody responseBody;
}
@Root(name = "Body", strict = false)
public class AssetResponseBody {
    @Element(name = "AssetMaterialInfoResponse", required = false)
    public AssetResponseModel responseModel;
}
@Root(name = "AssetMaterialInfoResponse")
public class AssetResponseModel {
    @Attribute(name = "xmlns", empty = "http://tempuri.org/", required = false)
    public String nameSpace;
    @Element(name = "AssetMaterialInfoResult")
    public String result;
}

因為與請求體類似,這里我也不用對這三個類做過多介紹.不過,值得一提的是,在AssetResponseModel類中,我沒有再用Namespace注解去指定命名空間,而是添加了一個成員變量,用Attribute注解將其指定.需要注意的是,再用Attribute注解指定的時候,name,empty,required三個屬性,缺一不可.
下面奉上SimpleXml的地址,上面有關(guān)于xml與實體類之間綁定的詳細介紹:
SimpleXml

創(chuàng)建Interface

三個請求類和三個響應(yīng)類創(chuàng)建好了,下一步就是創(chuàng)建請求接口Interface.(不明白為啥要這樣做的,可以去復(fù)習(xí)下Retrofit,哦不對,是預(yù)習(xí)~)
直接上代碼:

public interface ApiStore {
    @Headers({
            "Content-Type: text/xml; charset=utf-8",
            "SOAPAction: http://tempuri.org/AssetMaterialInfo"
    })
    @POST("GetService.asmx")
    Call<AssetResponseEnvelope> getAssetInfo(@Body RequestEnvelope requestEnvelope);
}

在請求接口中,我們定義了一個函數(shù),將其請求方式制定為post請求,并且為其添加了請求頭.這個函數(shù)接收一個RequestEnvelope參數(shù).

使用Retrofit請求

所有初始化工作都做完之后,使用Retrofit去請求WebService這塊還是蠻簡單的.
不得不說,Retrofit確實很強大,整個請求流程下來,結(jié)構(gòu)清晰明了,一點都不拖泥帶水.如果再結(jié)合上RxJava,豈不是更爽?

    /**
     * 去服務(wù)端請求數(shù)據(jù)
     */
    private void request() {
        String url = "http://192.168.191.1:2000/";
        // 初始化Retrofit
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(SimpleXmlConverterFactory.create()) // 返回數(shù)據(jù)為xml,因此要加入xml解析
                .build();
        ApiStore apiStore = retrofit.create(ApiStore.class);
        // 初始化請求體
        RequestModel requestModel = new RequestModel("2012-01-01", 0);
        RequestBody requestBody = new RequestBody(requestModel);
        RequestEnvelope requestEnvelope = new RequestEnvelope(requestBody);
        // 開始請求
        Call<AssetResponseEnvelope> call = apiStore.getAssetInfo(requestEnvelope);
        call.enqueue(new Callback<AssetResponseEnvelope>() {
            @Override
            public void onResponse(Call<AssetResponseEnvelope> call, Response<AssetResponseEnvelope> response) {
                // 處理響應(yīng)體
                AssetResponseEnvelope responseEnvelope = response.body();
                if (responseEnvelope == null) {
                    Log.d(TAG, "onResponse: responseEnvelope == null");
                    return;
                }
                AssetResponseBody responseBody = responseEnvelope.responseBody;
                if (responseBody == null) {
                    Log.d(TAG, "onResponse: responseBody == null");
                    return;
                }
                AssetResponseModel responseModel = responseBody.responseModel;
                if (responseModel == null) {
                    Log.d(TAG, "onResponse: responseModel == null");
                    return;
                }
                String result = responseModel.result;
                Log.d(TAG, "onResponse: result : " + result);
//                showResult(result);
            }

            @Override
            public void onFailure(Call<AssetResponseEnvelope> call, Throwable t) {

            }
        });
    }

總結(jié)

到此為止,一個基于Retrofit使用post請求訪問WebService的小Demo就算寫完了.我已經(jīng)將代碼提交到了GitHub,感興趣的同學(xué)可以去看一下,很簡單的小程序.
項目地址
有不明白的同學(xué),歡迎向我提出問題,我們共同學(xué)習(xí).
第一次寫文章,還望各位前輩多多批評指正,不勝感激!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末含蓉,一起剝皮案震驚了整個濱河市亩歹,隨后出現(xiàn)的幾起案子承二,更是在濱河造成了極大的恐慌驰怎,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件否过,死亡現(xiàn)場離奇詭異不脯,居然都是意外死亡卫枝,警方通過查閱死者的電腦和手機酣倾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門舵揭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人灶挟,你說我怎么就攤上這事琉朽《咀猓” “怎么了稚铣?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長墅垮。 經(jīng)常有香客問我惕医,道長,這世上最難降的妖魔是什么算色? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任抬伺,我火速辦了婚禮,結(jié)果婚禮上灾梦,老公的妹妹穿的比我還像新娘峡钓。我一直安慰自己,他們只是感情好若河,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布能岩。 她就那樣靜靜地躺著,像睡著了一般萧福。 火紅的嫁衣襯著肌膚如雪拉鹃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音膏燕,去河邊找鬼钥屈。 笑死,一個胖子當(dāng)著我的面吹牛坝辫,可吹牛的內(nèi)容都是我干的篷就。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼近忙,長吁一口氣:“原來是場噩夢啊……” “哼腻脏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起银锻,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤永品,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后击纬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鼎姐,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年更振,在試婚紗的時候發(fā)現(xiàn)自己被綠了炕桨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡肯腕,死狀恐怖献宫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情实撒,我是刑警寧澤姊途,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站知态,受9級特大地震影響捷兰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜负敏,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一贡茅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧其做,春花似錦顶考、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至浮庐,卻和暖如春甚负,著一層夾襖步出監(jiān)牢的瞬間柬焕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工梭域, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留斑举,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓病涨,卻偏偏與公主長得像富玷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子既穆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,756評論 25 707
  • 整體Retrofit內(nèi)容如下: 1赎懦、Retrofit解析1之前哨站——理解RESTful2、Retrofit解析2...
    隔壁老李頭閱讀 3,978評論 8 19
  • 1.下載:打開http://www.xmindchina.net/點擊免費下載 2.下載完成雙擊xmind-8-w...
    三玉米閱讀 1,582評論 0 4
  • 好吧幻工,那就去上咯~BUT励两!我們剛到實測地點-翰林苑,又被告知老師一次只帶一個班囊颅,今天三班上課当悔,我們是明天。歐踢代!然后...
    許小小麗閱讀 260評論 1 2
  • 快速讀完《舒克貝塔傳》盲憎。 童話故事不僅僅是寫給小孩子看的。作者借著鼠口道出的胳挎,是人世間常見的現(xiàn)象饼疙。自然而然地,讓我...
    夏又幽閱讀 447評論 0 0