Перенос байтового массива из мыльного сервиса на андроид - PullRequest
4 голосов
/ 24 июля 2011

У меня есть Android-клиент, который отправляет запрос на мыльный сервис. Сервис мыла считывает изображение в серию байтов и возвращает массив байтов (довольно большой). Будет ли это рассматриваться как примитивный тип передачи? Я спрашиваю, потому что у меня есть служебный код, который читает изображение и печатает первые 5 байтов. Затем он возвращает байтовый массив.

@Override
public byte[] getImage() {
    byte[] imageBytes = null;
    try {
        File imageFile = new File("C:\\images\\car.jpg");
        BufferedImage img = ImageIO.read(imageFile);
        ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
        ImageIO.write(img, "jpg", baos);
        baos.flush();
        imageBytes = baos.toByteArray();
        baos.close();
    } catch (IOException ioe) {
        ioe.printStackTrace();
    }
    System.out.println("Got request");
    System.out.println("****** FIRST 5 BYTES: ");
    for(int i=0; i<5; i++) {
        System.out.println("****** " + imageBytes[i]);
    }
    return imageBytes;
}

Выходные данные службы на сервере:

****** FIRST 5 BYTES: 
****** -119
****** 80
****** 78
****** 71
****** 13

Когда я получаю это на моем эмуляторе Android, я печатаю первые 5 байтов, и они полностью отличаются от тех, которые напечатаны на сервере. Вот мой код Android:

        androidHttpTransport.call(SOAP_ACTION, envelope);
        SoapPrimitive  resultsRequestSOAP = (SoapPrimitive) envelope.getResponse();
        String result = resultsRequestSOAP.toString();
        System.out.println("****** RESULT: " + result);
        byte[] b = result.getBytes();
        System.out.println("****** FIRST 5 BYTES: ");
        for(int i=0; i<5; i++) {
            System.out.println("****** " + b[i]);
        }

И вывод

****** FIRST 5 BYTES: 
****** 105
****** 86
****** 66
****** 79
****** 82

Работает нормально, если я тестирую его на простом сервисном клиенте, написанном на Java. Есть идеи, почему это может происходить?

Ответы [ 3 ]

11 голосов
/ 25 июля 2011

@ Майкл, это сработало. Вот мой последний рабочий код, который отправит jpeg из мыльного сервиса в эмулятор Android и отобразит его. Я использую jax-ws. Вот компонент реализации службы для операции getImage (), которая возвращает закодированную в base64 строку байтов изображения.

@Override
public String getImage() {
    byte[] imageBytes = null;
    try {
        File imageFile = new File("C:\\images\\fiesta.jpg");
        BufferedImage img = ImageIO.read(imageFile);
        ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
        ImageIO.write(img, "jpg", baos);
        baos.flush();
        imageBytes = baos.toByteArray();
        baos.close();
    } catch (IOException ioe) {
        ioe.printStackTrace();
    }
    return (imageBytes != null) ? Base64.encodeBase64String(imageBytes) : "";
}

Теперь вот код Android, который будет вызывать службу и получать содержимое закодированного изображения, декодировать его в байтовый массив, создавать растровое изображение и отображать его в эмуляторе:

public class ImageSoapActivity extends Activity {

private static final String NAMESPACE = "http://image.webservice";
private static final String URL = "http://10.0.2.2:8080/images?wsdl";
private static final String METHOD_NAME = "getImage";
private static final String SOAP_ACTION = "http://image.webservice/getImage";   

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); 
    envelope.setOutputSoapObject(request);
    HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
    try {
        androidHttpTransport.call(SOAP_ACTION, envelope);
        SoapPrimitive  resultsRequestSOAP = (SoapPrimitive) envelope.getResponse();
        String result = resultsRequestSOAP.toString();
        if (result != "") {
            byte[] bloc = Base64.decode(result, Base64.DEFAULT);         
            Bitmap bmp = BitmapFactory.decodeByteArray(bloc,0,bloc.length);
            ImageView image = new ImageView(this);
            image.setImageBitmap(bmp);
            setContentView(image);
        }
    } catch (Exception e) {
        System.out.println("******* THERE WAS AN ERROR ACCESSING THE WEB SERVICE");
        e.printStackTrace();
    }        
    }
}

enter image description here

Надеюсь, это будет полезно для кого-то, кому это может понадобиться. Вы также должны установить разрешение: <uses-permission android:name="android.permission.INTERNET"></uses-permission>. Также обратите внимание, что эмулятор подключается к локальному хосту машины на 10.0.2.2, а не на 127.0.0.1

5 голосов
/ 24 июля 2011

Похоже, вы пропустили важный шаг декодирования.Код, генерирующий ответ SOAP, должен кодировать байтовый массив, чтобы его можно было представить в виде строки в XML.Трудно сказать, как вы должны декодировать его, не зная механизма кодирования, используемого на стороне сервера ( base64 и т. Д. ).

В приведенном выше коде вы вызываете String#getBytes () , которая кодирует данную строку в виде двоичных данных, используя набор символов по умолчанию (который является UTF-8 в Android).Это не то же самое, что декодирование исходных данных изображения.UTF-8 не может использоваться в качестве механизма кодирования общего назначения, поскольку он не может представлять какую-либо произвольную последовательность байтов (не все последовательности байтов являются действительными UTF-8).

Проверьте код службы, чтобы увидеть, как он кодируетдвоичные данные и использовать соответствующий механизм декодирования на стороне клиента, и это должно решить вашу проблему.

HTH.

РЕДАКТИРОВАТЬ : Этот faq (для более старой версии, но, вероятно, все еще применяется) рекомендует кодировать массив байтов как base64 и помещать его в SoapPrimitive.Лично я бы использовал Commons Codec и его класс Base64 для кодирования байтового массива в виде строки на стороне сервера и использовал его на стороне клиента для декодирования этой строки обратно в исходный байтовый массив.

Одна вещь, на которую следует обратить внимание ... Android фактически включает в себя более старую версию кодека Commons, так что это может вас запутать.В частности, он не включает удобный метод encodeBase64String, поэтому вам нужно будет поэкспериментировать или провести некоторое исследование, чтобы выяснить, какие методы декодирования существуют на платформе Android.Вы можете использовать android.util.Base64 на стороне клиента, но убедитесь, что используете правильные флаги, соответствующие стилю кодировки, который вы использовали на стороне сервера.Удачи.

0 голосов
/ 24 июля 2011

нам нужно реализовать сериализацию перед отправкой байтового массива, в противном случае мы получаем ошибку, не можем сериализовать байтовый массив. см. Пример ниже

     private static final String NAMESPACE = ".xsd url taken from  the web service URL";
    private static final String URL = "web service URL";
    private static final String SOAP_ACTION = "Action port typr";
    private static final String METHOD_NAME = "Method name";
the above parameter can be taken from the users web service (?WSDL) url

SoapObject request = new SoapObject(NAMESPACE, AUTH_METHOD);
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
                SoapEnvelope.VER11);


new MarshalBase64().register(envelope);   //serialization
envelope.encodingStyle = SoapEnvelope.ENC;


        request.addProperty("body", str);
        request.addProperty("image", imagebyte);
        envelope.setOutputSoapObject(request);
        HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
try{
        androidHttpTransport.call(SOAP_ACTION, envelope);

            SoapObject resultsRequestSOAP = (SoapObject) envelope.bodyIn;

            String str=resultsRequestSOAP.toString();

   }catch(Exception e)
{
}
see
...