qual è il modo corretto per inviare un file dal servizio web REST al client?

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 è diverso, 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.

Ho letto della 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? Ecco come sta una semplice class di risorse nel mio progetto:

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 getTemas() throws SQLException{ TemaDao temaDao = new TemaDao(); List temas=temaDao.getTemas(); temaDao.terminarSesion(); return temas; } } 

Sto indovinando 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}) , è 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 object JSON? o la codifica non è necessaria per inviarlo come object JSON? Grazie per l’aiuto che potresti dare.

Non consiglio di codificare i dati binari in base64 e di inserirli in JSON. Aumenterà inutilmente le dimensioni della risposta e rallenterà le cose.

application/octect-stream semplicemente i tuoi dati di file usando GET e application/octect-stream usando uno dei metodi di fabbrica di javax.ws.rs.core.Response (parte dell’API JAX-RS, quindi non sei bloccato 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 non si dispone di un object File effettivo, ma un InputStream , Response.ok(entity, mediaType) dovrebbe essere in grado di gestirlo.

Se si desidera restituire un file da scaricare, specialmente se si desidera integrare con alcune librerie javascript di caricamento / download di file, 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(); } 

Cambia l’indirizzo della macchina da localhost all’indirizzo IP a cui desideri che il tuo client si connetta per chiamare il servizio sotto menzionato.

Client per chiamare il servizio web REST:

 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 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 per il cliente di 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 aveva bisogno di:

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

web.xml:

   DownloadFileDemo  JAX-RS REST Servlet JAX-RS REST Servlet com.sun.jersey.spi.container.servlet.ServletContainer  com.sun.jersey.config.property.packages in.india.service.downloadfiledemo  1   JAX-RS REST Servlet /services/*   index.jsp   

Dal momento che stai usando JSON, vorrei Base64 codificarlo prima di inviarlo attraverso il filo.

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

Puoi anche comprimere i file, se comprimono bene, prima che la base64 li codifichi.