2012-09-02 22 views
67

Ho appena iniziato a sviluppare i servizi REST, ma mi sono imbattuto in una situazione difficile: l'invio di file dal mio servizio REST al mio cliente. Finora ho imparato come inviare semplici tipi di dati (stringhe, interi, ecc.) Ma l'invio di un file è una questione diversa poiché ci sono così tanti formati di file che non so dove dovrei iniziare. Il mio servizio REST è realizzato su Java e sto utilizzando Jersey, sto inviando tutti i dati utilizzando il formato JSON.qual è il modo corretto per inviare un file dal servizio web REST al client?

Ho letto sulla codifica base64, alcune persone dicono che è una buona tecnica, altri dicono che non è a causa di problemi di dimensioni del file. Qual è il modo corretto? Questo è come una semplice classe di risorse nel mio progetto è alla ricerca:

import java.sql.SQLException; 
import java.util.List; 

import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.Produces; 
import javax.ws.rs.core.Context; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.core.Request; 
import javax.ws.rs.core.UriInfo; 

import com.mx.ipn.escom.testerRest.dao.TemaDao; 
import com.mx.ipn.escom.testerRest.modelo.Tema; 

@Path("/temas") 
public class TemaResource { 

    @GET 
    @Produces({MediaType.APPLICATION_JSON}) 
    public List<Tema> getTemas() throws SQLException{ 

     TemaDao temaDao = new TemaDao();   
     List<Tema> temas=temaDao.getTemas(); 
     temaDao.terminarSesion(); 

     return temas; 
    } 
} 

sto cercando di indovinare il codice per l'invio di un file sarebbe qualcosa di simile:

import java.sql.SQLException; 

import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.Produces; 

@Path("/resourceFiles") 
public class FileResource { 

    @GET 
    @Produces({application/x-octet-stream}) 
    public File getFiles() throws SQLException{ //I'm not really sure what kind of data type I should return 

     // Code for encoding the file or just send it in a data stream, I really don't know what should be done here 

     return file; 
    } 
} 

Che tipo di annotazioni dovrei usare? Ho visto alcune persone consigliare per un @GET utilizzando @Produces({application/x-octet-stream}), è che il modo corretto? I file che invio sono specifici, quindi il client non ha bisogno di sfogliare i file. Qualcuno può guidarmi in come dovrei inviare il file? Dovrei codificarlo usando base64 per inviarlo come oggetto JSON? o la codifica non è necessaria per inviarlo come oggetto JSON? Grazie per l'aiuto che potresti dare.

+0

Avete un vero e proprio java.io.File' (o file path) 'sul vostro server o sono i dati provenienti da qualche altra fonte, come un database, servizio Web, chiamata di metodo restituire un 'InputStream'? –

risposta

93

I don' t consiglia di codificare i dati binari in base64 e di inserirli in JSON. Aumenterà inutilmente le dimensioni della risposta e rallenterà le cose.

Semplicemente servono i dati di file utilizzando GET e application/octect-stream utilizzando uno dei metodi di fabbrica di javax.ws.rs.core.Response (parte della API JAX-RS, in modo da non siete bloccati in Jersey):

@GET 
@Produces(MediaType.APPLICATION_OCTET_STREAM) 
public Response getFile() { 
    File file = ... // Initialize this to the File path you want to serve. 
    return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM) 
     .header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"") //optional 
     .build(); 
} 

Se don 't hanno un oggetto reale File, ma un InputStream, Response.ok(entity, mediaType) dovrebbe essere in grado di gestire anche quello.

+0

grazie, questo ha funzionato alla grande, ma cosa succede se voglio consumare un'intera struttura di cartelle? Stavo pensando qualcosa come [questo] (http://pastebin.com/XJy4gkNj) Inoltre, dal momento che riceverò vari file sul client, come dovrei trattare la risposta dell'entità di HttpResponse? – Uriel

+3

Dai un'occhiata a ['ZipOutputStream'] (http://docs.oracle.com/javase/6/docs/api/java/util/zip/ZipOutputStream.html) insieme a restituire uno [' StreamingOutput'] (http : //jsr311.java.net/nonav/javadoc/javax/ws/rs/core/StreamingOutput.html) da 'getFile()'. In questo modo si ottiene un noto formato multi-file che la maggior parte dei client dovrebbe essere in grado di leggere facilmente. Usa la compressione solo se ha senso per i tuoi dati, ad esempio non per i file pre-compressi come i JPEG. Sul lato client, c'è ['ZipInputStream'] (http://docs.oracle.com/javase/6/docs/api/java/util/zip/ZipInputStream.html) per analizzare la risposta. –

+1

Questo potrebbe aiutare: http://stackoverflow.com/questions/10100936/file-downloading-in-restfull-web-services –

-3

Dal momento che si utilizza JSON, vorrei Base64 codificarlo prima di inviarlo attraverso il filo.

Se i file sono di grandi dimensioni, provare a guardare BSON, o qualche altro formato che è meglio con i trasferimenti binari.

È anche possibile comprimere i file, se comprimono bene, prima di codificarli in base64.

+0

Avevo intenzione di comprimerle prima di inviarle per l'intero motivo della dimensione del file, ma se la codec64 lo codifica, cosa dovrebbe contenere la mia annotazione '@ Produces'? – Uriel

+0

application/json secondo le specifiche JSON, indipendentemente da ciò che viene inserito. (http://www.ietf.org/rfc/rfc4627.txt?number=4627) Ricordare che il file codificato base64 deve essere ancora all'interno dei tag JSON – LarsK

+2

Non c'è alcun vantaggio nella codifica dei dati binari in base64 e quindi nel suo wrapping JSON. Aumenterà inutilmente le dimensioni della risposta e rallenterà le cose. –

5

Se si desidera restituire un file da scaricare, specialmente se si desidera integrare con alcune librerie javascript di upload di file/download, quindi il codice qui sotto dovrebbe fare il lavoro:

@GET 
@Path("/{key}") 
public Response download(@PathParam("key") String key, 
         @Context HttpServletResponse response) throws IOException { 
    try { 
     //Get your File or Object from wherever you want... 
      //you can use the key parameter to indentify your file 
      //otherwise it can be removed 
     //let's say your file is called "object" 
     response.setContentLength((int) object.getContentLength()); 
     response.setHeader("Content-Disposition", "attachment; filename=" 
       + object.getName()); 
     ServletOutputStream outStream = response.getOutputStream(); 
     byte[] bbuf = new byte[(int) object.getContentLength() + 1024]; 
     DataInputStream in = new DataInputStream(
       object.getDataInputStream()); 
     int length = 0; 
     while ((in != null) && ((length = in.read(bbuf)) != -1)) { 
      outStream.write(bbuf, 0, length); 
     } 
     in.close(); 
     outStream.flush(); 
    } catch (S3ServiceException e) { 
     e.printStackTrace(); 
    } catch (ServiceException e) { 
     e.printStackTrace(); 
    } 
    return Response.ok().build(); 
} 
4

Modificare l'indirizzo della macchina da localhost all'indirizzo IP a cui si desidera connettere il client per chiamare il servizio indicato di seguito.

client chiamare REST webservice:

package in.india.client.downloadfiledemo; 

import java.io.BufferedInputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 

import javax.ws.rs.core.MediaType; 
import javax.ws.rs.core.Response.Status; 

import com.sun.jersey.api.client.Client; 
import com.sun.jersey.api.client.ClientHandlerException; 
import com.sun.jersey.api.client.ClientResponse; 
import com.sun.jersey.api.client.UniformInterfaceException; 
import com.sun.jersey.api.client.WebResource; 
import com.sun.jersey.multipart.BodyPart; 
import com.sun.jersey.multipart.MultiPart; 

public class DownloadFileClient { 

    private static final String BASE_URI = "http://localhost:8080/DownloadFileDemo/services/downloadfile"; 

    public DownloadFileClient() { 

     try { 
      Client client = Client.create(); 
      WebResource objWebResource = client.resource(BASE_URI); 
      ClientResponse response = objWebResource.path("/") 
        .type(MediaType.TEXT_HTML).get(ClientResponse.class); 

      System.out.println("response : " + response); 
      if (response.getStatus() == Status.OK.getStatusCode() 
        && response.hasEntity()) { 
       MultiPart objMultiPart = response.getEntity(MultiPart.class); 
       java.util.List<BodyPart> listBodyPart = objMultiPart 
         .getBodyParts(); 
       BodyPart filenameBodyPart = listBodyPart.get(0); 
       BodyPart fileLengthBodyPart = listBodyPart.get(1); 
       BodyPart fileBodyPart = listBodyPart.get(2); 

       String filename = filenameBodyPart.getEntityAs(String.class); 
       String fileLength = fileLengthBodyPart 
         .getEntityAs(String.class); 
       File streamedFile = fileBodyPart.getEntityAs(File.class); 

       BufferedInputStream objBufferedInputStream = new BufferedInputStream(
         new FileInputStream(streamedFile)); 

       byte[] bytes = new byte[objBufferedInputStream.available()]; 

       objBufferedInputStream.read(bytes); 

       String outFileName = "D:/" 
         + filename; 
       System.out.println("File name is : " + filename 
         + " and length is : " + fileLength); 
       FileOutputStream objFileOutputStream = new FileOutputStream(
         outFileName); 
       objFileOutputStream.write(bytes); 
       objFileOutputStream.close(); 
       objBufferedInputStream.close(); 
       File receivedFile = new File(outFileName); 
       System.out.print("Is the file size is same? :\t"); 
       System.out.println(Long.parseLong(fileLength) == receivedFile 
         .length()); 
      } 
     } catch (UniformInterfaceException e) { 
      e.printStackTrace(); 
     } catch (ClientHandlerException e) { 
      e.printStackTrace(); 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

    } 

    public static void main(String... args) { 
     new DownloadFileClient(); 
    } 
} 

servizio al cliente la risposta:

package in.india.service.downloadfiledemo; 

import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.Produces; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.core.Response; 

import com.sun.jersey.multipart.MultiPart; 

@Path("downloadfile") 
@Produces("multipart/mixed") 
public class DownloadFileResource { 

    @GET 
    public Response getFile() { 

     java.io.File objFile = new java.io.File(
       "D:/DanGilbert_2004-480p-en.mp4"); 
     MultiPart objMultiPart = new MultiPart(); 
     objMultiPart.type(new MediaType("multipart", "mixed")); 
     objMultiPart 
       .bodyPart(objFile.getName(), new MediaType("text", "plain")); 
     objMultiPart.bodyPart("" + objFile.length(), new MediaType("text", 
       "plain")); 
     objMultiPart.bodyPart(objFile, new MediaType("multipart", "mixed")); 

     return Response.ok(objMultiPart).build(); 

    } 
} 

JAR necessari:

jersey-bundle-1.14.jar 
jersey-multipart-1.14.jar 
mimepull.jar 

WEB.XML:

<?xml version="1.0" encoding="UTF-8"?> 
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    id="WebApp_ID" version="2.5"> 
    <display-name>DownloadFileDemo</display-name> 
    <servlet> 
     <display-name>JAX-RS REST Servlet</display-name> 
     <servlet-name>JAX-RS REST Servlet</servlet-name> 
     <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> 
     <init-param> 
      <param-name>com.sun.jersey.config.property.packages</param-name> 
      <param-value>in.india.service.downloadfiledemo</param-value> 
     </init-param> 
     <load-on-startup>1</load-on-startup> 
    </servlet> 
    <servlet-mapping> 
     <servlet-name>JAX-RS REST Servlet</servlet-name> 
     <url-pattern>/services/*</url-pattern> 
    </servlet-mapping> 
    <welcome-file-list> 
     <welcome-file>index.jsp</welcome-file> 
    </welcome-file-list> 
</web-app> 
1
package com.mastercard.dispute.pro.openapi.casefiling.restservice.impl; 

import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.HttpURLConnection; 
import java.net.MalformedURLException; 
import java.net.URL; 

import javax.ws.rs.core.MediaType; 

public class DownloadFileClient { 

    // http://localhost:8080/RESTfulExample/json/product/get 
    public static void main(String[] args) { 
     FileOutputStream out = null; 
     try { 

      URL url = new URL(
        "http://localhost:8080/ProService/json/claims/document/case/10000016?userId=n000027&&format=ORIGINAL"); 
      HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
      conn.setRequestMethod("GET"); 
      conn.setRequestProperty("Accept", MediaType.MULTIPART_FORM_DATA); 
      conn.setRequestProperty("system_id", "op"); 
      conn.setRequestProperty("source", "s0001"); 
      conn.setRequestProperty("user_id", "n000027"); 

      if (conn.getResponseCode() != 200) { 
       throw new RuntimeException("Failed : HTTP error code : " 
         + conn.getResponseCode()); 
      } 

      /* 
      * BufferedReader br = new BufferedReader(new InputStreamReader(
      * (conn.getInputStream()))); 
      */ 

      InputStream in = conn.getInputStream(); 

      out = new FileOutputStream(
        "C:\\Users\\E077106\\Desktop\\upload_15_05_2017\\sunil.zip"); 
      copy(in, out, 1024); 
      out.close(); 
      String output; 
      System.out.println("Output from Server .... \n"); 
      /* 
      * while ((output = br.readLine()) != null) { 
      * System.out.println(output); } 
      */ 
      conn.disconnect(); 

     } catch (MalformedURLException e) { 

      e.printStackTrace(); 

     } catch (IOException e) { 

      e.printStackTrace(); 

     } 
    } 

    public static void copy(InputStream input, OutputStream output, 
      int bufferSize) throws IOException { 
     byte[] buf = new byte[bufferSize]; 
     int n = input.read(buf); 
     while (n >= 0) { 
      output.write(buf, 0, n); 
      n = input.read(buf); 
     } 
     output.flush(); 
    } 

} 
+0

PER Il file Api di riposo scarica il codice client di purpose.rest –

Problemi correlati