2012-09-02 3 views
67

Je viens de commencer à développer des services REST, mais j'ai rencontré une situation difficile: envoyer des fichiers de mon service REST à mon client. Jusqu'à présent, j'ai compris comment envoyer des types de données simples (chaînes, entiers, etc.) mais l'envoi d'un fichier est une question différente car il y a tellement de formats de fichiers que je ne sais pas où je devrais commencer. Mon service REST est fait sur Java et j'utilise Jersey, j'envoie toutes les données en utilisant le format JSON. J'ai lu à propos de l'encodage base64, certaines personnes disent que c'est une bonne technique, d'autres disent que ce n'est pas à cause de problèmes de taille de fichier. Quelle est la bonne façon? Voici comment une simple classe de ressources dans mon projet est à la recherche:Quelle est la bonne façon d'envoyer un fichier du service Web REST au client?

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

Je devine que le code pour envoyer un fichier serait quelque chose comme:

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

Quel genre d'annotations dois-je utiliser? J'ai vu certaines personnes recommandent pour @GET en utilisant @Produces({application/x-octet-stream}), est-ce la bonne façon? Les fichiers que j'envoie sont spécifiques, de sorte que le client n'a pas besoin de parcourir les fichiers. Quelqu'un peut-il me guider dans la façon dont je suis censé envoyer le fichier? Dois-je l'encoder en utilisant base64 pour l'envoyer en tant qu'objet JSON? ou le codage n'est pas nécessaire pour l'envoyer en tant qu'objet JSON? Merci pour toute aide que vous pourriez donner.

+0

Avez-vous une 'java.io.File' réelle (ou chemin du fichier) sur votre serveur ou est les données provenant d'une autre source, comme une base de données, service Web, appel de méthode renvoyer un 'InputStream'? –

Répondre

93

Je ne t recommande de coder les données binaires dans base64 et de les encapsuler dans JSON. Cela augmentera inutilement la taille de la réponse et ralentira les choses.

servent simplement vos données de fichiers en utilisant GET et application/octect-stream en utilisant l'une des méthodes d'usine de javax.ws.rs.core.Response (partie de l'API JAX-RS, de sorte que vous n'êtes pas prisonnier 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(); 
} 

Si vous ne pas un objet réel File, mais un InputStream, Response.ok(entity, mediaType) devrait être capable de gérer cela aussi bien.

+0

merci, cela a bien fonctionné, mais si je veux consommer toute une structure de dossier? Je pensais quelque chose comme [ceci] (http://pastebin.com/XJy4gkNj) Aussi puisque je recevrai divers dossiers sur le client, comment devrais-je traiter la réponse d'entité de HttpResponse? – Uriel

+3

Jetez un coup d'œil à ['ZipOutputStream'] (http://docs.oracle.com/javase/6/docs/api/java/util/zip/ZipOutputStream.html) et renvoyez un [' StreamingOutput'] (http : //jsr311.java.net/nonav/javadoc/javax/ws/rs/core/StreamingOutput.html) from 'getFile()'. De cette façon, vous obtenez un format multi-fichiers bien connu que la plupart des clients devraient pouvoir lire facilement. Utilisez la compression uniquement si cela a un sens pour vos données, c'est-à-dire pas pour les fichiers pré-compressés tels que les fichiers JPEG. Du côté client, il y a ['ZipInputStream'] (http://docs.oracle.com/javase/6/docs/api/java/util/zip/ZipInputStream.html) pour analyser la réponse. –

+1

Cela peut aider: http://stackoverflow.com/questions/10100936/file-downloading-in-restfull-web-services –

-3

Depuis que vous utilisez JSON, je Base64 l'encoder avant de l'envoyer à travers le fil.

Si les fichiers sont volumineux, essayez de regarder BSON, ou un autre format qui est meilleur avec les transferts binaires.

Vous pouvez également compresser les fichiers, s'ils se compriment bien, avant leur encodage en base64.

+0

Je prévoyais de les compresser avant de les envoyer pour toute la raison de la taille du fichier, mais si je le code en base64, que devrait contenir mon annotation '@ Produces'? – Uriel

+0

application/json selon la spécification JSON, indépendamment de ce que vous y mettez. (http://www.ietf.org/rfc/rfc4627.txt?number=4627) Gardez à l'esprit que le fichier encodé en base64 doit toujours se trouver dans les balises JSON. – LarsK

+2

Il n'y a aucun avantage à encoder des données binaires dans base64, JSON. Cela augmentera inutilement la taille de la réponse et ralentira les choses. –

5

Si vous voulez retourner un fichier à télécharger, spécialement si vous souhaitez intégrer quelques libs javascript de fichier upload/download, le soufflet de code doit faire le travail:

@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

Changez l'adresse de l'ordinateur localhost en adresse IP avec laquelle vous souhaitez que votre client se connecte pour appeler le service mentionné ci-dessous.

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

service au client de réponse:

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 nécessaire:

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 télécharger le code client purpose.rest –

Questions connexes