2015-09-30 14 views
22

Sto provando a scaricare/caricare un file con Retrofit 2 ma non riesco a trovare esempi di tutorial su come farlo. Il mio codice per il download è: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); 

e

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()); 
     } 
    }); 

Ho provato con Call e Call, ma nulla sembra funzionare.

Il codice lato server scrive i byte del file nel flusso di output di HttpServletResponse dopo aver impostato correttamente le intestazioni e il tipo mime.

Cosa sto sbagliando?

Infine, il codice di caricamento:

@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); 

e

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()); 
       } 
      }); 

Grazie!

Edit:

Dopo la risposta, il download solo produce un file danneggiato (senza il @Streaming), caricando non si pure. Quando utilizzo il codice precedente, il server restituisce un errore 400. Dopo averlo modificato in

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()); 

, la richiesta viene eseguita ma il backend non sembra ricevere un file.

codice 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) 

Che cosa sto facendo di sbagliato? Sono stato in grado di utilizzare il backend dalla pianura Java con 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); 

Modifica v2

Per chiunque sia interessato, sia a monte e il download di lavoro ora: Queste sono le soluzioni:

Servizio:

@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); 

Scarica Codice:

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()); 
      } 
     }); 

Upload Codice:

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

quali messaggi di registro stai ottenendo. è possibile impostare il livello di registro 'restAdapter.setLogLevel (LogLevel.FULL);' – Eoin

+0

Dopo aver aggiunto la registrazione tramite Retrofit.client(). interceptors(). add, il problema sembra essere che la lunghezza del contenuto è sempre 0 ma non ho idea perché, il file esiste sul file system. – N4zroth

+0

Si può aggiornare con il metodo di download completo in Spring Server, per favore? Grazie –

risposta

18

per il download, è possibile utilizzare ResponseBody come tipo di ritorno -

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

e si può ottenere il flusso ResponseBody di ingresso nel vostro call back -

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 

Il tuo caricamento sembra ok a prima vista se si ver gestisce correttamente i messaggi multipart. Funziona?In caso contrario, puoi spiegare la modalità fallimento? Potresti anche essere in grado di semplificare non rendendolo multipart. Rimuovere il @Multipart annotazioni e convertire @Path a @Body -

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

Grazie, il download funziona ora, solo il caricamento non funziona - vedi modifica per la descrizione del problema :-) – N4zroth

3

Sto usando retrofit 2.0.0-beta2 e ho avuto un problema di caricare un'immagine utilizzando richiesta multipart. Ho risolto questo problema utilizzando questa risposta: https://stackoverflow.com/a/32796626/2915075

La chiave per me era utilizzare POST standard con MultipartRequestBody anziché la richiesta annotata @Multipart.

Qui è il mio codice:

classe di servizio Retrofit

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

Uso dall'attività, frammento:

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 è ora MultipartBody.Builder in okhttp3 –

0

Inoltre ho avuto questo problema, è così che cerco di risolvere il mio problema (retrofit 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

È possibile fare riferimento tutorial per Image Download using Retrofit 2.0

Per il momento è possibile fare riferimento seguenti funzioni per scaricare l'immagine:

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()); 
     } 
    }); 
} 

In seguito è l'immagine parte scaricare la gestione dei file utilizzando Retrofit 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; 
    } 
} 

Spero che possa essere d'aiuto. Ti auguro il meglio. Happy Coding :)