Retrofit2+Okhttp3+Rxjava2 Request Web Service through SOAP Protocol
Shortly after joining the new company, I spent nine nights and two tigers reading the company's source code, describing it in two words as "bedroom". What's this writing about? After consulting with the leaders, I intend to reconstruct the source code in my spare time. It's mainly one of the most frequent network requests (feeling is talking nonsense). I found that the backstage is Web Service, which used to be JAVA, which I haven't done before. After consulting, Ksoap2 can be used for requests. It is found that Ksoap2 is troublesome. It is not as easy as okhttp+Retrofit before. So it simply encapsulates a SOAP protocol request Library Based on Retrofit2+Okhttp3+Rxjava2.
Third-party dependency //retrofit dependency compile 'com.squareup.retrofit2:retrofit:2.2.0' //XML parsing compile('com.squareup.retrofit2:converter-simplexml:2.2.0') { exclude group: 'xpp3', module: 'xpp3' exclude group: 'stax', module: 'stax-api' exclude group: 'stax', module: 'stax' } compile 'com.squareup.retrofit2:converter-gson:2.2.0' compile 'com.squareup.retrofit2:converter-scalars:2.2.0' compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0' //OkHttp dependence compile 'com.squareup.okhttp3:okhttp:3.7.0' compile 'com.squareup.okhttp3:logging-interceptor:3.7.0' compile 'com.squareup.okhttp3:okhttp-urlconnection:3.7.0' //RxJava dependence compile 'io.reactivex.rxjava2:rxandroid:2.0.1' // Because RxAndroid releases are few and far between, it is recommended you also // explicitly depend on RxJava's latest version for bug fixes and new features. compile 'io.reactivex.rxjava2:rxjava:2.0.9'
Request Envelope
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.NamespaceList;
import org.simpleframework.xml.Root;
@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;
public RequestEnvelope(RequestBody body) {
this.body = body;
}
}
Request Body
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
@Root(name = "soap:Body", strict = false)
public class RequestBody {
@Element(name = "Move_GetDate", required = false)
public RequestModel AssetMaterialInfo;
public RequestBody(RequestModel assetMaterialInfo) {
AssetMaterialInfo = assetMaterialInfo;
}
}
Request Body Request Model
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;
@Root(name = "Move_GetDate", strict = false)
@Namespace(reference = "http://tempuri.org/")
public class RequestModel {
@Element(name = "Code", required = false)
public String Code;
@Element(name = "Info", required = false)
public String Info;
@Element(name = "SNum", required = false)
public String SNum;
@Element(name = "yhnm", required = false)
public String yhnm;
@Element(name = "ipdz", required = false)
public String ipdz;
public RequestModel(String Code, String Info,String SNum,String yhnm,String ipdz) {
this.Code = Code;
this.Info = Info;
this.SNum = SNum;
this.yhnm = yhnm;
this.ipdz = ipdz;
}
}
Next comes the response body, Response Envelope.
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.NamespaceList;
import org.simpleframework.xml.Root;
// Specify the node name, soap: can be omitted, that is @Root (name = Envelope)
// When the class name is the same as the node name, the name attribute can be omitted, i.e. @Root
@Root(name = "soap:Envelope")
// Specify a namespace collection that can nest multiple @Namespace annotations internally
@NamespaceList({
/*
* Specify the namespace, the reference attribute specifies the namespace name, and the prefix attribute specifies the prefix.
* For example:
* The namespace is: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
* The annotation is @Namespace (reference = http://www.w3.org/2001/XMLSchema-instance/), prefix = xsi)
*/
@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 ResponseEnvelope {
// Specifying the node name of the child node should correspond to the @Root annotation of AssetResponseBody
@Element(name = "Body", required = false)
public ResponseBody responseBody;
}
Response Body
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
@Root(name = "Body", strict = false)
public class ResponseBody {
@Element(name = "Move_GetDateResponse", required = false)
public ResponseModel responseModel;
}
Response Body Response Model
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
@Root(name = "Move_GetDateResponse")
public class ResponseModel {
@Attribute(name = "xmlns", empty = "http://tempuri.org/", required = false)
public String nameSpace;
@Element(name = "Move_GetDateResult")
public String result;
}
Then there's the API.
public interface ApiStore {
/*
* Specify the request header:
* "Content-Type: text/xml; charset=utf-8"Specify text format, and encoding format
* SOAPAction The value is
* Decomposition into http://tempuri.org/+Move_GetDate, which is actually namespace+interface name
*/
@Headers({
"Content-Type: text/xml; charset=utf-8",
"SOAPAction: http://tempuri.org/Move_GetDate"
})
@POST("DBHelperOra.asmx")
Observable<ResponseEnvelope> getAssetInfo(@Body RequestEnvelope requestEnvelope);
}
public static NetWorkClient getApiService() {
if (apiStore == null) {
apiStore = createService(ApiStore.class);
}
return netWorkClient;
}
/**
* Default OKHttp configuration
* @return
*/
private static OkHttpClient.Builder getdefOkhttp() {
//Log correlation
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
okHttpClient.connectTimeout(10, TimeUnit.SECONDS);
okHttpClient.readTimeout(10, TimeUnit.SECONDS);
okHttpClient.writeTimeout(10, TimeUnit.SECONDS);
okHttpClient.addInterceptor(definterceptor);
okHttpClient.addInterceptor(logging);
//Failure reconnect
okHttpClient.retryOnConnectionFailure(true);
return okHttpClient;
}
/**
* Default interceptor GET
* The default interceptor cache is only for GET requests and does not cache POST
*/
private static Interceptor defcacheInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!NetWorkUtil.isConnect(mContext)) {//Mandatory read from cache without network
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
Response responseLatest;
if (NetWorkUtil.isConnect(mContext)) {
int maxAge = 0; //Setting up a cache timeout time of 0 hours when there is a network
responseLatest = response.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader("Pragma")// Clear header information, because if the server does not support it, it will return some interference information. Clear header information will not take effect below.
.build();
} else {
int maxStale = 60 * 60 * 72; // Failure of power grid for 72 hours
responseLatest = response.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader("Pragma")
.build();
}
return responseLatest;
}
};
/**
* cache
*
* @return
*/
private static Cache defcache() {
int cacheSize = 10 * 1024 * 1024;
if (mContext == null) {
throw new NullPointerException("Not in Application Middle initial");
}
return new Cache(PathUtils.getDiskCacheDir(mContext, BASE_CACHE_PATH), cacheSize);
}
private static <T> T createService(Class<T> serviceClass) {
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------
OkHttpClient.Builder okHttpClient = getdefOkhttp();
//Setting Cache Directory
okHttpClient.cache(defcache());
//Set cache
okHttpClient.addInterceptor(defcacheInterceptor);
okHttpClient.addNetworkInterceptor(defcacheInterceptor);
//--------------------------------------------------------------
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
//Setting up OKHttpClient
.client(okHttpClient.build())
.addConverterFactory(ScalarsConverterFactory.create())
//gson converter
// .addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(SimpleXmlConverterFactory.create(new Persister(new AnnotationStrategy())))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//
.build();
return retrofit.create(serviceClass);
}
/**
* Specific mode of request
* @param requestEnvelope
* @param callBack
*/
public static void execute(RequestEnvelope requestEnvelope, final RequestCallBack callBack) {
apiStore.getAssetInfo(requestEnvelope)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ResponseEnvelope>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.d("msg", "onSubscribe");
callBack.onStart();
}
@Override
public void onNext(@NonNull ResponseEnvelope responseEnvelope) {
String str = responseEnvelope.responseBody.responseModel.result;
Log.d("msg///////", str);
onNext(responseEnvelope);
}
@Override
public void onError(@NonNull Throwable e) {
Log.d("msg", e.getMessage());
callBack.onFail(e.getMessage());
}
@Override
public void onComplete() {
Log.d("msg", "---------------------------------------------");
callBack.onEnd();
}
});
Request mode
// Initialization request body
RequestModel requestModel = new RequestModel("CodeData",
"InfoData",
"SNumData",
"yhnmData",
"ipdzData");
RequestBody requestBody = new RequestBody(requestModel);
RequestEnvelope requestEnvelope = new RequestEnvelope(requestBody);
NetWorkClient.getApiService().execute(requestEnvelope, new RequestCallBack() {
@Override
public void onStart() {
}
@Override
public void onEnd() {
}
@Override
public void onResponse(ResponseEnvelope response) {
}
@Override
public void onFail(String msg) {
}
});