Retrofit2+Okhttp3+Rxjava通過SOAP協議請求WebService

qsbn8763 8年前發布 | 39K 次閱讀 OkHttp SOAP Retrofit Android開發 移動開發

前言

剛入職新公司,負責其Android App的開發,他們的接口訪問是通過SOAP協議實現的(基于xml數據格式的數據交換規范),由于之前也沒有接觸過這種東西,對此也是一臉懵逼,好在公司之前通過AnsysTask封裝了SOAP的工具類,那就先做個一不明真相的吃瓜群眾,直接拿來使用吧。

先用著再說

作為一個有上進心的程序員,你會甘心停止不前么?管你會不會,反正我是不會哈哈哈.....在使用的過程中發現AnsysTask封裝的SOAP還是存在一定的 缺陷(具體是什么就不闡述了QAQ),由于項目的功能還在擴充,需求也在不斷的改,我就想對 這種請求進行優化,可是那個封裝代碼寫得那叫一個亂,關鍵還沒注釋(哎呀。。。腦袋瓜子疼,你知道這是有多么痛苦!),受盡折磨,果斷放棄不干。前段時間公司要重新開發一個App,我打算放棄之前的架構,重新開始,包括網絡請求框架,可是選擇什么比較好呢?打開技術論壇你就會發現什么Retrofit啊,okhttp,Rxjava,MVP的架構模式之間的各種整合的Demo,發展可謂是風生水起,這么好的東西我也不會錯過嘿嘿,當然每個工具都有它流行的意義,經過一段時間對它們的了解,最終決定使用etrofit2+Okhttp3+Rxjava封裝SOAP來請求WebService,當然這其中也有過坎坷,畢竟網上對于這種問題的提問和回答少之又少。

輾轉很久,最終谷歌給我了答案,所以我決定把我的經驗進行分享,希望對有需求的小伙伴有所幫助。接下來我會對具體實現進行詳細分析。

分析

什么是SOAP?

它是基于xml規范的數據交換協議,WebServices就是基于 XML 和 HTTP 的,簡單點講使用soap對WebServices進行訪問請求就是普通的HTTP,只不過參數類型是以XML的格式進行傳遞和交流,明白了這點,我們就可以對我們的請求參數進行封裝,封裝成為WebServices能夠識別的數據格式進行普通的Http請求就可以,管它后臺服務器是java寫的還是.NET寫的,這時就與我們無關了,但是每個公司定義的數據類型各不相同,在拼接封裝時候需要對數據進行分析和調試。

首先我們需要使用HTTP請求的調試工具,這類工具很多,我這里使用REST Client,它是一個谷歌瀏覽器的插件,安裝到谷歌瀏覽器里很方便使用,在調試之前還是先看一下請求和返回的數據格式規范(這是我們公司的一個接口數據規范)。

這個是數據請求的格式

每次請求服務器都會對你的請求進行驗證,里面有“UserName”和“PassWord”(可能是為了安全性考慮需要驗證吧),然后就是請求參數,該參數是一個String類型的字符串,如果是多個參數的話需要拼接成一個字符串進行處理。該字符串也是有嚴格的規范,一不小心就會掉入坑中,別問我是怎么知道的O.o(曾經爬了一天才脫坑)。

這個是返回數據的格式

真正的返回有效數據就是里面的String。

知道了數據的請求和返回的數據格式,接著我們就可以進行調試了

http模擬請求

參數類型的拼接需要遵循這樣的規范,這里需要對“<”和“>”進行 轉義字符處理,否則的話就直接當作xml的節點了,這樣的話是不符合服務器的參數規法就會返回錯誤數據,可以測試一下,效果如下:

參數沒有進行處理

這個時候就會返回失敗:

參數錯誤,返回失敗

請求參數規范,需要轉義字符

請求成功返回的json數據

由以上的調試我們可以發現,在進行soap請求只是參數和頭部信息不同而已,事實就是這樣,我們把它當作普通http請求,在參數上動點手腳就可以了。從數據的請求格式可以看出每一個請求都不許要添加Content-Type: text/xml; charset=utf-8,這是用來說明我們上傳的參數類型是xml格式的,SOAPAction: "http://tempuri.org/ADInquiry"這里調用的每個接口都不一樣,其實不一樣的就是“ADInquiry”這個參數會變化。

返回的數據類型也是xml形式的,我們可以把返回數據看作字符串來進行處理。對數據進行適當截取,里面的json才是我們真正想要的。

分析到這里已經差不多了,廢話不多說,直接擼代碼!

具體實現

開始之前先放出鎖需要的依賴:

Rxjava依賴:

compile'io.reactivex:rxandroid:1.2.1'

compile'io.reactivex:rxjava:1.1.6' </code></pre>

OkHttp依賴:

compile'com.squareup.okhttp3:okhttp:3.4.1'

compile'com.squareup.okhttp3:logging-interceptor:3.4.1'

compile'com.squareup.okhttp3:okhttp-urlconnection:3.4.1'</code></pre>

Retrofit依賴:

compile'com.squareup.retrofit2:retrofit:2.0.1'

compile'com.squareup.retrofit2:converter-scalars:2.1.0'

compile'com.squareup.retrofit2:converter-gson:2.1.0'

compile('com.squareup.retrofit2:converter-simplexml:2.1.0') {

excludegroup:'xpp3',module:'xpp3'

excludegroup:'stax',module:'stax-api'

excludegroup:'stax',module:'stax'

}</code></pre>

新建Interface請求接口:

需要通過注解方法添加頭部信息

需要對請求的參數進行拼接處理,這里我們選擇字符串的拼接,可能有的人會問,simplexml支持實體類的拼接啊,通過注解就可以輕松實現xml數據的轉化,為什么不用而選擇字符串呢?答案就是封裝!封裝!封裝!(重要話說三遍),因為我們的請求數據格式字段比較多,每個接口請求的話大約需要建立五個實體并且進行賦值,記得,是每個接口,這是多么繁重的工作,果斷拋棄,但是呢,我還是打算在文章最后對這種使用方法進行簡單說明一下,誰讓Retrofit如此強大呢!

對請求參數進行拼接處理

封裝RequestManager網絡請求工具類,采用單例模式:

public final static intCONNECT_TIMEOUT=10;

public final static intREAD_TIMEOUT=20;

public final static intWRITE_TIMEOUT=10;

public RetrofitmRetrofit;

protected Map  params;

private staticRequestManager manager;//管理者實例

publicOkHttpClient mClient;//OkHttpClient實例</code></pre>

在構造方法中進行數據初始化:

1:對OkHttp進行緩存,請求超時,重連機制進行設置;

2:對Retrofit進行設置并與OkHttp進行關聯;

private RequestManager() {

Strategy strategy =newAnnotationStrategy();

Serializer serializer =newPersister(strategy);

HttpLoggingInterceptor interceptor =newHttpLoggingInterceptor();

interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

File httpCacheDirectory =newFile(App.getInstance().getCacheDir(),"retrofit");

intcacheSize =3210241024;

Cache cache =newCache(httpCacheDirectory, cacheSize);

OkHttpClient.Builder builder =newOkHttpClient.Builder();

builder.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);

builder.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);

builder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);

builder.retryOnConnectionFailure(true);

builder.addInterceptor(interceptor);

builder.addNetworkInterceptor(getNetWorkInterceptor());

builder.addInterceptor(getInterceptor());

builder.cache(cache);

mClient= builder.build();

mRetrofit=newRetrofit.Builder()

.baseUrl(Constans.WEBSERVICE_URL)

.addConverterFactory(ScalarsConverterFactory.create())

.addConverterFactory(GsonConverterFactory.create())

.addConverterFactory(SimpleXmlConverterFactory.create(serializer))

.client(mClient)

.build();

}</code></pre>

新建execute()方法,主要請求和處理網絡數據,服務器返回的 數據是xml形式,我們需要對數據進行解析,把結果看作String類型的字符串,然后進行分割就可以得到json數據:

execute

鐺鐺.....Rxjava上場了,doRequest方法內部就是通過Rxjava,把異步的結果返回到主線程,輕松實現主線程與非主線程之間的相互切換(是不是突然也感覺到Rxjava真是太好用了),否則的話,你第一時間想到的可能就是Handler。

doRequest

對OkHttp攔截器進行設置,有網絡時候請求數據,沒有網絡從緩存讀取 數據,比較遺憾的是還沒有找到更好的方法去設置SOAP的緩存(貌似SOAP不支持緩存),普通的請求是完全支持的:

攔截器設置

定義一個RequestCallBack接口,用于把請求結果進行回調處理:

public interfaceRequestCallBack {

voidonSueecss(String msg);

voidonError(String msg);

voidonStart();

voidonFinish();

} </code></pre>

調用方式,由于項目是基于MVP模式來寫的,接口層次比較多,這里就簡單的說明一下調用方式:

Map map=newHashMap<>();

map.put("DoctorMobile",name);

map.put("Password",psd);

map.put("PhoneType","0");

map.put("ClientID","");

map.put("DeviceToken","");

String result= Node.getResult("MSDoctorLogin",map);

finalServiceStore service=manager.create(ServiceStore.class);

Call call=service.login(result);</code></pre>

Map集合里面存放的就是參數的值,然后通過Node的getResult()方法進行數據拼接,返回拼接后帶參數的字符串。對于json字符串的解析有很多方法和工具類,Retrofit也可以對返回json進行轉化,這里我就使用最原始的解析方式。

execute

execute

以上就是Retrofit+Soap對webservice進行訪問請求具體實現,該實現是通過String字符串的拼接,傳輸過程中轉化為xml數據格式來實現的,接下來順便提一下另一種方式,通過SimpleXml注解實體類的方式實現轉化。對SimpleXml不太了解的話可以在網上百度一下,使用很簡單,

廢話不多說,我們用代碼說話!

通過對請求數據格式的分析可以清晰的看到,里面包含五個節點,分別為:soap:Envelope,soap:Header,Identify,soap:Body,ADInquiry,好的,就是這樣,毫無疑問需要建立五個實體類。

Envelope實體類:

根節點Envelope

Header實體類:

Header實體類

Identify實體類:

Identify實體類

Body實體類:

Body實體類

ADInquiry實體類:

ADInquiry實體類

請求接口:

請求接口

注意這個時候getInfo()方法里面的參數就是一個實體。

對實體進行初始化和賦值:

初始化和賦值

進行請求:

進行請求

OK,大功告成,可以進行數據請求了,請求的結果我就通過log輸出,親自測試成功訪問。

 

來自:http://www.jianshu.com/p/b865c855a1e8

 

 本文由用戶 qsbn8763 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!