webentwicklung-frage-antwort-db.com.de

Wie kann ich eine Datei vom REST Web-Service zum Client senden?

Ich habe gerade angefangen, REST Services zu entwickeln, aber ich bin auf eine schwierige Situation gestoßen: Senden von Dateien von meinem REST Service an meinen Kunden. Bisher habe ich gelernt, wie man einfache Datentypen (Zeichenfolgen, Ganzzahlen usw.) sendet, aber das Senden einer Datei ist eine andere Angelegenheit, da es so viele Dateiformate gibt, dass ich nicht weiß, wo ich überhaupt anfangen soll. Mein REST Service wird auf Java ausgeführt und ich verwende Jersey. Ich sende alle Daten im JSON-Format.

Ich habe über die Base64-Codierung gelesen. Einige Leute sagen, dass dies eine gute Technik ist, andere sagen, dass dies nicht auf Probleme mit der Dateigröße zurückzuführen ist. Was ist der richtige Weg? So sieht eine einfache Ressourcenklasse in meinem Projekt aus:

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

Ich vermute, der Code für das Senden einer Datei würde ungefähr so ​​lauten:

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

Welche Art von Anmerkungen sollte ich verwenden? Ich habe einige Leute gesehen, die @GET Mit @Produces({application/x-octet-stream}) empfehlen. Ist das der richtige Weg? Die von mir gesendeten Dateien sind spezifisch, sodass der Client die Dateien nicht durchsuchen muss. Kann mich jemand anleiten, wie ich die Datei senden soll? Sollte ich es mit base64 codieren, um es als JSON-Objekt zu senden? oder ist die Kodierung nicht erforderlich, um es als JSON-Objekt zu senden? Vielen Dank für jede Hilfe, die Sie geben können.

91
Uriel

Es wird nicht empfohlen, Binärdaten in base64 zu codieren und in JSON zu verpacken. Es wird nur unnötig die Größe der Antwort erhöhen und die Dinge verlangsamen.

Stellen Sie Ihre Dateidaten einfach mit GET und application/octect-stream Mit einer der Factory-Methoden von javax.ws.rs.core.Response (Teil der JAX-RS-API) bereit, damit Sie nicht an diese gebunden sind 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();
}

Wenn Sie kein tatsächliches File -Objekt haben, aber ein InputStream, sollte Response.ok(entity, mediaType) auch damit umgehen können.

122

Wenn Sie eine herunterzuladende Datei zurückgeben möchten, insbesondere wenn Sie Javascript-Bibliotheken für das Hoch- und Herunterladen von Dateien einbinden möchten, sollte der folgende Code die Aufgabe übernehmen:

@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();
}
5
john 4d5

Ändern Sie die Rechneradresse von localhost in die IP-Adresse, mit der Ihr Client eine Verbindung herstellen soll, um den unten genannten Dienst aufzurufen.

Client zum Aufrufen des 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 für den Antwort-Client:

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 benötigt:

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>
5