0

从过去几天开始,我一直在编写一个调用本地 Web 服务的 Android 代码。我正在使用 Android 的 ksoap2 库“ksoap2-android-assembly-2.5.7-jar-with-dependencies.jar”来调用我在 .NET 中创建的 SOAP Web 服务问题是,在请求特定功能之前,我需要进行身份验证使用基本 http 请求的客户端。

这是我的代码:

public String CallSoapConnexion(String login, String mdp) {
    SoapObject request = new SoapObject(nms, mth);
    PropertyInfo pi = new PropertyInfo();
    pi.setName("login");
    pi.setValue(login);
    pi.setType(String.class);
    request.addProperty(pi);
    pi = new PropertyInfo();
    pi.setName("mdp");
    pi.setValue(mdp);
    pi.setType(String.class);
    request.addProperty(pi);

    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
            SoapEnvelope.VER11);

    envelope.dotNet = true;

    envelope.setOutputSoapObject(request);

    HttpTransportSE httpTransport = new HttpTransportSE(urlHttp);

    List<HeaderProperty> headerList = new ArrayList<HeaderProperty>();

    headerList
            .add(new HeaderProperty("Authorization", "Basic "
                    + org.kobjects.base64.Base64.encode("login:pasword"
                            .getBytes())));

    Object response = null;
    try {

        httpTransport.call(act, envelope, headerList);
        response = envelope.getResponse();

    } catch (Exception ex) {

        return ex.toString;

    }
    return ex.toString;
}

但我得到以下异常:

org.xmlpull.v1.XmlPullParserException: expected: START_TAG {http://schemas.xmlsoap.org/soap/envelope/}Envelope (position:START_TAG <html>@2:7 in java.io.InputStreamReader@44f66cb0)
4

1 回答 1

1

Ksoap2 给了我很多麻烦,我最终使用 SAXparser 制作了自己的解析器,这是解析 XML 的最快方法。我就是这样做的。

首先在一个类中,我保存了 WebServices 需要的所有常量参数。它们都是公共的和静态的,所以我可以在项目的任何地方访问它们,而无需实例化类。我们称之为 MyConstants.class

//######################## LOGIN WEB SERVICE CONSTANTS
/**
 * This string constructs the SOAP Envelope you need to use to Use the DoLogin WebService.
 * Use this string with String.format in the following way.
 * @param sUserName (String)
 * @param sPassword (String)
 * @Example String env = String.format(WebserviceConsumer.LOGIN_ENVELOPE, username, password);
 * */
public static final String LOGIN_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>" +
    "<Login xmlns=\"webServiceNamespace\">" +
      "<sUsername>%s</sUsername>" +
      "<sPassword>%s</sPassword>" +
    "</Login>" +
  "</soap:Body>" +
"</soap:Envelope>";
public static final String LOGIN_SOAP_ACTION = "webServiceNamespace/Login";
public static final String LOGIN_URL = "https://ws.yoururl.com/YourLoginPage.asmx?op=Login";
public static final int LOGIN = 100;

这是我“做”的解析器。它基于我找到的另一个解析器,所以我不知道它是否完美,但它工作得很好。

[编辑] 一段时间后我更改了解析器,因为 SAX 解析器不是一个好方法。它速度快但效率不高,因为它创建了大量对象,然后必须由垃圾收集器收集。Google 建议使用 XMLPullParser 来完成这项工作。它的使用甚至比 SAX 更容易。[/编辑]

package com.yourproject.parsers;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.os.Bundle;

/**Callback Example
 * @example
 * <?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>
 *         <LoginResponse xmlns="https://ws.yoururl.com/" >
 *             <LoginResult>
 *                 <ROOT xmlns="" >
 *                     <PassportKey>
 *                         <Key>653215989827346254362544623544652321</Key>
 *                         <otherLoginInfo>585051</otherLoginInfo>
 *                     </PassportKey>
 *                 </ROOT>
 *             </LoginResult>
 *         </LoginResponse>
 *     </soap:Body>
 * </soap:Envelope>
 */

/**
 * The loginParser saves the parsed data in a bundle. Once the parsing is done, call the 
 * getResutl() function to get a bundle that has the login authentication result.
 * */
public class LoginParser extends DefaultHandler {
    private String foundData = "";
    private String authCode = "";
    private String otherInfo = "";
    private Bundle result;

    public synchronized void parse(InputStream is) throws ParserConfigurationException, SAXException, IOException{
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser sp = spf.newSAXParser();
        XMLReader xr = sp.getXMLReader();
        xr.setContentHandler(this);

        xr.parse(new InputSource(is));
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        foundData += new String(ch, start, length);
    }

    @Override
    public void startDocument() throws SAXException{
        // Nothing to do
    }

    @Override
    public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException{
        foundData = "";
    }

    @Override
    public void endElement(String namespaceURI, String localName, String qName) throws SAXException{
        if (qName.equals("Key")) {
            authCode = foundData;
        } else if (qName.equals("otherLoginInfo")){
            otherInfo = foundData;
        }
    }

    @Override
    public void endDocument() throws SAXException{
        // Nothing to do.
    }

    public Bundle getResult(){
        result = new Bundle();
        result.putString("authCode", authCode);
        result.putString("otherInfo", otherInfo);
        return result;
    }
}

现在是使用解析器的类。一旦你有了这个,你可以在你喜欢的项目中的任何地方调用它。

package com.yourproject.web;

import java.io.IOException;
import java.io.InputStream;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;


import com.yourproject.parsers.LoginParser;

import android.content.Context;
import android.os.Bundle;
import android.util.Log;

/**
 * Public class used to send a SOAP message to our Webservices.
 * 
 * Code from
 * http://mobileorchard.com/android-app-development-calling-web-services/
 * */
public class WebserviceCall{
    LoginParser lp;
    [... other parsers ...]


    [... other parsers implementation ...]

    public Bundle CallWebServiceParseAndReturn(String url, String soapAction, String envelope, int callerRequest) throws Exception {
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httpRequest = null;
        HttpResponse httpResponse = null;
        Bundle result = null;

        httpRequest = new HttpPost(url);
        if (envelope != null) {
            httpRequest.setEntity(new StringEntity(envelope));
            httpRequest.addHeader("Content-Type", "text/xml; charset=utf-8");
        }

        httpResponse = httpclient.execute(httpRequest);
        switch (callerRequest) {
        case MyConstants.LOGIN:
            lp = new LoginParser();
            lp.parse(httpResponse.getEntity().getContent());
            result = lp.getResult();
            break;
        case MyConstants.OTHERPARSERS:
        case default:
            break;
        return result;
    }
}

最后,这是一个如何在项目中使用它的示例。

private void callWebserviceLogin(String userName, String password) {
    try{
        Bundle result = null;
        WebserviceCall wsCall = new WebserviceCall();
        String wsEnvelope = String.format(MyConstants.LOGIN_ENVELOPE, userName, password);
        result = wsCall.CallWebServiceParseAndReturn(MyConstants.LOGIN_URL, MyConstants.LOGIN_SOAP_ACTION, wsEnvelope, MyConstants.LOGIN);
        authenticationResult = result.getString("authCode");
    } catch (Exception e) {
        authenticationResult = "";
        Log.e("Login error", e.getMessage());
    }
}

如果您看到我的信封常数,则字符串中有一些 %s 标记。当我使用 String.format 时,它会按照出现的顺序将每个标记替换为您在第一个参数之后传递的参数(即保存标记的字符串)。

我知道这不是你所期望的,但我希望这会有所帮助。

于 2012-09-13T18:36:52.697 回答