2012-09-02 12 views
67

Właśnie zacząłem rozwijać usługi REST, ale natknąłem się na trudną sytuację: wysyłanie plików z mojej usługi REST do mojego klienta. Do tej pory zrozumiałem, jak wysyłać proste typy danych (łańcuchy, liczby całkowite itp.), Ale wysyłanie pliku to inna sprawa, ponieważ istnieje tak wiele formatów plików, że nie wiem, od czego powinienem zacząć. Moja usługa REST jest wykonywana na Javie i używam Jersey, wysyłam wszystkie dane w formacie JSON.jaki jest prawidłowy sposób wysyłania pliku z usługi WWW REST do klienta?

Przeczytałem o kodowaniu base64, niektórzy twierdzą, że jest to dobra technika, inni twierdzą, że nie jest to spowodowane problemami z rozmiarami plików. Jaki jest prawidłowy sposób? Jest to, jak prosta klasa zasób w moim projekcie poszukuje:

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

Zgaduję kod do wysyłania pliku byłoby coś takiego:

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

Jaki rodzaj adnotacji należy użyć? Widziałem, że niektórzy ludzie polecają @GET używając @Produces({application/x-octet-stream}), czy to jest właściwy sposób? Pliki, które wysyłam, są specyficzne, więc klient nie musi przeglądać plików. Czy każdy może mnie poprowadzić w jaki sposób mam wysłać plik? Czy mogę zakodować go przy użyciu base64, aby wysłać go jako obiekt JSON? czy kodowanie nie jest konieczne, aby wysłać je jako obiekt JSON? Dziękuję za pomoc, którą możesz udzielić.

+0

Czy masz rzeczywisty 'java.io.File' (lub pliku path) na serwerze lub są dane pochodzące z innego źródła, takie jak bazy danych, usług internetowych, wywołanie metody zwracanie 'InputStream'? –

Odpowiedz

93

I don” t zalecane kodowanie danych binarnych w base64 i owijanie w JSON. To tylko niepotrzebnie zwiększy rozmiar odpowiedzi i spowolni działania.

prostu służyć do danych plików za pomocą GET i application/octect-stream za pomocą jednej z metod fabrycznych javax.ws.rs.core.Response (część API JAX-RS, więc nie jesteś zamknięty w 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(); 
} 

Jeśli don nie ma rzeczywistego obiektu File, ale powinien on także być w stanie obsłużyć to, InputStream, Response.ok(entity, mediaType).

+0

dziękuję, działało świetnie, ale co jeśli chcę spożyć całą strukturę folderów? Myślałem coś podobnego [this] (http://pastebin.com/XJy4gkNj) Również od kiedy będę otrzymywać różne pliki na kliencie, w jaki sposób powinienem traktować odpowiedź jednostki HttpResponse? – Uriel

+3

Spójrz na ['ZipOutputStream'] (http://docs.oracle.com/javase/6/docs/api/java/util/zip/ZipOutputStream.html) wraz z zwracaniem [' StreamingOutput'] (http : //jsr311.java.net/nonav/javadoc/javax/ws/rs/core/StreamingOutput.html) z 'getFile()'. W ten sposób otrzymujesz dobrze znany format wielu plików, który większość klientów powinna łatwo odczytać. Używaj kompresji tylko wtedy, gdy ma to sens dla twoich danych, tzn. Nie dla wstępnie skompresowanych plików, takich jak JPEG. Po stronie klienta znajduje się ['ZipInputStream'] (http://docs.oracle.com/javase/6/docs/api/java/util/zip/ZipInputStream.html), aby przeanalizować odpowiedź. –

+1

Może to pomóc: http://stackoverflow.com/questions/10100936/file-downloading-in-restfull-web-services –

-3

Ponieważ korzystasz z JSON, zakodowałbym Base64 przed wysłaniem go przez przewód.

Jeśli pliki są duże, spróbuj spojrzeć na BSON lub inny format, który jest lepszy w przypadku transferów binarnych.

Można również skompresować pliki, jeśli kompresują się dobrze, zanim zaczną je kodować base64.

+0

Planowałem je skompresować przed wysłaniem ich z powodu całego rozmiaru pliku, ale jeśli mam go kodować64, co powinien zawierać adnotacja '@ Produces'? – Uriel

+0

application/json zgodnie ze specyfikacją JSON, niezależnie od tego, co w nim wstawisz. (http://www.ietf.org/rfc/rfc4627.txt?number=4627) Pamiętaj, że zakodowany plik base64 powinien nadal znajdować się wewnątrz znaczników JSON – LarsK

+2

Nie ma żadnej korzyści w kodowaniu danych binarnych w base64, a następnie owijaniu go w JSON. To tylko niepotrzebnie zwiększy rozmiar odpowiedzi i spowolni działania. –

5

Jeśli chcesz powrócić do pliku do pobrania, szczególnie jeśli chcesz zintegrować z niektórych javascript libs upload file/download, wówczas poniżej kod powinien wykonać zadanie:

@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

Zmień adres urządzenia z localhost na adres IP, z którym chcesz połączyć się z klientem w celu połączenia się z poniższą usługą.

Client zadzwonić REST usługa:

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

Service do klienta odpowiedź:

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 potrzebne:

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

FOR Rest Api file download purpose.rest kod klienta –

Powiązane problemy