加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Retrofit框架请求SOAP WebService

发布时间:2020-12-16 21:42:35 所属栏目:安全 来源:网络整理
导读:前言: ? ? ? ? 近期android使用Retrofit框架进行网络请求,已经非常流行,但是网上的例子或是现有请求后台服务器一般基于Rest方式,即发送请求时发送的参数一般直接放到header或是path路径里,稍复杂点的参数放到表单里请求。如果后台基于WebService方式,

前言:

? ? ? ? 近期android使用Retrofit框架进行网络请求,已经非常流行,但是网上的例子或是现有请求后台服务器一般基于Rest方式,即发送请求时发送的参数一般直接放到header或是path路径里,稍复杂点的参数放到表单里请求。如果后台基于WebService方式,发送的数据格式是SOAP型的XML数据,大家一般用的都是ksoap框架来请求。如果一个客户端如果有两种后台服务,在客户端代码中用两套网络框架,一般不是大家希望的。随着Retrofit框架的不断更新,此框架进行网络请求应该是大势所趋。然而用Retrofit进行Webservice请求,网上资源太少,这两天查找,也只找到两篇相关的文档和一个demo:

? ? ? ? 文章一:http://m.blog.csdn.net/article/details?id=51133893这是转载一个台湾人写的,只有片断式的零星代码,没有从头到尾讲清楚数据的组装,更没有一个可以直接运行的demo,也没有讲清楚不同的SOAP版本,请求也大不相同;

? ? ? ? 文章二:http://m.blog.csdn.net/article/details?id=51163808这篇是作者本人的实践,不得不说费了一番功夫,但是数据组装也没有讲清楚,也没有展示的demo。且作者在发送请求时,直接把请求的model直接用字符串传过去,没有发挥出retrofit的SimpleXmlConverterFactory的强大优势。

? ? ? ? 例子:demo下载地址是https://github.com/asanchezyu/RetrofitSoapSample,不得不说,这是一个能运行完整demo,但这是基于SOAP Version1.2的,对于不同的SOAP版本, 在请求上还是大不一样。而且作者的返回里没有数据,无法看到解析返回数据。


? ? ? ?看到网上这点零星的资料,好几次都想转回ksoap战营。但做为一名开发人员,不能一直copy他人代码,不动脑筋的程序员不是好程序员。下定决心一定要用Retrofit成功请求Webservice数据,终于经过两天研究,终于功夫不负有心人,成功请求出数据。


? ? ? ? SOAP Webservice的测试工具一般都是基于SoapUI工具,此工具在导入工程后可以清楚查看WebService包含的方法,SOAP版本,各方法请求参数。还可以直接模拟网络请求,查看返回结果。具体的SoapUI使用方法在这里就不多说,下面是用http://www.webservicex.net/uszip.asmx?WSDL这个工程测试的,左侧展示的是工程包含的方法,中间是请求发送的xml包,右边是服务器返回xml数据。


? ? ? ??

? ? ? ? 如果成功调用过函数,也可用charles抓包工具看看请求数据的封装。

? ? ? ? 这是成功用retrofit框架请求webservice的截图



? ? ? 通过SoapUI工具可以清楚查看到请求体,实现方面也会更容易。下面具体说说如何用Retrofit实现SOAP WebService网络请求。


实现:

1. SOAP版本

不同SOAP版本所需的命名空间有些不一样,具体查看,可以通过SoapUI工具,也可以问后台开发人员,通过查看SoapEnvelop源码可以看到。



从上图可以看出,1.0,1.1,1.2版本,命名空间都有些不一样,这会影响到后面编写Envelope包封装的请求。


2. 准备工作,因为WebService数据请求及返回都是xml形式,需要导入Retrofit xml解析的依赖包(需要把stax|stax-api|xpp3这三个类排除掉,否则编译时会报错)

compile("com.squareup.retrofit2:converter-simplexml:2.0.0-beta3")
{
    exclude module: 'stax'  exclude module: 'stax-api'  exclude module: 'xpp3' }

3. 编写Retrofit请求对象,包括请求的基址,请求头Content-Type设为text/xml;charset=UTF-8,转换器设置为
SimpleXmlConverterFactory

[java] view plain copy
  1. /**?
  2. ?*?服务器Retrofit变量初始化?
  3. ?*?Created?by?SmileXie?on?16/7/16.?
  4. ?*/??
  5. public?class?JXHDRetrofitGenerator?{??
  6. ??
  7. ????private?static?Strategy?strategy?=?new?AnnotationStrategy();??
  8. ????private?static?Serializer?serializer?=?new?Persister(strategy);??
  9. ??
  10. ????private?static?OkHttpClient.Builder?okHttpClient?=?new?OkHttpClient.Builder();??
  11. ??
  12. ???private?static?Retrofit.Builder?retrofitBuilder?=??new?Retrofit.Builder()??
  13. ????????????.addConverterFactory(SimpleXmlConverterFactory.create(serializer))??
  14. ????????????.baseUrl(Constant.BASE_URL);?//请求的webservice基址??
  15. ??
  16. ????public?static?<S>?S?createService(Class<S>?serviceClass)?{??
  17. ????????okHttpClient.interceptors().add(new?Interceptor()?{??
  18. ????????????@Override??
  19. ????????????public?okhttp3.Response?intercept(Interceptor.Chain?chain)?throws?IOException?{??
  20. ????????????????Request?original?=?chain.request();??
  21. ??
  22. ????????????????Request.Builder?requestBuilder?=?original.newBuilder()??
  23. ????????????????????????.header("Content-Type",?"text/xml;charset=UTF-8")//添加请求头??
  24. ????????????????????????.method(original.method(),?original.body());??
  25. ??
  26. ????????????????Request?request?=?requestBuilder.build();??
  27. ????????????????return?chain.proceed(request);??
  28. ????????????}??
  29. ????????});??
  30. ??
  31. ????????OkHttpClient?client?=?okHttpClient.connectTimeout(2,?TimeUnit.MINUTES)??
  32. ????????????????.writeTimeout(2,?TimeUnit.MINUTES)??
  33. ????????????????.readTimeout(2,?TimeUnit.MINUTES)??
  34. ????????????????.build();??
  35. ????????Retrofit?retrofit?=?retrofitBuilder.client(client).build();??
  36. ????????return?retrofit.create(serviceClass);??
  37. ????}??
  38. }??

4. 编写请求函数
 
 
[java] view plain copy
  1. /**?
  2. ?*?定义请求接口?
  3. ?*?Created?by?SmileXie?on?16/7/15.?
  4. ?*/??
  5. public?interface?JXHDInterfaceFun?{??
  6. ????@Headers({"SOAPAction:?getRoleinfo"})//请求的Action,类似于方法名??
  7. ????@POST("service?wsdl")//请求的地址??
  8. ????Call<RoleInfoResponseEnvelope>?getRoleInfo(@Body?RoleInfoRequestEnvelope?requestEnvelope);??
  9. }??
5. 组装请求Request Model
主要组装xml数据如下:


1)组装最外层的soapenv:Envelope,这里请求就涉及到命名空间,不同的SOAP版本是不一样的,下面是SOAP1.1版本的:
  
  
[java] view plain copy
  1. /**?
  2. ?*?Created?by?SmileXie?on?16/7/15.?
  3. ?*/??
  4. @Root(name?=?"soapenv:Envelope")??
  5. @NamespaceList({??
  6. ????????@Namespace(reference?=?"http://www.w3.org/2001/XMLSchema-instance",?prefix?=?"xsi"),??
  7. ????????@Namespace(reference?=?"http://www.w3.org/2001/XMLSchema",?prefix?=?"xsd"),??
  8. ????????@Namespace(reference?=?"http://schemas.xmlsoap.org/soap/encoding/",?prefix?=?"enc"),??
  9. ????????@Namespace(reference?=?"http://schemas.xmlsoap.org/soap/envelope/",?prefix?=?"soapenv")??
  10. })??
  11. public?class?RoleInfoRequestEnvelope?{??
  12. ????@Element(name?=?"soapenv:Body",?required?=?false)??
  13. ????public?RoleInfoRequestBody?body;??
  14. ??
  15. ????@Element(name?=?"soapenv:Header",?required?=?false)??
  16. ????public?String?aHeader;??
  17. ??
  18. }??
如果你服务器是SOAP1.2版本的,命名空间应该这样写,前缀可以自己定义,但要对应上@Element里的前缀。
  
  
[java] view plain copy
  1. @Root(name?=?"soap12:Envelope")??
  2. @NamespaceList({??
  3. ????????@Namespace(?prefix?=?"xsi",?reference?=?"http://www.w3.org/2001/XMLSchema-instance"),??
  4. ????????@Namespace(?prefix?=?"xsd",?reference?=?"http://www.w3.org/2001/XMLSchema"),??
  5. ????????@Namespace(?prefix?=?"soap12",?reference?=?"http://www.w3.org/2003/05/soap-envelope")??
  6. })??
2)组装最外层的Body部分:
  
  
[java] view plain copy
  1. /**?
  2. ?*?用户角色返回body?
  3. ?*?Created?by?SmileXie?on?16/7/15.?
  4. ?*/??
  5. @Root(name?=?"soapenv:Body",?strict?=?false)??
  6. public?class?RoleInfoRequestBody?{??
  7. ????@Element(name?=?"getroleinfo",?required?=?false)??
  8. ????public?UserInfoBaseRequest?getroleinfo;??
  9. }??

3)组装getroleinfo部分:
  
  
[java] view plain copy
  1. /**?
  2. ?*?用户信息?
  3. ?*?Created?by?SmileXie?on?16/7/15.?
  4. ?*/??
  5. ??
  6. public?class?UserInfoBaseRequest?{??
  7. ??
  8. ????@Element(name?=?"token",?required?=?false)??
  9. ????public?String?token;??
  10. ??
  11. ????@Element(name?=?"userId")??
  12. ????public?String?userid;??
  13. ??
  14. ????@Element(name?=?"userType")??
  15. ????public?String?userType;??
  16. ??
  17. ????public?String?getToken()?{??
  18. ????????return?token;??
  19. ????}??
  20. ??
  21. }??

至此,Request部分组装完成。所有请求变量都可以写成private,再用setter方法赋值。因为这里不涉及到修改数据,所以笔者全部用了public。
6. 编写请求Response Model
如果事先不知道返回的数据格式,这部分可以先不写,返回数据直接用ResponseBody来接收,通过抓包工具,查看Response部分,获取到数据的返回结果,再进行编写。
接收的数据格式跟Request Model一样,一层一层解析。Retrofit默认用的是SAX解析,所以每个标签都需要进行解析,要不会报错。
1)先解析最外层的soapevn:Envelope
  
  
[java] view plain copy
  1. /**?
  2. ?*?用户角色返回总信息?
  3. ?*?Created?by?SmileXie?on?16/7/15.?
  4. ?*/??
  5. @Root(name?=?"soapenv:Envelope")??
  6. @NamespaceList({??
  7. ????????@Namespace(reference?=?"http://www.w3.org/2001/XMLSchema-instance",??
  8. ????????@Namespace(reference?=?"http://www.w3.org/2001/XMLSchema",??
  9. ????????@Namespace(reference?=?"http://schemas.xmlsoap.org/soap/encoding/",??
  10. ????????@Namespace(reference?=?"http://schemas.xmlsoap.org/soap/envelope/",?prefix?=?"soapenv")??
  11. })??
  12. public?class?RoleInfoResponseEnvelope?{??
  13. ????@Element(name?=?"Body")??
  14. ????public?RoleInfoResponseBody?body;??
  15. ??
  16. }??

2)解析soapenv:Body部分
  
  
[java] view plain copy
  1. /**?
  2. ?*?用户角色返回body?
  3. ?*?Created?by?SmileXie?on?16/7/15.?
  4. ?*/??
  5. @Root(name?=?"Body")??
  6. public?class?RoleInfoResponseBody?{??
  7. ??
  8. ????@Element(name?=?"getroleinfoResponse",?required?=?false)??
  9. ????public?RoleInfoResponse?roleInfoResponse;??
  10. ??
  11. }??
3)解析getroleinfoResponse部分
   
   
[java] view plain copy
  1. /**?
  2. ?*?用户角色返回?
  3. ?*?Created?by?SmileXie?on?16/7/15.?
  4. ?*/??
  5. ??
  6. @Root(name?=?"getroleinfoResponse")??
  7. @NamespaceList({??
  8. ????????@Namespace(reference?=?"http://www.w3.org/2001/XMLSchema-instance",??
  9. ????????@Namespace(reference?=?"http://www.w3.org/2001/XMLSchema",??
  10. ????????@Namespace(reference?=?"http://schemas.xmlsoap.org/soap/encoding/",??
  11. ????????@Namespace(reference?=?"http://schemas.xmlsoap.org/soap/envelope",?prefix?=?"env"),?prefix?=?"encodingStyle"),??
  12. })??
  13. public?class?RoleInfoResponse?{??
  14. ????@Attribute(name?=?"encodingStyle")??
  15. ????public?String?encodingStyle;??
  16. ??
  17. ??
  18. ????@Element(name?=?"getroleinfoReturn")??
  19. ????public?RoleInfoResponseReturn?reolInfo;??
  20. ??
  21. }??
4)解析最里一层,getroleinfoReturn部分
    
    
[java] view plain copy
  1. /**?
  2. ?*?用户角色返回?
  3. ?*?Created?by?SmileXie?on?16/7/18.?
  4. ?*/??
  5. ??
  6. @Root(name?=?"getroleinfoReturn")??
  7. @Namespace(reference?=?"http://www.w3.org/2001/XMLSchema-instance",?prefix?=?"xsi")??
  8. public?class?RoleInfoResponseReturn?{??
  9. ????@Attribute(name?=?"type")??
  10. ????public?String?xsiType;??
  11. ??
  12. ????@Text()??
  13. ????public?String?message;??
  14. ??
  15. }??
最里边的数据其实是String型,直接用@Text注解获取,我们这里返回的是一个json,最后转用Gson来解析的。
7. 编写请求代码
[java] view plain copy
  1. private?void?testSOAP()?{??
  2. ????????JXHDInterfaceFun?apiService?=?JXHDRetrofitGenerator.createService(JXHDInterfaceFun.class);??
  3. ????????RoleInfoRequestEnvelope?requestEnvelope?=?new?RoleInfoRequestEnvelope();????//soapenv:Envelope??
  4. ????????RoleInfoRequestBody?requestBody?=?new?RoleInfoRequestBody();????//?body??
  5. ????????UserInfoBaseRequest?baseRequest?=?new?UserInfoBaseRequest();????//?getroleinfo??
  6. ????????baseRequest.userid?=?"liliting";??
  7. ????????baseRequest.userType?=?"2";??
  8. ????????requestBody.getroleinfo?=?baseRequest;??
  9. ????????requestEnvelope.body?=?requestBody;??
  10. ??
  11. ????????Call<RoleInfoResponseEnvelope>?call?=?apiService.getRoleInfo(requestEnvelope);??
  12. ????????call.enqueue(new?Callback<RoleInfoResponseEnvelope>()?{??
  13. ????????????@Override??
  14. ????????????public?void?onResponse(Response<RoleInfoResponseEnvelope>?response)?{??
  15. ????????????????Util.stopProgressDialog();??
  16. ????????????????RoleInfoResponseEnvelope?roleInfoResponseEnvelope?=?response.body();??
  17. ????????????????if?(roleInfoResponseEnvelope?!=?null?)?{??
  18. ????????????????????String?message?=?roleInfoResponseEnvelope.body.roleInfoResponse.reolInfo.message;??
  19. ????????????????????BaseResponse?baseResponse?=?GsonUtil.getJsonObject(message,?BaseResponse.class);??
  20. ????????????????????if(baseResponse?!=?null)?{??
  21. ????????????????????????RoleInfoResponse?roleResponse?=?GsonUtil.getJsonObject(baseResponse.getMessage(),?RoleInfoResponse.class);??
  22. ????????????????????????String?roleType?=?roleResponse.getRoles();??
  23. ????????????????????}??
  24. ??
  25. ????????????????}??
  26. ????????????}??
  27. ????????????@Override??
  28. ????????????public?void?onFailure(Throwable?t)?{??
  29. ????????????????Util.stopProgressDialog();??
  30. ????????????????Toast.makeText(SendMessageActivity.this,?getString(R.string.load_fail),?Toast.LENGTH_SHORT).show();??
  31. ????????????}??
  32. ????????});??
  33. ????}??

采用Retrofit进行WebService请求,上面代码完整显示了请求数据的封装,返回数据的解析,请求函数的编写,Retrofit对象组装,请求代码等。稍候我会把在项目实施中遇到的一些问题进行总结,并把相应代码整理成demo,供大家参考。
后记:
两种框架对比:
用Retrofit进行WebService请求,在组装请求数据时,需要进行Envelop,Body,RequestMode的组装,至少要用到3个类;
在解析返回的XML数据时,也要进行Envelop,Body,ResponseModel的解析,至少需要用3个类。
这样Retrofit框架比ksoap框架进行WebService请求,类变多了,但并没有变麻烦。这样写使整个请示都清晰了,开发者可以清楚看到数据的组装。

用ksoap请求,请求头公共的,可以写在一起,请求的对象只需要通过HashMap传值过去,ksoap会相应的组装body部分;
返回的对象解析只需要用到一个类,比WebService编写简单。
但ksoap需要单独写个AsyncTask来进行网络请求,而Retrofit包含了同步和异步请求框架,不用开发者单独写线程请求。
且Retrofit结合RxJava,现在变得越来越流行起来。
具体大家如何决择,还得具体情况具体分析。
--------------------我是华丽的分隔线-----------------------
这两天写了个demo,利用Retrofit网络框架进行WebService SOAP1.1请求,以请求天气预报为例,天气预报的请求网址为:
http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?op=getWeatherbyCityName
这里边也很详情的说明了SOAP1.1和SOAP1.2请求model和返回model的数据格式。
工程下载地址为:
https://github.com/xiewenfeng/RetorfitWebServiceSample


转自:http://blog.csdn.net/smileiam/article/details/51957232

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读