Retrofit 用Soap协议访问WebService 详解

参考

1、结合Retrofit使用post请求访问WebService
2、retrofit2调用webservice-2.基本实现

前言

1、首先不要把这个想的太复杂,它就是使用【soap】协议的请求,数据格式都是【xml】,基础还是http的post请求,但是它的规范显然更多一些,总体逃不过【Request和Response】。
2、以下所有的范例都是使用 【 WeatherWebService 】 这个网站,它提供了【Soap1.1 和 Soap1.2 】的请求范例,有【Request和Response】报文可看,这样更好理解规范和格式

一、WebService 基础与注意点(第一次用的话稍微看看)

有soap1.1,soap1.2的区别,请求的header不同,xml的内容也略有不同啦~~
跳转阅读》》》【 WebService 基础知识点和用Postman调试】,复制了部分内容过来

Soap1.1:

1、xmlns后基本都是namespace,比如envelopse标签有三个namespace,getSupportCity这个方法名有一个namespace
2、区分soap1.1的是:【xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"】
3、soap1.1的请求header有:【Content-Type: text/xml; charset=utf-8 】和【SOAPAction: "http://WebXml.com.cn/getSupportCity"】

//-------------------------------------Request------------------------------------
POST /WebServices/WeatherWebService.asmx HTTP/1.1
Host: www.webxml.com.cn
Content-Type: text/xml; charset=utf-8   //header中的哦~~
Content-Length: length
SOAPAction: "http://WebXml.com.cn/getSupportCity"  //header中的哦~~

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">  //标记为soap1.1协议
  <soap:Body>
    <getSupportCity xmlns="http://WebXml.com.cn/">  //method和其namespace
      <byProvinceName>string</byProvinceName>     //param
    </getSupportCity>
  </soap:Body>
</soap:Envelope>

//-------------------------------------Response------------------------------------
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <getSupportCityResponse xmlns="http://WebXml.com.cn/">  //结果集啦~~
      <getSupportCityResult>
        <string>string</string>
        <string>string</string>
      </getSupportCityResult>
    </getSupportCityResponse>
  </soap:Body>
</soap:Envelope>
Soap1.2:

1、略,同上
2、区分soap1.2的是:【xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"】
3、soap1.2的请求header有:【application/soap+xml; charset=utf-8 】和没有【SOAPAction】

//-------------------------------------Requeset------------------------------------
POST /WebServices/WeatherWebService.asmx HTTP/1.1
Host: www.webxml.com.cn
Content-Type: application/soap+xml; charset=utf-8  //header中的,与soap1.1不同哦,而且没有soapaction了,需要注意~~~~
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"> //标记为soap1.2协议
  <soap12:Body>
    <getSupportCity xmlns="http://WebXml.com.cn/">
      <byProvinceName>string</byProvinceName>
    </getSupportCity>
  </soap12:Body>
</soap12:Envelope>

//-------------------------------------Response------------------------------------
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Body>
    <getSupportCityResponse xmlns="http://WebXml.com.cn/">  //结果集~~~
      <getSupportCityResult>
        <string>string</string>
        <string>string</string>
      </getSupportCityResult>
    </getSupportCityResponse>
  </soap12:Body>
</soap12:Envelope>

二、实例

1、公共部分

(1)app 的 builde.gradle添加依赖库

    compile 'com.squareup.okhttp3:okhttp:3.6.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.6.0'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile 'io.reactivex.rxjava2:rxjava:2.0.1'
    compile 'com.squareup.retrofit2:retrofit:2.2.0'
    //retrofit - webservice
    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-scalars:2.2.0'
    compile 'com.squareup.retrofit2:converter-gson:2.2.0'
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'

(2)Retrofit的访问工具类

/**
 *  Retrofit
 * Created by wujn on 2018/5/25.
 *
 * request : webservice soap
 * response : xml data
 */

public class RetrofitSoapClient {
    //public ZYDApiService service;
    public SoapApiService service;

    private RetrofitSoapClient(){
        //okhttp log : 包含header、body数据
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {LogUtil.i("RetrofitLog","retrofitBack = "+message);}
        });
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        //okhttp client
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .addInterceptor(loggingInterceptor)
                .build();

        //retrofit client
        Retrofit retrofit = new Retrofit.Builder()
                .client(client)
                .addConverterFactory(ScalarsConverterFactory.create())      //添加 String类型[ Scalars (primitives, boxed, and String)] 转换器
                .addConverterFactory(SimpleXmlConverterFactory.create())    //添加 xml数据类型 bean-<xml
                .addConverterFactory(GsonConverterFactory.create())         //添加 json数据类型 bean->json
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl("http://www.webxml.com.cn")        //test baseurl ;http://www.webxml.com.cn/WebServices/
                .build();
        service = retrofit.create(SoapApiService.class);
    }

    private static RetrofitSoapClient INSTANCE  = null;
    //获取单例
    public static RetrofitSoapClient getInstance() {
        if(INSTANCE == null){
            INSTANCE = new RetrofitSoapClient();
        }
        return INSTANCE;
    }

}

--------------------------------------------------------------------------------------------

2、从简单的开始,能访问上有数据返回就不错了。

2.1、简单的soap1.1和1.2的访问

2.1.1、接口类

1、RequestBody和ResponseBody的基本参数不用说
2、根据网站提供的范例,soap1.1和soap1.2的RequestHeader是不一样的,对应的@Body中的ResquetBody也是不一样的

/**
 * Created by wujn on 2018/5/25.
 * Version : v1.0
 * Function: http://www.webxml.com.cn/WebServices/WeatherWebService.asmx
 * 用来测试的
 *
 *  * 有几点需要注意:
 * 1、endpoint(baseurl-wsdl) : 不同使用中.wsdl或者?wsdl可以去掉
 * 2、namespace
 * 3、soapaction
 * 4、method
 *
 * Soap1.1
 * 格式:xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
 * 请求头:1、Content-Type:text/xm;charset=UTF-8  2、SOAPAction= Namespace + Method
 *
 * Soap1.2
 * 格式:xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"
 * 请求头:1、Content-Type:application/soap+xml;charset=UTF-8  2、无SOAPAction
 *
 */

public interface SoapApiService {
    //--------------------------原始---------------------------------
    //soap1.1
    @Headers({"Content-Type:text/xml; charset=utf-8",
            "SOAPAction:http://WebXml.com.cn/getSupportCity" })
    @POST("/WebServices/WeatherWebService.asmx")
    Observable<ResponseBody> getSupportCity_11(@Body String s);

    //soap1.2
    @Headers({"Content-Type:application/soap+xml;charset=UTF-8" })
    @POST("/WebServices/WeatherWebService.asmx")
    Observable<ResponseBody> getSupportCity_12(@Body String s);
}
2.1.2、具体请求访问

这里一定要注意,有一个坑,就是在RetrofitSoapClient中的转换中必须加上
【.addConverterFactory(ScalarsConverterFactory.create())】否则传的string会混乱,不符合soap协议格式,然后一种报错,说SoapVersion用错啥的~~((((ToT)†~~这个着实浪费了一点时间

/**
     * 原始soap1.1访问:把请求的requestbody全部用string弄出来
     * 注意全是xml形式的string,需要添加 addConverterFactory(ScalarsConverterFactory.create()) 否则有乱七八糟的符号
     * */
    public void testOrgSoap11(View v){
        String soap11 = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
                "  <soap:Body>\n" +
                "    <getSupportCity xmlns=\"http://WebXml.com.cn/\">\n" +
                "      <byProvinceName>福建</byProvinceName>\n" +
                "    </getSupportCity>\n" +
                "  </soap:Body>\n" +
                "</soap:Envelope>";

        addRxDestroy(RetrofitSoapClient.getInstance().service
                .getSupportCity_11(soap11) //its body
                .compose(RxSchedulers.<ResponseBody>io_main())
                .subscribeWith(new DisposableObserver<ResponseBody>() {

                    @Override
                    public void onNext(ResponseBody responseBody) {
                        try {
                            String result = responseBody.string();
                            LogUtil.d("testOrgSoap11 : webservice response result = \n"+result);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    @Override
                    public void onError(Throwable e) {
                        e.printStackTrace();
                        LogUtil.e("testOrgSoap11 : ex="+e.getMessage());
                    }
                    @Override
                    public void onComplete() {}
                }));
    }


    /**
     * 原始soap1.2访问:把请求的requestbody全部用string弄出来
     * 注意全是xml形式的string,需要添加 addConverterFactory(ScalarsConverterFactory.create()) 否则有乱七八糟的符号
     * */
    public void testOrgSoap12(View v){
        String soap12 = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                "<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">\n" +
                "  <soap12:Body>\n" +
                "    <getSupportCity xmlns=\"http://WebXml.com.cn/\">\n" +
                "      <byProvinceName>江苏</byProvinceName>\n" +
                "    </getSupportCity>\n" +
                "  </soap12:Body>\n" +
                "</soap12:Envelope>";

        addRxDestroy(RetrofitSoapClient.getInstance().service
                .getSupportCity_12(soap12) //its body
                .compose(RxSchedulers.<ResponseBody>io_main())
                .subscribeWith(new DisposableObserver<ResponseBody>() {
                    @Override
                    public void onNext(ResponseBody responseBody) {
                        try {
                            String result = responseBody.string();
                            LogUtil.d("testOrgSoap12 : webservice response result = \n"+result);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    @Override
                    public void onError(Throwable e) {
                        e.printStackTrace();
                        LogUtil.e("testOrgSoap12 : ex="+e.getMessage());
                    }
                    @Override
                    public void onComplete() {}
                }));
    }
2.1.3、拼接工具:针对不同公司其实不一样的
public class ApiNode {
    // 正常字符-> <xxx>
    public static String toStart(String name) {
        return "<" + name + ">";
    }
    // 正常字符-> </xxx>
    public static String toEnd(String name) {
        return "</" + name + ">";
    }

    //soap 1.1
    public static String getRequestBody11(String method, Map<String, String> map) {
        StringBuffer sbf = new StringBuffer();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            sbf.append(ApiNode.toStart(entry.getKey()));
            sbf.append(entry.getValue());
            sbf.append(ApiNode.toEnd(entry.getKey()));
        }
        String str = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
                "  <soap:Body>" +
                "    <" + method + " xmlns=\"http://WebXml.com.cn/\">" + sbf.toString() +
                "    </" + method + ">" +
                "  </soap:Body>" +
                "</soap:Envelope>";
        LogUtil.v(method+"Soap1.1 请求入参:" + str);
        return str;
    }

    //soap 1.2
    public static String getRequestBody12(String method, Map<String, String> map) {
        StringBuffer sbf = new StringBuffer();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            sbf.append(ApiNode.toStart(entry.getKey()));
            sbf.append(entry.getValue());
            sbf.append(ApiNode.toEnd(entry.getKey()));
        }
        String str = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                "<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">" +
                "  <soap12:Body>" +
                "    <" + method + " xmlns=\"http://WebXml.com.cn/\">" + sbf.toString() +
                "    </" + method + ">" +
                "  </soap12:Body>" +
                "</soap12:Envelope>";
        LogUtil.v(method+"Soap1.2 请求入参:" + str);
        return str;
    }


}

--------------------------------------------------------------------------------------------

2.2、用bean的方式会不会好一点,继续哦

就是把数据封装到bean里面,看的舒服一点,符合以前用json,resetful风格的那些请求

2.2.1、接口类:RequestEnvelope11 和ResponseEnvelope11需要看一下
public interface SoapApiService {
    //-----------------------------继续封装-------------------------------------
    //soap1.1
    @Headers({
            "Content-Type:text/xml; charset=utf-8",
            "SOAPAction:http://WebXml.com.cn/getSupportCity"
    })
    @POST("/WebServices/WeatherWebService.asmx")
    Observable<ResponseEnvelope11> getSupportCity_11_model_2(@Body RequestEnvelope11 requestEnvelope11);
}
2.2.2、所有RequestBody相关的类,这里面一层层东西请参考最上面的报文,当然代码注释里也有,所有的root,element,namespace需要对应上哦~~

(1)、最外层envelopse

/**
 * Created by wujn on 2018/5/27.
 * Version : v1.0
 * Function: whether webservice request envelope
 *
 <?xml version="1.0" encoding="utf-8"?>
 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
 <soap:Body>
 <getSupportCity xmlns="http://WebXml.com.cn/">
 <byProvinceName>string</byProvinceName>
 </getSupportCity>
 </soap:Body>
 </soap:Envelope>
 */

//Soap 1.1
//request的根目录标签
@Root(name = "soap:Envelope" , strict = false)
//Soap 1.1 根标签的namespace
@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 RequestEnvelope11 {
    //第一级子标签body
    @Element(name = "soap:Body", required = false)
    private RequestBody11 requestBody11;

    public RequestBody11 getRequestBody11() {
        return requestBody11;
    }
    public void setRequestBody11(RequestBody11 requestBody11) {
        this.requestBody11 = requestBody11;
    }
}

(2)、envelopse内的body层

/**
 * Created by wujn on 2018/5/27.
 * Version : v1.0
 * Function: whether webservice request body
 *
 <soap:Body>
 <getSupportCity xmlns="http://WebXml.com.cn/">
 <byProvinceName>string</byProvinceName>
 </getSupportCity>
 </soap:Body>
 */

@Root(name = "soap:Body", strict = false)
public class RequestBody11 {
    @Element(name = "getSupportCity", required = false)
    private RequestSupportCityBean requestSupportCityBean;

    public RequestSupportCityBean getRequestSupportCityBean() {
        return requestSupportCityBean;
    }

    public void setRequestSupportCityBean(RequestSupportCityBean requestSupportCityBean) {
        this.requestSupportCityBean = requestSupportCityBean;
    }
}

(3)、body内的请求方法getSupportCity,还有方法内的参数byProvinceName

/**
 * Created by wujn on 2018/5/27.
 * Version : v1.0
 * Function: whether webservice request method
 *
 <getSupportCity xmlns="http://WebXml.com.cn/">
 <byProvinceName>string</byProvinceName>
 </getSupportCity>
 */

@Root(name = "getSupportCity", strict = false)
@Namespace(reference = "http://WebXml.com.cn/")
public class RequestSupportCityBean {
    @Element(name = "byProvinceName" , required = false)
    private String byProvinceName;

    public String getByProvinceName() {
        return byProvinceName;
    }

    public void setByProvinceName(String byProvinceName) {
        this.byProvinceName = byProvinceName;
    }
}
2.2.3、所有ResponseBody相关的类,这里面一层层东西请参考最上面的报文,当然代码注释里也有,所有的root,element,namespace需要对应上哦~~
注意:坑,这里的Body层,用的是name="Body"不是name="soap:Body",否则结果中的body=null,不知道为什么,有大神能解释下么,为什么不按照报文来~~~

(1)、最外层envelopse :@Element(name = "Body", required = false)

/**
 * Created by wujn on 2018/5/27.
 * Version : v1.0
 * Function: whether webservice response envelope
 *
 <?xml version="1.0" encoding="utf-8"?>
 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
 <soap:Body>
 <getSupportCityResponse xmlns="http://WebXml.com.cn/">
 <getSupportCityResult>
 <string>string</string>
 <string>string</string>
 </getSupportCityResult>
 </getSupportCityResponse>
 </soap:Body>
 </soap:Envelope>
 */

//Soap 1.1
//request的根目录标签
@Root(name = "soap:Envelope" , strict = false)
//Soap 1.1 根标签的namespace
@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 ResponseEnvelope11 {
    //第一级子标签body
    //************** this is Body , not soap:Body **************
    @Element(name = "Body", required = false) 
    public ResponseBody11 responseBody11;

    public ResponseBody11 getResponseBody11() {
        return responseBody11;
    }
    public void setResponseBody11(ResponseBody11 responseBody11) {
        this.responseBody11 = responseBody11;
    }

}

(2)、envelopse内的body层:@Root(name = "Body", strict = false) //this is Body , not soap:Body

/**
 * Created by wujn on 2018/5/27.
 * Version : v1.0
 * Function: whether webservice response body
 *
 <soap:Body>
 <getSupportCityResponse xmlns="http://WebXml.com.cn/">
 <getSupportCityResult>
 <string>string</string>
 <string>string</string>
 </getSupportCityResult>
 </getSupportCityResponse>
 </soap:Body>
 */

@Root(name = "Body", strict = false) //this is Body , not soap:Body
public class ResponseBody11 {
    @Element(name = "getSupportCityResponse", required = false)
    public ResponseSupportCityBean responseSupportCityBean;

    public ResponseSupportCityBean getResponseSupportCityBean() {
        return responseSupportCityBean;
    }

    public void setResponseSupportCityBean(ResponseSupportCityBean responseSupportCityBean) {
        this.responseSupportCityBean = responseSupportCityBean;
    }
}

(3)、body下具体的response

/**
 * Created by wujn on 2018/5/27.
 * Version : v1.0
 * Function: whether webservice response result
 *
 <getSupportCityResponse xmlns="http://WebXml.com.cn/">
 <getSupportCityResult>
 <string>string</string>
 <string>string</string>
 </getSupportCityResult>
 </getSupportCityResponse>
 */

@Root(name = "getSupportCityResponse" )
@Namespace(reference = "http://WebXml.com.cn/")
public class ResponseSupportCityBean {
//    @Attribute(name = "xmlns", empty = "http://WebXml.com.cn/", required = false)
//    public String nameSpace;

    @Element(name="getSupportCityResult" )
    public ResponseCityBean cityBeen;

    public ResponseCityBean getCityBeen() {
        return cityBeen;
    }

    public void setCityBeen(ResponseCityBean cityBeen) {
        this.cityBeen = cityBeen;
    }
}

(4)、response下的结果集,还比较简单,就一个element下面多组数据

/**
 * Created by wujn on 2018/5/27.
 * Version : v1.0
 * Function: whether webservice response result detail...
 *
 <getSupportCityResult>
 <string>string</string>
 <string>string</string>
 </getSupportCityResult>
 */

@Root(name = "getSupportCityResult" )
public class ResponseCityBean {
    @ElementList(name = "string" , inline = true)
    public List<String> city;

    public List<String> getCity() {
        return city;
    }

    public void setCity(List<String> city) {
        this.city = city;
    }
}
2.2.4、具体访问
/**
     * soap1.1:封装的bean的requestbody 和 responsebody
     *
     * */
    public void testModelSoap11(View v){
        //webservice的 request 请求参数:一层层的
        RequestSupportCityBean requestSupportCityBean = new RequestSupportCityBean();
        requestSupportCityBean.setByProvinceName("浙江");
        RequestBody11 requestBody11 = new RequestBody11();
        requestBody11.setRequestSupportCityBean(requestSupportCityBean);;
        RequestEnvelope11 requestEnvelope11 = new RequestEnvelope11();
        requestEnvelope11.setRequestBody11(requestBody11);


        addRxDestroy(RetrofitSoapClient.getInstance().service
                .getSupportCity_11_model(requestEnvelope11) //its body
                .compose(RxSchedulers.<ResponseEnvelope11>io_main())
                .subscribeWith(new DisposableObserver<ResponseEnvelope11>() {

                    @Override
                    public void onNext(ResponseEnvelope11 responseEnvelope11) {
                        LogUtil.d("testModelSoap11 : response callback");

                         //封装的请求bean,返回的响应也是成功的,有数据
                         //model data : ResponseBody callback success
                        if(responseEnvelope11 == null){
                            LogUtil.e("testModelSoap11 : ResponseEnvelope11 Null");
                            return;
                        }

                        ResponseBody11 responseBody11 = responseEnvelope11.getResponseBody11();
                        if(responseBody11 == null){
                            LogUtil.e("testModelSoap11 : ResponseBody11 Null");
                            return;
                        }

                        ResponseSupportCityBean responseSupportCityBean = responseBody11.getResponseSupportCityBean();
                        if(responseSupportCityBean == null){
                            LogUtil.e("testModelSoap11 : ResponseSupportCityBean Null");
                            return;
                        }

                        ResponseCityBean citybean = responseSupportCityBean.getCityBeen();
                        if(citybean == null){
                            LogUtil.e("testModelSoap11 : citybean Null");
                            return;
                        }

                        List<String> citys = citybean.getCity();


                        StringBuilder sb = new StringBuilder();
                        for (String c : citys){
                            sb.append(c+"、 ");
                        }
                        LogUtil.d("testModelSoap11 : webservice citys = \n"+sb.toString());
                        tv_response_result.setText(mode+"\n"+sb.toString());
                    }

                    @Override
                    public void onError(Throwable e) {
                        e.printStackTrace();
                        LogUtil.e("testModelSoap11 : ex="+e.getMessage());
                    }
                    @Override
                    public void onComplete() {}
                }));
    }

以上就是对用retrofit访问webservice的一点感悟,还没有考虑继续封装。。

----------------------------更新 2018/5/31-----------------------------------------

3、对固定响应数据的格式小小优化

3.1、响应数据:

显然status,description,tableUpdateTime是固定格式,updateData里面是CDATA的数据,先不理他...

 <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <instrumentDictionaryResponse xmlns="http://www.zhiyunda.com/zydjcy" xmlns:ns2="http://www.zhiyunda.com/service/instrumentDockingService">
            <status>1</status>
            <description>成功</description>
            <tableUpdateTime>data_dictionary:2018-05-25 11:19:52;checked_unit:2016-09-18 06:32:52;standard_limit:2016-08-15 10:27:48;</tableUpdateTime>
            <updateData><![CDATA[<updatedata><table><name>data_dictionary</name><field>id, codeid, name, pid, remark, inputdate, modifydate, status, type_num</field><values><value>302|302|亚硝酸盐|1|检测项目|2016-08-24
 ..............一堆数据的省略.........
 10:58:51.0|null|C|null</value></values></table>-200<table><name>standard_limit</name><field>id, inputdate, modifydate, decision_basis, max_limit, min_limit, test_basis, unit, food_type, test_item</field><values></values></table></updatedata>]]>
            </updateData>
        </instrumentDictionaryResponse>
    </S:Body>
 </S:Envelope>
3.2、响应的bean类
3.2.1、响应的最外层bean:Envelope
//Soap 1.1
//request的根目录标签
@Root(name = "S:Envelope" , strict = false)
//Soap 1.1 根标签的namespace
@NamespaceList({
        @Namespace(reference = "http://schemas.xmlsoap.org/soap/envelope/", prefix = "S")
})
public class ZydResponseDictionaryEnvelope {

    @Path("S:Body") //跳过body
    @Element(name = "instrumentDictionaryResponse", required = false)
    private ZydResponseDictionary zydResponseDictionary;

    public ZydResponseDictionary getZydResponseDictionary() {
        return zydResponseDictionary;
    }

    public void setZydResponseDictionary(ZydResponseDictionary zydResponseDictionary) {
        this.zydResponseDictionary = zydResponseDictionary;
    }
}
3.2.2、body下的具体返回数据的bean,此处还可以继续优化:@Element(name = "updateData", required = false) private String updateData; 这个可以用泛型T,暂时不用了就算是获取CDATA的string值好了,因为转换xml的string也可以之后用泛型T来做
@Root(name = "instrumentDictionaryResponse", strict = false)
@NamespaceList({
        @Namespace(reference = "http://www.zhiyunda.com/zydjcy"),
        @Namespace(reference = "http://www.zhiyunda.com/service/instrumentDockingService", prefix = "ns2")
})
public class ZydResponseDictionary {
    //状态
    @Element(name = "status", required = false)
    private String status;

    //描述
    @Element(name = "description", required = false)
    private String description;

    //更新时间
    @Element(name = "tableUpdateTime", required = false)
    private String tableUpdateTime;

    //更新数据  -->  这个可以用泛型T,暂时不用了就算是获取CDATA的string值好了
    @Element(name = "updateData", required = false)
    private String updateData;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getTableUpdateTime() {
        return tableUpdateTime;
    }

    public void setTableUpdateTime(String tableUpdateTime) {
        this.tableUpdateTime = tableUpdateTime;
    }

    public String getUpdateData() {
        return updateData;
    }

    public void setUpdateData(String updateData) {
        this.updateData = updateData;
    }

   
}
3.3、API接口
        @Headers({
            "Content-Type:text/xml; charset=utf-8",
            "SOAPAction:\"\""
    })
    @POST(ZYDApiConfig.POST_WSDL)
    Observable<ZydResponseDictionaryEnvelope> instrumentDictionaryHandle(@Body String s);
3.4、CallBack:请求的返回值略优化下,不管是访问失败,或者访问成功,数据获取失败都并到一起处理了,返回就是--》成功+有效数据,失败+提示语句
public abstract class ZydResponseDictionaryCallback extends DisposableObserver<ZydResponseDictionaryEnvelope> {

    @Override
    public void onNext(ZydResponseDictionaryEnvelope zydResponseDictionaryEnvelope) {
        if(zydResponseDictionaryEnvelope == null){
            onFailed("接口数据为空");
            return;
        }
        ZydResponseDictionary dictionary = zydResponseDictionaryEnvelope.getZydResponseDictionary();
        if (dictionary == null){
            onFailed("接口数据为空");
            return;
        }

        if(dictionary.getStatus().equals("1")){
            onSuccess(dictionary.getTableUpdateTime() , dictionary.getUpdateData());
        }else{
            onFailed(dictionary.getDescription());
        }

    }

    @Override
    public void onError(Throwable e) {
        onFailed(ApiException.handleApiExMsg(e)); //就是http code处理
    }
    @Override
    public void onComplete() { }

    public abstract void onSuccess(String tableDate,String updateData);
    public void onFailed(String msg) {

    }
}
3.5、具体请求
String requestBodyStr = ZYDApiNode.getRequestString2InstrumentDictionaryHandle(instance ,
                                                                ZYDSpOper.getTableDate(instance));

        addRxDestroy(RetrofitSoapClient.getInstance().service
                .instrumentDictionaryHandle(requestBodyStr) //its body
                .compose(RxSchedulers.<ZydResponseDictionaryEnvelope>io_main())
                .subscribeWith(new ZydResponseDictionaryCallback() {
                    @Override
                    public void onSuccess(String tableDate, String updateData) {
                      //对CDATA数据做处理,这个单独拉开来讲
                      //后续的业务需求
                    }

                    @Override
                    public void onFailed(String msg) {
                        DialogUtil.errorDialog(instance,msg);
                    }
                }));
3.6、CDATA的xml数据处理,请看下一篇文章:Android XStream 解析xml数据变成bean,支持CDATA

留下疑问,啥年代了为啥还有webservice,他有啥好的??

上一篇:win7技巧


下一篇:重写DataGridViewColumn