2014-02-05 3 views
6

У меня есть 4 дня, пытаясь сделать многопользовательский запрос с использованием Retrofit 1.8.0 в android с успехом. Мой интерфейс выглядит что-то вроде этогоМногопользовательский запрос с использованием Retrofit 1.8.0 не работает

@Multipart 
@POST("/posts/add.json") 
void addComment(
    @Part("id") String id, 
    @Part("post[body]") String body, 
    @Part("post[attachment]") TypedFile attachment, 
    Callback<Map<String, String>> callback); 

Но, на стороне сервера, я получаю следующее

Parameters: {"id"=># <File:/var/folders/z0/0ggjvvfj4t1fdsvbxf3lc9pw0000gn/T/RackMultipart9853-0>, "post"=>{"body"=>#<File:/var/folders/z0/0ggjvvfj4t1fdsvbxf3lc9pw0000gn/T/RackMultipart9853-1>, "attachment"=>#<File:/var/folders/z0/0ggjvvfj4t1fdsvbxf3lc9pw0000gn/T/RackMultipart9853-2>}, "controller"=>"posts", "action"=>"add", "format"=>"json"} 

Как вы можете видеть, файл часть посылает его в каждой части, но и я отсутствует значение по параметрам с идентификатором и пост [тела]

Вот это то, что дооснащения пытается отправить

02-06 15:01:16.213 32545-822/com.myapp D/Retrofit﹕ --fe41634b-6826-4ee4-95cb-65efb0ca66c2 
Content-Disposition: form-data; name="id" 
Content-Type: text/plain; charset=UTF-8 
Content-Length: 3 
Content-Transfer-Encoding: binary 
189 
--fe41634b-6826-4ee4-95cb-65efb0ca66c2 
Content-Disposition: form-data; name="post[body]" 
Content-Type: text/plain; charset=UTF-8 
Content-Length: 4 
Content-Transfer-Encoding: binary 
test 
--fe41634b-6826-4ee4-95cb-65efb0ca66c2 
Content-Disposition: form-data; name="post[attachment]"; filename="IMG_20140203_144358.jpg" 
Content-Type: image/jpg 
Content-Length: 1615460 
Content-Transfer-Encoding: binary 
����/�Exif����MM��*��������� 

Вот это то, что библиотека HttpMime посылает в многотомных, разница является «Content-Transfer-Encoding» заголовок против Модернизированный

Content-Disposition: form-data; name="id" 
Content-Type: text/plain; charset=US-ASCII 
Content-Transfer-Encoding: 8bit 

Content-Disposition: form-data; name=“post[body]" 
Content-Type: text/plain; charset=US-ASCII 
Content-Transfer-Encoding: 8bit 

Content-Disposition: form-data; name=“post[attachment]"; filename="images.jpg" 
Content-Type: image/jpg 
Content-Transfer-Encoding: binary 

Любой ключ? Заранее заблаговременно

------------------------------- РЕШЕНИЕ ---------- ------------------------

В конце концов, я решил этот путь, на самом деле мой ответ довольно близок к @lazypig, это было хороший ориентир

Единственное, что я изменил был своим классом «ByteArrayTypedOutput»

Я создал класс под названием «MultipartTypedOutputCustom» http://pastie.org/10549360

И это, как он выглядит мой интерфейс Теперь

класс "PostsRetrofitAPI.java"

@POST("/posts/add.json") 
    void addComment(@Body MultipartTypedOutputCustom parts, 
        Callback<Map<String, String>> callback); 

класс "PostsService.java"

//Properties 
private PostsRetrofitAPI mApi; 
... 

    @Override 
     public void addComment(ServiceResponseHandler<Map<String, String>> handler, String id, String body, TypedFile attachment) { 
      MultipartTypedOutputCustom parts = new MultipartTypedOutputCustom(); 
      parts.addPart("id", new TypedString(id)); 
      parts.addPart("post[body]", new TypedString(body)); 
      parts.addPart("post[attachment]", attachment); 
    objectRetrofitCallback= new ObjectRetrofitCallback(handler, ServerError.class, ClientError.class); 
      mApi.addComment(parts, objectRetrofitCallback); 
     } 
+0

Вы можете разместить свой HTTP-конверт? Включить журналы в RestAdapter.Builder(). setLogLevel (LogLevel.FULL) –

+0

Привет, я уже редактировал свой пост с вашим предложением – arh

+1

Вы поняли это в конце? – Lion789

ответ

1

Я сделал это вместо того, чтобы для интерфейса

interface MultipartFormDataService { 
    @POST("/{uploadPath}") 
    void multipartFormDataSend(
      @EncodedPath("uploadPath") String uploadPath, 
      @Body MultipartTypedOutput multipartTypedOutput, 
      Callback<String> cb); 
} 

Тогда позже, когда я звоню, он выглядит следующим образом

// creating the Multipart body using retrofit 
MultipartTypedOutput multipartTypedOutput = new MultipartTypedOutput(); 
TypedString idParam = new TypedString("[ID Value]") 
TypedString bodyParam = new TypedString("[Body text]") 
ByteArrayTypedOutput byteMultipartTypedOut = new ByteArrayTypedOutput(bytes) 

// add parts 
multipartTypedOutput.addPart("id", idParam); 
multipartTypedOutput.addPart("body", bodyParam); 
multipartTypedOutput.addPart("attachment", extraParamTypedString); 

// send 
multipartService.multipartFormDataSend(
       "[TARGET URL]", 
       multipartTypedOutput, 
      aCallback); 

My ByteArrayTypedOutput был прост

public class ByteArrayTypedOutput implements TypedOutput { 

    private MultipartFormMetadata metadata; 
    private byte[] imageData; 

    public ByteArrayTypedOutput(MultipartFormMetadata metadata, byte[] imageData) 
     this.metadata = metadata; 
     this.imageData = imageData; 
    } 

    @Override 
    public String fileName() { 
     return metadata.fileName; 
    } 

    @Override 
    public String mimeType() { 
     return metadata.fileMimeType; 
    } 

    @Override 
    public long length() { 
     return imageData.length; 
    } 

    @Override 
    public void writeTo(OutputStream outputStream) throws IOException { 
     outputStream.write(imageData); 
    } 
} 
+0

Спасибо @lazypig, это было довольно неплохое руководство. – arh

3

Если вы видите примеры на http://square.github.io/retrofit/ объекта типы для ваших параметров «id» и «part [body]» должны быть TypedString, а не String.TypedString устанавливает соответствующий тип MIME и выполняет преобразование в байтах:

https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit/mime/TypedString.java

0

У меня была аналогичная проблема сегодня для отправки файла и некоторые поля, вот мое решение

Мой интерфейс, TypedFile представляет собой класс ДООСНАСТКЕ

@Multipart 
    @POST("/api/Media/add") 
    void addMedia(@Part("file") TypedFile photo, 
        @Part("type") String type, 
        @Part("name") String name, 
        @Part("description") String description, 
        Callback<com.yourcompany.pojo.Media> callback); 

в деятельности

profileImage.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      Intent galleryIntent = new Intent(
        Intent.ACTION_PICK, 
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI); 
      startActivityForResult(galleryIntent , RESULT_GALLERY); 
     } 
    }); 

, а затем

@Override 
public void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 

    switch (requestCode) { 
     case RESULT_GALLERY : 
      if (null != data) { 
       imageUri = data.getData(); 
       String selectedImagePath = null; 
       Uri selectedImageUri = data.getData(); 
       Cursor cursor = activity.getContentResolver().query(selectedImageUri, null, null, 
       null, null); 
       if (cursor == null) { 
        selectedImagePath = imageUri.getPath(); 
       } else { 
        cursor.moveToFirst(); 
        int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); 
        selectedImagePath = cursor.getString(idx); 
       } 
       File file = new File(selectedImagePath); 
       waiter.setVisibility(View.VISIBLE); 
       _YOUR_APP_._YOUR_INTERFACE_.addMedia(new TypedFile("image/*", file), "avatar", "avatar", "avatar", new Callback<Media>() { 

        @Override 
        public void success(Media media, Response response) { 

        } 

        @Override 
        public void failure(RetrofitError error) { 

        } 
       }); 
      } 
      break; 
     default: 
      break; 
    } 
} 

Медиа-класс является простым pojo, чтобы держать ответ

public class Media { 

@Expose 
private int[] data; 

/** 
* 
* @return 
* The data 
*/ 
public int getData() { 
    return data[0]; 
} 

/** 
* 
* @param data 
* The data 
*/ 
public void setData(int[] data) { 
    this.data = data; 
} 

}