2015-09-30 3 views
22

Я пытаюсь загрузить/загрузить файл с модификацией 2, но не могу найти примеры учебников о том, как это сделать. Моего код скачивания:Retrofit 2 file down/upload

@GET("documents/checkout") 
public Call<File> checkout(@Query(value = "documentUrl") String documentUrl, @Query(value = "accessToken") String accessToken, @Query(value = "readOnly") boolean readOnly); 

и

Call<File> call = RetrofitSingleton.getInstance(serverAddress) 
       .checkout(document.getContentUrl(), apiToken, readOnly[i]); 
call.enqueue(new Callback<File>() { 
     @Override 
     public void onResponse(Response<File> response, 
       Retrofit retrofit) { 
      String fileName = document.getFileName(); 
      try { 
       System.out.println(response.body()); 
       long fileLength = response.body().length(); 
       InputStream input = new FileInputStream(response.body()); 
       File path = Environment.getExternalStorageDirectory(); 
       File file = new File(path, fileName); 
       BufferedOutputStream output = new BufferedOutputStream(
         new FileOutputStream(file)); 
       byte data[] = new byte[1024]; 

       long total = 0; 
       int count; 
       while ((count = input.read(data)) != -1) { 
        total += count; 
        output.write(data, 0, count); 
       } 

       output.flush(); 

       output.close(); 
      } catch (IOException e) { 
       String logTag = "TEMPTAG"; 
       Log.e(logTag, "Error while writing file!"); 
       Log.e(logTag, e.toString()); 
      } 
     } 
     @Override 
     public void onFailure(Throwable t) { 
      // TODO: Error handling 
      System.out.println(t.toString()); 
     } 
    }); 

Я попытался с звонком и, но ничего не похоже на работу.

Код на стороне сервера записывает байты файла в выходной поток HttpServletResponse после правильной настройки заголовков и типа mime.

Что я делаю неправильно?

Наконец, код загрузки:

@Multipart 
@POST("documents/checkin") 
public Call<String> checkin(@Query(value = "documentId") String documentId, @Query(value = "name") String fileName, @Query(value = "accessToken") String accessToken, @Part("file") RequestBody file); 

и

RequestBody requestBody = RequestBody.create(MediaType.parse(document.getMimeType()), file); 

      Call<String> call = RetrofitSingleton.getInstance(serverAddress).checkin(documentId, document.getFileName(), apiToken, requestBody); 
      call.enqueue(new Callback<String>() { 
       @Override 
       public void onResponse(Response<String> response, Retrofit retrofit) { 
        System.out.println(response.body()); 
       } 

       @Override 
       public void onFailure(Throwable t) { 
        System.out.println(t.toString()); 
       } 
      }); 

Спасибо!

Edit:

После ответа, загрузка только дает поврежденный файл (без @Streaming), загрузка не так. Когда я использую вышеуказанный код, сервер возвращает ошибку 400. После его замены на

RequestBody requestBody = RequestBody.create(MediaType.parse(document.getMimeType()), file); 
      MultipartBuilder multipartBuilder = new MultipartBuilder(); 
      multipartBuilder.addFormDataPart("file", document.getFileName(), requestBody); 

      Call<String> call = RetrofitSingleton.getInstance(serverAddress).checkin(documentId, document.getFileName(), apiToken, multipartBuilder.build()); 

запрос выполняется, но бэкенд, похоже, не получает файл.

код Backend:

@RequestMapping(value = "/documents/checkin", method = RequestMethod.POST) 
public void checkInDocument(@RequestParam String documentId, 
     @RequestParam String name, @RequestParam MultipartFile file, 
     @RequestParam String accessToken, HttpServletResponse response) 

Что я делаю неправильно? Я был в состоянии использовать бэкенд из простого Java с помощью Apache HTTPClient:

MultipartEntityBuilder builder = MultipartEntityBuilder.create(); 
    builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); 
    builder.addBinaryBody("file", new File("E:\\temp\\test.jpg")); 
    HttpEntity httpEntity = builder.build(); 
    System.out.println("HttpEntity " + EntityUtils.toString(httpEntity.)); 
    HttpPost httpPost = new HttpPost(uri); 
    httpPost.setEntity(httpEntity); 

Edit v2

Для тех, кто заинтересован, как вверх и скачивания работы в настоящее время: это решение:

Услуги:

@GET("documents/checkout") 
public Call<ResponseBody> checkout(@Query(value = "documentUrl") String documentUrl, @Query(value = "accessToken") String accessToken, @Query(value = "readOnly") boolean readOnly); 

@Multipart 
@POST("documents/checkin") 
public Call<String> checkin(@Query(value = "documentId") String documentId, @Query(value = "name") String fileName, @Query(value = "accessToken") String accessToken, @Part("file") RequestBody file); 

Скачать Код:

Call<ResponseBody> call = RetrofitSingleton.getInstance(serverAddress) 
       .checkout(document.getContentUrl(), apiToken, readOnly[i]); 
     call.enqueue(new Callback<ResponseBody>() { 
      @Override 
      public void onResponse(Response<ResponseBody> response, 
        Retrofit retrofit) { 
       String fileName = document.getFileName(); 

       try { 
        File path = Environment.getExternalStorageDirectory(); 
        File file = new File(path, fileName); 
        FileOutputStream fileOutputStream = new FileOutputStream(file); 
        IOUtils.write(response.body().bytes(), fileOutputStream); 
       } catch (IOException e) { 
        Log.e(logTag, "Error while writing file!"); 
        Log.e(logTag, e.toString()); 
       } 
      } 

      @Override 
      public void onFailure(Throwable t) { 
       // TODO: Error handling 
       System.out.println(t.toString()); 
      } 
     }); 

Загрузить код:

Call<String> call = RetrofitSingleton 
        .getInstance(serverAddress).checkin(documentId, 
          document.getFileName(), apiToken, 
          multipartBuilder.build()); 
      call.enqueue(new Callback<String>() { 
       @Override 
       public void onResponse(Response<String> response, 
         Retrofit retrofit) { 
        // Handle response here 
       } 

       @Override 
       public void onFailure(Throwable t) { 
        // TODO: Error handling 
        System.out.println("Error"); 
        System.out.println(t.toString()); 
       } 
      }); 
+0

какие сообщения журнала вы получаете. вы можете установить уровень журнала 'restAdapter.setLogLevel (LogLevel.FULL);' – Eoin

+0

После добавления журнала через Retrofit.client(). interceptors(). add, проблема заключается в том, что длина содержимого всегда равна 0, но у меня нет идея, почему файл существует в файловой системе. – N4zroth

+0

Не могли бы вы обновить с помощью метода полной загрузки на сервере Spring? Спасибо –

ответ

18

Для скачивания, вы можете использовать ResponseBody в качестве типа возвращаемого значения -

@GET("documents/checkout") 
@Streaming 
public Call<ResponseBody> checkout(@Query("documentUrl") String documentUrl, @Query("accessToken") String accessToken, @Query("readOnly") boolean readOnly); 

и вы можете получить поток на ResponseBody вход в ваш обратный вызов -

Call<ResponseBody> call = RetrofitSingleton.getInstance(serverAddress) 
      .checkout(document.getContentUrl(), apiToken, readOnly[i]); 

call.enqueue(new Callback<ResponseBody>() { 
     @Override 
     public void onResponse(Response<ResponseBody> response, 
       Retrofit retrofit) { 
      String fileName = document.getFileName(); 
      try { 
       InputStream input = response.body().byteStream(); 
       // rest of your code 

Ваша загрузка выглядит на первый взгляд, если вы ver правильно обрабатывает множественные сообщения. Работает?Если нет, можете ли вы объяснить режим отказа? Вы также можете упростить, не делая его многочастным. Удалите @Multipart аннотацию и конвертировать @Path в @Body -

@POST("documents/checkin") 
public Call<String> checkin(@Query("documentId") String documentId, @Query("name") String fileName, @Query("accessToken") String accessToken, @Body RequestBody file); 
+0

Спасибо, сейчас скачивает работы, только загрузка не работает - см. Edit для описания проблемы :-) – N4zroth

3

Я использую модифицированную 2.0.0-beta2 и у меня была проблема с загрузкой изображения с помощью многослойную запроса. Я решил это, используя этот ответ: https://stackoverflow.com/a/32796626/2915075

Ключ для меня состоял в том, чтобы использовать стандартный POST с MultipartRequestBody вместо аннотированного запроса @Multipart.

Вот мой код:

класс дооснащения службы

@POST("photo") 
Call<JsonElement> uploadPhoto(@Body RequestBody imageFile, @Query("sessionId")); 

Usage от активности, фрагмент:

RequestBody fileBody = RequestBody.create(MediaType.parse("image/jpeg"), imageFile); 
MultipartBuilder multipartBuilder = new MultipartBuilder(); 
multipartBuilder.addFormDataPart("photo", imageFile.getName(), fileBody); 
RequestBody fileRequestBody = multipartBuilder.build(); 

//call 
mRestClient.getRetrofitService().uploadProfilePhoto(fileRequestBody, sessionId); 
+3

MultipartBuilder теперь MultipartBody.Builder в okhttp3 –

0

Также у меня была эта проблема, это как я пытаюсь решить мою проблему (ДООСНАСТКЕ 2)

//1. What We Need From Server (upload.php Script) 
    public class FromServer { 
     String result; 
    } 

    //2. Which Interface To Communicate Our upload.php Script? 
    public interface ServerAPI { 

     @Multipart 
     @POST("upload.php")//Our Destination PHP Script 
     Call<List<FromServer>> upload(
       @Part("file_name") String file_name, 
       @Part("file") RequestBody description); 

     Retrofit retrofit = 
       new Retrofit.Builder() 
         .baseUrl("http://192.168.43.135/retro/") // REMEMBER TO END with/
         .addConverterFactory(GsonConverterFactory.create()) 
       .build(); 
    } 


    //3. How To Upload 
    private void upload(){ 

      ServerAPI api = ServerAPI.retrofit.create(ServerAPI.class); 

      File from_phone = FileUtils.getFile(Environment.getExternalStorageDirectory()+"/aa.jpg"); //org.apache.commons.io.FileUtils 
      RequestBody to_server = RequestBody.create(MediaType.parse("multipart/form-data"), from_phone); 

      api.upload(from_phone.getName(),to_server).enqueue(new Callback<List<FromServer>>() { 
       @Override 
       public void onResponse(Call<List<FromServer>> call, Response<List<FromServer>> response) { 
        Toast.makeText(MainActivity.this, response.body().get(0).result, Toast.LENGTH_SHORT).show(); 
       } 
       @Override 
       public void onFailure(Call<List<FromServer>> call, Throwable t) { } 
      }); 


     } 

//4. upload.php 
<?php 

    $pic = $_POST['file_name']; 

    $pic = str_replace("\"", "", $pic); //REMOVE " from file name 
    if(file_exists($pic)){unlink($pic);} 

    $f = fopen($pic, "w"); 
    fwrite($f,$_POST['file']); 
    fclose($f); 

    $arr[] = array("result"=>"Done"); 
    print(json_encode($arr)); 
?> 
0

Вы можете обратиться учебник для Image Download using Retrofit 2.0

В настоящее время вы можете обратиться следующие функции для загрузки изображения:

void getRetrofitImage() { 

    Retrofit retrofit = new Retrofit.Builder() 
      .baseUrl(url) 
      .addConverterFactory(GsonConverterFactory.create()) 
      .build(); 

    RetrofitImageAPI service = retrofit.create(RetrofitImageAPI.class); 

    Call<ResponseBody> call = service.getImageDetails(); 

    call.enqueue(new Callback<ResponseBody>() { 
     @Override 
     public void onResponse(Response<ResponseBody> response, Retrofit retrofit) { 

      try { 

       Log.d("onResponse", "Response came from server"); 

       boolean FileDownloaded = DownloadImage(response.body()); 

       Log.d("onResponse", "Image is downloaded and saved ? " + FileDownloaded); 

      } catch (Exception e) { 
       Log.d("onResponse", "There is an error"); 
       e.printStackTrace(); 
      } 

     } 

     @Override 
     public void onFailure(Throwable t) { 
      Log.d("onFailure", t.toString()); 
     } 
    }); 
} 

Ниже приводится обработка загрузки файла часть изображения с помощью Дооснащение 2.0

private boolean DownloadImage(ResponseBody body) { 

    try { 
     Log.d("DownloadImage", "Reading and writing file"); 
     InputStream in = null; 
     FileOutputStream out = null; 

     try { 
      in = body.byteStream(); 
      out = new FileOutputStream(getExternalFilesDir(null) + File.separator + "AndroidTutorialPoint.jpg"); 
      int c; 

      while ((c = in.read()) != -1) { 
       out.write(c); 
      } 
     } 
     catch (IOException e) { 
      Log.d("DownloadImage",e.toString()); 
      return false; 
     } 
     finally { 
      if (in != null) { 
       in.close(); 
      } 
      if (out != null) { 
       out.close(); 
      } 
     } 

     int width, height; 
     ImageView image = (ImageView) findViewById(R.id.imageViewId); 
     Bitmap bMap = BitmapFactory.decodeFile(getExternalFilesDir(null) + File.separator + "AndroidTutorialPoint.jpg"); 
     width = 2*bMap.getWidth(); 
     height = 6*bMap.getHeight(); 
     Bitmap bMap2 = Bitmap.createScaledBitmap(bMap, width, height, false); 
     image.setImageBitmap(bMap2); 

     return true; 

    } catch (IOException e) { 
     Log.d("DownloadImage",e.toString()); 
     return false; 
    } 
} 

Надеюсь, это поможет. Всего наилучшего. Happy Coding :)

Смежные вопросы