SOAP协议之Retrofit解析

一、前言

最近公司需要对接webservice的服务器接口,从而给了时间研究webservice的内部协议。webservice中用到的是soap协议,简单来说,soap协议就是http协议+XML格式,它是RPC调用的一种。Android中的主流http请求框架用的是OKhttp,请求解耦框架是Retrofit。既然soap是基于http协议的,那么通过Retrofit框架处理是没有问题的。

soap即简单的面向对象协议,类比onc rpc是一个基于二进制的调用,这并不利于扩展,所以之后才有了面向对象的soap协议,在XML中参数的顺序和增加并不会对之前的代码有所影响。

在网上找了些Retrofit封装代码,比较好比较入门的https://github.com/xiewenfeng/RetorfitWebServiceSample,本文也是在此基础上分析完善。

二、SOAP协议

1)、WebService请求协议

POST http://www.webxml.com.cn/WebServices/WeatherWebService.asmx HTTP/1.1
Content-Type: text/xml;charset=UTF-8
Content-Length: 347
SOAPAction: http://WebXml.com.cn/getWeatherbyCityName

 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
   <soap:Body xmlns="http://WebXml.com.cn/">
      <getWeatherbyCityName>
          <theCityName>合肥</theCityName>
       </getWeatherbyCityName>
    </soap:Body>
 </soap:Envelope>

从webservice发送的协议来看,很容易看出,它是基于Http协议的,增加了header字段SOAPAction,以及将文本类型改成Content-Type: text/xml;charset=UTF-8。这样就能告诉服务器,参数类型是XML,以及调用哪个方法解析。

下面再来看看SOAP的语法结构:

<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">

<soap:Header>
  ...
  ...
</soap:Header>

<soap:Body>
  ...
  ...
  <soap:Fault>
    ...
    ...
  </soap:Fault>
</soap:Body>

</soap:Envelope>

从SOAP结构中可以看到有四大块:

  • Envelope必选,可把此 XML 文档标识为一条 SOAP 消息
  • Header可选,头部信息附属功能
  • Body必选,调用信息(传递的参数)或者响应信息(返回的结果)
  • Fault可选,提供有关在处理此消息所发生错误的信息

Envelope

Envelope为根元素,没有该元素的一律不会是SOAP消息。

其中soap:Envelope中的soap是根据xmlns:soap="http://www.w3.org/2003/05/soap-envelope"而来的,它们必须一一匹配。

Body

Body元素在请求时放入传递给服务器的参数,返回时是服务器返回的数据。

2)、WebService返回协议

先看下上面的请求的返回例子:

        200 OK http://www.webxml.com.cn/WebServices/WeatherWebService.asmx
        Content-Length: 3229
        Content-Type: application/soap+xml; charset=utf-8
        Server: Microsoft-IIS/7.5
        X-AspNet-Version: 2.0.50727
        X-Powered-By: ASP.NET
        Date: Sun, 05 May 2019 07:11:36 GMT
        OkHttp-Sent-Millis: 1557040300871
        OkHttp-Received-Millis: 1557040300923
        <?xml version="1.0" encoding="utf-8"?>
        <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <soap:Body>
                <getWeatherbyCityNameResponse xmlns="http://WebXml.com.cn/">
                    <getWeatherbyCityNameResult>
                        <string>安徽</string>
                        <string>合肥</string>
                        <string>58321</string>
                        <string>58321.jpg</string>
                        <string>2019/5/5 14:51:16</string>
                        <string>15℃/28℃</string>
                        <string>5月5日 多云</string>
                        <string>东风3-4级转东北风小于3级</string>
                        <string>1.gif</string>
                        <string>1.gif</string>
                        <string>今日天气实况:气温:27℃;风向/风力:东北风 3级;湿度:46%;紫外线强度:弱。空气质量:良。</string>
                        <string>紫外线指数:弱,辐射较弱,涂擦SPF12-15、PA+护肤品。
                                健臻·血糖指数:易波动,血糖易波动,注意监测。
                                穿衣指数:舒适,建议穿长袖衬衫单裤等服装。
                                洗车指数:较适宜,无雨且风力较小,易保持清洁度。
                                空气污染指数:良,气象条件有利于空气污染物扩散。</string>
                        <string>12℃/23℃</string>
                        <string>5月6日 多云</string>
                        <string>东风3-4级转小于3级</string>
                        <string>1.gif</string>
                        <string>1.gif</string>
                        <string>13℃/20℃</string>
                        <string>5月7日 多云转小雨</string>
                        <string>东风小于3级</string>
                        <string>1.gif</string>
                        <string>7.gif</string>
                        <string>合肥市,古称庐州,又名庐阳,位于安徽省中部,地处江淮之间、巢湖北岸,辖东市、西市、中市、郊区4区和长丰、肥东、肥西3县。总面积7266平方公里,人口425.9万。市内道路宽阔,绿树成荫,景色优美,既多现代建筑,又有名胜古迹,是一座古老而又年青的城市。合肥市位于江淮之间,处于中纬度地带,为亚热带湿润季风气候。年平均气温在15℃-16℃之间,极端最低气温-20.6℃,极端最高气温38℃以上。年平均降水量在900-1000毫米之间。全年气温变化的特点是季风明显、四季分明、气候温和、雨量适中、春温多变、秋高气爽、梅雨显著、夏雨集中,总之气候条件优越,气候资源丰富。合肥市素以“三国旧地、包拯故里”闻名于世,具有“淮右襟喉、江南唇齿”的战略地位,常为兵家必争之地。三国时魏将张辽大败孙权十万大军的逍遥津战役,即发生在这里。两千多年前,这里就已开始形成商业都会。秦、汉在此设郡县,明、清为庐州府治,民国时为安徽省省会,如今已是千樯鳞次、商贾辐凑的商业都会。合肥素有“绿色城市”、“花园城市”的美名,其环城公园便修建在合肥古城墙的基础之上,沿着起伏的岗丘地形,加之原有的绿林带及护城河,精筑而成。环城公园总长约达9公里,分为六个景区,其中较为著名的有茂林修竹,夏河朝露的银河景区;湖峦相映、水碧枫赤的西山景区;林木葱茏、芳草常青的环北景区。这样的环城公园无城墙之隔阂,面水而立,一派迷人旖旎的江南风光。</string>
                    </getWeatherbyCityNameResult>
                </getWeatherbyCityNameResponse>
            </soap:Body>
        </soap:Envelope>

从返回的可以看出来它是包含了以上的Envelope和Body,解析只需要将XML格式化成对象格式即可。

小结

从以上的协议分析,使用Retrofit请求和解析没有任何问题。请求的是Post请求,现在将请求的消息按照SOAP协议封装成符合服务器要求的格式,再将其字符串注入到post请求的Body中即可。返回的消息是个XML格式的字符串,现在只需要按照后台给定的消息去解析即可,也可以通过XML解析框架处理,这会更加简单。

三、实践Retrofit解析

引用的第三方库:

  • retrofit :网络请求框架
  • logging-interceptor : OKhttp日志打印
  • converter-simplexml : 生成及解析XML框架

1)、请求参数编写

 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
   <soap:Body xmlns="http://WebXml.com.cn/">
      <getWeatherbyCityName>
          <theCityName>合肥</theCityName>
       </getWeatherbyCityName>
    </soap:Body>
 </soap:Envelope>

需要我们将代码拼接成如上的格式,其中theCityName里面的内容是传入的。

为此使用了converter-simplexml框架将对象封装成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://www.w3.org/2003/05/soap-envelope", prefix = "soap")
})
public class RequestEnvelope {
    @Element(name = "soap:Body")
    private RequestBody requestBody;

    public void setRequestBody(RequestBody requestBody) {
        this.requestBody = requestBody;
    }
}
@NamespaceList({
        @Namespace(reference = "http://WebXml.com.cn/")
})
public class RequestBody {

    @Element(name = "getWeatherbyCityName")
    private RequestModel getWeatherbyCityName;

    public void setGetWeatherbyCityName(RequestModel getWeatherbyCityName) {
        this.getWeatherbyCityName = getWeatherbyCityName;
    }
}
/**
 * 描述:参数
 * Created by PHJ on 2019/5/5.
 */
public class RequestModel {

    @Element(name = "theCityName")
    public String cityName;     //城市名字


    public void setCityName(String cityName) {
        this.cityName = cityName;
    }
}

以此转化,就是所需要的XML。并将XML放入到请求体即可。

2)、解析响应信息

        200 OK http://www.webxml.com.cn/WebServices/WeatherWebService.asmx
        Content-Length: 3229
        Content-Type: application/soap+xml; charset=utf-8
        Server: Microsoft-IIS/7.5
        X-AspNet-Version: 2.0.50727
        X-Powered-By: ASP.NET
        Date: Sun, 05 May 2019 07:11:36 GMT
        OkHttp-Sent-Millis: 1557040300871
        OkHttp-Received-Millis: 1557040300923
        <?xml version="1.0" encoding="utf-8"?>
        <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <soap:Body>
                <getWeatherbyCityNameResponse xmlns="http://WebXml.com.cn/">
                    <getWeatherbyCityNameResult>
                        <string>安徽</string>
                        <string>合肥</string>
                        <string>58321</string>
                        <string>58321.jpg</string>
                        <string>2019/5/5 14:51:16</string>
                        <string>15℃/28℃</string>
                        <string>5月5日 多云</string>
                        <string>东风3-4级转东北风小于3级</string>
                        <string>1.gif</string>
                        <string>1.gif</string>
                        <string>今日天气实况:气温:27℃;风向/风力:东北风 3级;湿度:46%;紫外线强度:弱。空气质量:良。</string>
                        <string>紫外线指数:弱,辐射较弱,涂擦SPF12-15、PA+护肤品。
                                健臻·血糖指数:易波动,血糖易波动,注意监测。
                                穿衣指数:舒适,建议穿长袖衬衫单裤等服装。
                                洗车指数:较适宜,无雨且风力较小,易保持清洁度。
                                空气污染指数:良,气象条件有利于空气污染物扩散。</string>
                        <string>12℃/23℃</string>
                        <string>5月6日 多云</string>
                        <string>东风3-4级转小于3级</string>
                        <string>1.gif</string>
                        <string>1.gif</string>
                        <string>13℃/20℃</string>
                        <string>5月7日 多云转小雨</string>
                        <string>东风小于3级</string>
                        <string>1.gif</string>
                        <string>7.gif</string>
                        <string>合肥市,古称庐州,又名庐阳,位于安徽省中部,地处江淮之间、巢湖北岸,辖东市、西市、中市、郊区4区和长丰、肥东、肥西3县。总面积7266平方公里,人口425.9万。市内道路宽阔,绿树成荫,景色优美,既多现代建筑,又有名胜古迹,是一座古老而又年青的城市。合肥市位于江淮之间,处于中纬度地带,为亚热带湿润季风气候。年平均气温在15℃-16℃之间,极端最低气温-20.6℃,极端最高气温38℃以上。年平均降水量在900-1000毫米之间。全年气温变化的特点是季风明显、四季分明、气候温和、雨量适中、春温多变、秋高气爽、梅雨显著、夏雨集中,总之气候条件优越,气候资源丰富。合肥市素以“三国旧地、包拯故里”闻名于世,具有“淮右襟喉、江南唇齿”的战略地位,常为兵家必争之地。三国时魏将张辽大败孙权十万大军的逍遥津战役,即发生在这里。两千多年前,这里就已开始形成商业都会。秦、汉在此设郡县,明、清为庐州府治,民国时为安徽省省会,如今已是千樯鳞次、商贾辐凑的商业都会。合肥素有“绿色城市”、“花园城市”的美名,其环城公园便修建在合肥古城墙的基础之上,沿着起伏的岗丘地形,加之原有的绿林带及护城河,精筑而成。环城公园总长约达9公里,分为六个景区,其中较为著名的有茂林修竹,夏河朝露的银河景区;湖峦相映、水碧枫赤的西山景区;林木葱茏、芳草常青的环北景区。这样的环城公园无城墙之隔阂,面水而立,一派迷人旖旎的江南风光。</string>
                    </getWeatherbyCityNameResult>
                </getWeatherbyCityNameResponse>
            </soap:Body>
        </soap:Envelope>

解析XML就是去除外层的包装,转化成对象,并且保存。

在此之前需要配置转化格式:

    private static Strategy strategy = new AnnotationStrategy();
    private static Serializer serializer = new Persister(strategy);

        // 设置电脑链接
        instance.retrofit = builder.baseUrl(BASE_URL)
                // 设置client
                .client(client)
                // 设置Json解析器
                .addConverterFactory(SimpleXmlConverterFactory.create(serializer))
                .build();

采用了SimpleXmlConverterFactory解析对应的XML,当然这部分也可以自己获取字符串后自己解析。

详细代码可以参考GitHub代码

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容