結合Retrofit使用post請求訪問WebService

背景

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

工具準備

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

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

開工

RESTClient界面

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


圖1

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

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


    圖2

調試http請求

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


圖3

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


圖4

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

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

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

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


圖7

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

開始寫Demo

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


導包
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'
    }
請求體實例

對應圖2中Request的Body部分,需要寫三個類來作為請求體.分別對應請求體中的三個節(jié)點
根據由外到內的層級關系,它們分別是(類名 <---> 節(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é)點名稱,因為當前節(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é)點名稱,因為當前節(jié)點只有一個命名空間,因此使用Namespace注解而不是NamespaceList.Element注解指定子節(jié)點名稱,因為當前節(jié)點有兩個子節(jié)點,因此這個類有兩個參數,且都被Element注解修飾.
到這里,關于請求體的實體類,就創(chuàng)建好了.下面我們準備響應體的實體類.

響應體實例

跟請求體類似,我們也是需要根據服務器響應的xml文件格式來創(chuàng)建實體類.
通過分析xml格式,我們也需要創(chuàng)建三個實體類來分別對應三個節(jié)點.它們的對應關系如下(類名 <---> 節(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的地址,上面有關于xml與實體類之間綁定的詳細介紹:
SimpleXml

創(chuàng)建Interface

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

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);
}

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

使用Retrofit請求

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

    /**
     * 去服務端請求數據
     */
    private void request() {
        String url = "http://192.168.191.1:2000/";
        // 初始化Retrofit
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(SimpleXmlConverterFactory.create()) // 返回數據為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) {
                // 處理響應體
                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) {

            }
        });
    }

總結

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

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

友情鏈接更多精彩內容