Retorfit2.0+Rxjava1+Okhttp3实现soap协议的Webservice
来源:互联网 发布:大狗狗影视下载软件 编辑:程序博客网 时间:2024/06/03 22:46
最近业余接了一个项目,服务器端使用的是SOAP协议来传输数据,虽然之前也使用过ksoap包来实现SOAP协议传输,但懂不能一直停留在之前的技术上吧… 所以,这次我想换个方法来实现SOAP协议传输。
既然要换SOAP协议的实现方法,那么就先研究一下这个SOAP协议具体是个什么东东
下面是一段SOAP请求:
POST /WebServices/WeatherWebService.asmx HTTP/1.1User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.3603)Content-Type: text/xml; charset=utf-8SOAPAction: "http://WebXml.com.cn/getSupportCity"Host: www.webxml.com.cnContent-Length: 348Expect: 100-continueConnection: Keep-Alive<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><getSupportCity xmlns="http://WebXml.com.cn/"><byProvinceName>广东</byProvinceName></getSupportCity></soap:Body></soap:Envelope>
上面的内容显示,其实SOAP协议实现的就是一个HTTP的POST请求,不过使用了SOAPAction来标识请求的内容是SOAP协议的,接收端需要根据SOAP协议来解析内容;最后的XML格式的内容就是SOAP具体的请求内容了。
明白了这层关系,那么我们就可以考虑使用retrofit和okhttp来实现SOAP协议了。
本文使用到的库:
// Rxjava compile 'io.reactivex:rxandroid:1.2.1' compile 'io.reactivex:rxjava:1.1.6' // okhttp3 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' // Retorfit2 compile 'com.squareup.retrofit2:retrofit:2.2.0' //将网络请求转化成java bean对象 也可以自定义 compile 'com.squareup.retrofit2:converter-gson:2.2.0' compile 'com.squareup.retrofit2:converter-scalars:2.2.0' //XML解析 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' } //retrofit和rxandroid连接 compile 'com.squareup.retrofit2:adapter-rxjava:2.2.0'
注:由于SOAP使用的是XML的数据格式,因此需要使用xml解析器,但需要去掉retrofit中默认的xml格式解析的模块。
首先,需要对okhttp3进行一些设置,包括缓存以及超时机制等,直接上代码:
//------------------------设置缓存策略------------------------------------ OkHttpClient.Builder okHttpClient = getdefOkhttp(); //设置Cache目录 okHttpClient.cache(defcache()); //设置缓存 okHttpClient.addInterceptor(defcacheInterceptor); okHttpClient.addNetworkInterceptor(defcacheInterceptor); //-------------------------------------------------------------- mOkHttpClient = okHttpClient.build();
/** * 缓存 * * @return */ private static Cache defcache() { int cacheSize = 10 * 1024 * 1024; return new Cache(new File(FileUtil.getRootPath() + File.separator + "cache"), cacheSize); }
/*** 缺省OKHttp配置** @return*/private static OkHttpClient.Builder getdefOkhttp() { //Log相关 HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder(); okHttpClient.connectTimeout(10, TimeUnit.SECONDS); okHttpClient.readTimeout(8, TimeUnit.SECONDS); okHttpClient.writeTimeout(8, TimeUnit.SECONDS); okHttpClient.addInterceptor(logging); //失败重连 okHttpClient.retryOnConnectionFailure(true); return okHttpClient;}
然后,配置retrofit2,注意使用的是SimpleXmlConverterFactory:
Retrofit.Builder retrofitBuilder = new Retrofit.Builder() .baseUrl(url) //设置OKHttpClient .client(mOkHttpClient) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(SimpleXmlConverterFactory.create(new Persister(new AnnotationStrategy()))) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()); return retrofitBuilder.build().create(serviceClass);
OK,以上完成了HTTP请求的通信配置,接下来就是组装SOAP请求内容以及解析SOAP返回值的部分。
首先,我们需要使用一个工具:SOAPUI,来确定服务器端的SOAP协议版本,协议的命名空间。方法名称以及参数等信息,举个栗子:
请求内容:
应答内容:(请忽略应答错误内容….)
整明白请求以及应答的头部以及具体内容之后,接下来就是哟个retrofit的simplexml解析器来组装请求和解析应答:(注解的方式)
请求内容:
// 请求头部最外层接口public abstract class ISOAPReqEnv { @Element(name = "soapenv:Body") ISOAPReqBody mBody = null;}// 请求头部body接口public abstract class ISOAPReqBody {}// 请求头部env层以及body层的实现,因为所有请求的这两层格式都一样@Root(name = "soapenv:Envelope")@NamespaceList({ @Namespace(reference = "http://tempuri.org/", prefix = "tem"), @Namespace(reference = "http://schemas.xmlsoap.org/soap/envelope/", prefix = "soapenv")})public class SOAPReqEnv extends ISOAPReqEnv { public SOAPReqEnv(ISOAPReqBody body) { this.mBody = body; }}......// 登录请求body@Root(name = "soapenv:Body", strict = false)public class SOAPLoginReqBody extends ISOAPReqBody { @Element(name = "tem:AppLogin") private SOAPLoginReqParams mLoginParams; public SOAPLoginReqBody(SOAPLoginReqParams loginParams) { this.mLoginParams = loginParams; }}// 登录请求参数@Root(name = "tem:AppLogin", strict = false)public class SOAPLoginReqParams { @Element(name = "tem:key") private String mKey; @Element(name = "tem:userid") private String mUserId; @Element(name = "tem:pwd") private String mPwd; @Element(name = "tem:hospitalName") private String hospital; public SOAPLoginReqParams(String key, String userId, String pwd) { this.mKey = key; this.mUserId = userId; this.mPwd = pwd; }}
说明一下参数,如果参数中存在数组,可使用数组注解:
@ElementArray(name = "tem:filespath", entry = "tem:string") private String[] mFilePaths;
应答内容:
// 应答头部最外层@Root(name = "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 SOAPLoginResEnv { @Element(name = "Body") SOAPLoginResBody mBody = null; public SOAPLoginResBody getBody() { return mBody; }}// 应答头部body@Root(name = "Body", strict = false)public class SOAPLoginResBody { @Element(name = "userLoginResponse") private SOAPLoginResParams mLoginParams; public SOAPLoginResParams getLoginParams() { return mLoginParams; }}// 应答内容@Root(name = "userLoginResponse", strict = false)@Namespace(reference = "http://tempuri.org/")public class SOAPLoginResParams{ @Element(name = "userLoginResult") private String mResult; public String getResult() { return mResult; } public void setResult(String result) { mResult = result; }}
由于我们这边服务端的应答内容都是自行组装的xml格式的字符串,所以我们的应答内容中就只有一个String类型的response。
如果你的应答内容也是一个类似请求参数类型的,那么可以继续使用请求参数类型的注解方式来解析。
最后,由于我们使用了rxjava1的方式来进行一步的网络请求和解析,我们需要这样发送请求和接收应答:
// 发送请求接口public interface IServiceStore { /* * 指定请求头: * "Content-Type: text/xml; charset=utf-8"指定文本格式,及编码格式 * SOAPAction的值为 * 分解为http://tempuri.org/ + userLogin,其实就是命名空间+接口名 */ @Headers({ "Content-Type: text/xml; charset=utf-8", "SOAPAction: http://tempuri.org/userLogin" }) @POST("webToPad.asmx") Observable<SOAPLoginResEnv> userLogin(@Body ISOAPReqEnv requestEnvelope);} public static void login(ISOAPReqEnv soapReqEnv, final ResultCallback callback) { createStore();......// 发送请求接收应答的实现 public static void login(ISOAPReqEnv soapReqEnv, final ResultCallback callback) { createStore(); mRxServiceStore.userLogin(soapReqEnv).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<SOAPLoginResEnv>() { @Override public void onCompleted() { } @Override public void onError(@NonNull Throwable e) { e.printStackTrace(); callback.fail((Exception) e); } @Override public void onNext(@NonNull SOAPLoginResEnv isoapResEnv) { String result = isoapResEnv.getBody().getLoginParams().getResult(); if (isSuccess(result)) { callback.success(result); } else { onError(new Exception(StringUtil.getMiddle(result, "<msg>", "</msg>"))); } } }); }...... private static IServiceStore mRxServiceStore; private static void createStore() { mRxServiceStore = createService(IServiceStore.class); }
这样就完成了SOAP协议的实现。
- Retorfit2.0+Rxjava1+Okhttp3实现soap协议的Webservice
- Retrofit2+Okhttp3+Rxjava2通过SOAP协议请求WebService
- retorfit2+okhttp3文件上传下载
- Retorfit2和OkHttp3缓存
- 一个简单的使用SOAP协议调用Webservice实现
- retorfit2.0的一些用法
- 【soap】利用php的soap实现webservice
- php soap webservice的实现
- WebService:SOAP及协议的监控
- webservice--CXF发布SOAP协议的服务
- WebService - SOAP协议
- webservice---soap协议
- RxJava1.0的创建
- WebService之Http协议和SOAP协议的不同
- 【soap】利用soap实现webservice
- android使用soap协议访问webservice实现天气预报功能
- android使用soap协议访问webservice实现天气预报功能
- SOAP方式的CXF WebService实现
- 解决jemeter做接口测试时响应数据中文显示为乱码或者Unicode码的问题
- c语言文件操作函数
- USB转串口,以及RS232串口直接相连
- *** glibc detected *** free(): invalid pointer:解决方法
- webpack
- Retorfit2.0+Rxjava1+Okhttp3实现soap协议的Webservice
- 成为Java高级架构师必看的15本书
- vs2010 快捷键大全
- 【PythonDjango后台实例 第五章】Bootstrap3 在HTML页面中显示调用本地时间并动态显示
- 剑指Offer-52
- 树状数组模板
- COleDateTime vs. CTime. Which one is better?
- HDOJ6180 贪心,set容器的使用
- javaBean与Map<String,Object>互转