it-swarm.com.de

Ein- und Ausgabe von Binärströmen mit JERSEY?

Ich verwende Jersey, um eine RESTful-API zu implementieren, die hauptsächlich JSON-codierte Daten abruft und bereitstellt. In einigen Situationen muss ich jedoch Folgendes ausführen:

  • Exportieren Sie herunterladbare Dokumente wie PDF, XLS, Zip oder andere Binärdateien.
  • Rufen Sie mehrteilige Daten ab, z. B. JSON und eine hochgeladene XLS-Datei

Ich habe einen einseitigen JQuery-basierten Web-Client, der AJAX Aufrufe an diesen Web-Service erstellt. Derzeit werden keine Formulare gesendet und GET und POST (mit einem JSON-Objekt). Soll ich einen Formularpost zum Senden von Daten und einer angehängten Binärdatei verwenden oder kann ich eine mehrteilige Anforderung mit JSON plus Binärdatei erstellen?

Der Service-Layer meiner Anwendung erstellt derzeit einen ByteArrayOutputStream, wenn eine PDF) -Datei generiert wird. Wie kann ich diesen Stream am besten über Jersey an den Client ausgeben? Ich habe einen MessageBodyWriter erstellt, aber ich habe keinen ' Ich weiß nicht, wie ich es aus einer Jersey-Ressource verwenden soll. Ist das der richtige Ansatz?

Ich habe die mit Jersey gelieferten Beispiele durchgesehen, aber noch nichts gefunden, was zeigt, wie man eines dieser Dinge macht. Wenn es darauf ankommt, verwende ich Jersey mit Jackson, um Object-> JSON ohne den XML-Schritt auszuführen, und verwende JAX-RS nicht wirklich.

109
Tauren

Ich habe es geschafft, eine Zip-Datei oder eine PDF Datei durch Erweitern des Objekts StreamingOutput zu erhalten. Hier ist ein Beispielcode:

@Path("PDF-file.pdf/")
@GET
@Produces({"application/pdf"})
public StreamingOutput getPDF() throws Exception {
    return new StreamingOutput() {
        public void write(OutputStream output) throws IOException, WebApplicationException {
            try {
                PDFGenerator generator = new PDFGenerator(getEntity());
                generator.generatePDF(output);
            } catch (Exception e) {
                throw new WebApplicationException(e);
            }
        }
    };
}

Die PDFGenerator-Klasse (meine eigene Klasse zum Erstellen der PDF-Datei) entnimmt den Ausgabestream der write-Methode und schreibt in diesen anstelle eines neu erstellten Ausgabestreams.

Ich weiß nicht, ob dies der beste Weg ist, aber es funktioniert.

108
MikeTheReader

Ich musste eine RTF-Datei zurückgeben und das funktionierte für mich.

// create a byte array of the file in correct format
byte[] docStream = createDoc(fragments); 

return Response
            .ok(docStream, MediaType.APPLICATION_OCTET_STREAM)
            .header("content-disposition","attachment; filename = doc.rtf")
            .build();
29

Ich verwende diesen Code, um eine Excel (xlsx) -Datei (Apache Poi) in Jersey als Anhang zu exportieren.

@GET
@Path("/{id}/contributions/Excel")
@Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
public Response exportExcel(@PathParam("id") Long id)  throws Exception  {

    Resource resource = new ClassPathResource("/xls/template.xlsx");

    final InputStream inp = resource.getInputStream();
    final Workbook wb = WorkbookFactory.create(inp);
    Sheet sheet = wb.getSheetAt(0);

    Row row = CellUtil.getRow(7, sheet);
    Cell cell = CellUtil.getCell(row, 0);
    cell.setCellValue("TITRE TEST");

    [...]

    StreamingOutput stream = new StreamingOutput() {
        public void write(OutputStream output) throws IOException, WebApplicationException {
            try {
                wb.write(output);
            } catch (Exception e) {
                throw new WebApplicationException(e);
            }
        }
    };


    return Response.ok(stream).header("content-disposition","attachment; filename = export.xlsx").build();

}
22
Grégory

Hier ist ein weiteres Beispiel. Ich erstelle einen QRCode als PNG über ein ByteArrayOutputStream. Die Ressource gibt ein Response -Objekt zurück und die Daten des Streams sind die Entität.

Um die Handhabung des Antwortcodes zu veranschaulichen, habe ich die Handhabung von Cache-Headern (If-modified-since, If-none-matches Usw.) hinzugefügt.

@Path("{externalId}.png")
@GET
@Produces({"image/png"})
public Response getAsImage(@PathParam("externalId") String externalId, 
        @Context Request request) throws WebApplicationException {

    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    // do something with externalId, maybe retrieve an object from the
    // db, then calculate data, size, expirationTimestamp, etc

    try {
        // create a QRCode as PNG from data     
        BitMatrix bitMatrix = new QRCodeWriter().encode(
                data, 
                BarcodeFormat.QR_CODE, 
                size, 
                size
        );
        MatrixToImageWriter.writeToStream(bitMatrix, "png", stream);

    } catch (Exception e) {
        // ExceptionMapper will return HTTP 500 
        throw new WebApplicationException("Something went wrong …")
    }

    CacheControl cc = new CacheControl();
    cc.setNoTransform(true);
    cc.setMustRevalidate(false);
    cc.setNoCache(false);
    cc.setMaxAge(3600);

    EntityTag etag = new EntityTag(HelperBean.md5(data));

    Response.ResponseBuilder responseBuilder = request.evaluatePreconditions(
            updateTimestamp,
            etag
    );
    if (responseBuilder != null) {
        // Preconditions are not met, returning HTTP 304 'not-modified'
        return responseBuilder
                .cacheControl(cc)
                .build();
    }

    Response response = Response
            .ok()
            .cacheControl(cc)
            .tag(etag)
            .lastModified(updateTimestamp)
            .expires(expirationTimestamp)
            .type("image/png")
            .entity(stream.toByteArray())
            .build();
    return response;
}   

Bitte verprügel mich nicht, falls stream.toByteArray() ein No-No-Speicher ist :) Es funktioniert für meine <1KB PNG-Dateien ...

15
Hank

Ich habe meine Jersey 1.17-Dienste folgendermaßen zusammengestellt:

FileStreamingOutput

public class FileStreamingOutput implements StreamingOutput {

    private File file;

    public FileStreamingOutput(File file) {
        this.file = file;
    }

    @Override
    public void write(OutputStream output)
            throws IOException, WebApplicationException {
        FileInputStream input = new FileInputStream(file);
        try {
            int bytes;
            while ((bytes = input.read()) != -1) {
                output.write(bytes);
            }
        } catch (Exception e) {
            throw new WebApplicationException(e);
        } finally {
            if (output != null) output.close();
            if (input != null) input.close();
        }
    }

}

GET

@GET
@Produces("application/pdf")
public StreamingOutput getPdf(@QueryParam(value="name") String pdfFileName) {
    if (pdfFileName == null)
        throw new WebApplicationException(Response.Status.BAD_REQUEST);
    if (!pdfFileName.endsWith(".pdf")) pdfFileName = pdfFileName + ".pdf";

    File pdf = new File(Settings.basePath, pdfFileName);
    if (!pdf.exists())
        throw new WebApplicationException(Response.Status.NOT_FOUND);

    return new FileStreamingOutput(pdf);
}

Und der Kunde, wenn Sie es brauchen:

Client

private WebResource resource;

public InputStream getPDFStream(String filename) throws IOException {
    ClientResponse response = resource.path("pdf").queryParam("name", filename)
        .type("application/pdf").get(ClientResponse.class);
    return response.getEntityInputStream();
}
14
Daniel Szalay

In diesem Beispiel wird gezeigt, wie Protokolldateien in JBoss über eine Restressource veröffentlicht werden. Beachten Sie, dass die Methode get die StreamingOutput-Schnittstelle verwendet, um den Inhalt der Protokolldatei zu streamen.

@Path("/logs/")
@RequestScoped
public class LogResource {

private static final Logger logger = Logger.getLogger(LogResource.class.getName());
@Context
private UriInfo uriInfo;
private static final String LOG_PATH = "jboss.server.log.dir";

public void pipe(InputStream is, OutputStream os) throws IOException {
    int n;
    byte[] buffer = new byte[1024];
    while ((n = is.read(buffer)) > -1) {
        os.write(buffer, 0, n);   // Don't allow any extra bytes to creep in, final write
    }
    os.close();
}

@GET
@Path("{logFile}")
@Produces("text/plain")
public Response getLogFile(@PathParam("logFile") String logFile) throws URISyntaxException {
    String logDirPath = System.getProperty(LOG_PATH);
    try {
        File f = new File(logDirPath + "/" + logFile);
        final FileInputStream fStream = new FileInputStream(f);
        StreamingOutput stream = new StreamingOutput() {
            @Override
            public void write(OutputStream output) throws IOException, WebApplicationException {
                try {
                    pipe(fStream, output);
                } catch (Exception e) {
                    throw new WebApplicationException(e);
                }
            }
        };
        return Response.ok(stream).build();
    } catch (Exception e) {
        return Response.status(Response.Status.CONFLICT).build();
    }
}

@POST
@Path("{logFile}")
public Response flushLogFile(@PathParam("logFile") String logFile) throws URISyntaxException {
    String logDirPath = System.getProperty(LOG_PATH);
    try {
        File file = new File(logDirPath + "/" + logFile);
        PrintWriter writer = new PrintWriter(file);
        writer.print("");
        writer.close();
        return Response.ok().build();
    } catch (Exception e) {
        return Response.status(Response.Status.CONFLICT).build();
    }
}    

}

7
Jaime Casero

Verwenden von Jersey 2.16 Das Herunterladen von Dateien ist sehr einfach.

Unten ist das Beispiel für die Zip-Datei

@GET
@Path("zipFile")
@Produces("application/Zip")
public Response getFile() {
    File f = new File(Zip_FILE_PATH);

    if (!f.exists()) {
        throw new WebApplicationException(404);
    }

    return Response.ok(f)
            .header("Content-Disposition",
                    "attachment; filename=server.Zip").build();
}
6
orangegiraffa

Ich fand das Folgende hilfreich für mich und wollte es teilen, falls es dir oder jemand anderem hilft. Ich wollte etwas wie MediaType.PDF_TYPE, das es nicht gibt, aber dieser Code macht dasselbe:

DefaultMediaTypePredictor.CommonMediaTypes.
        getMediaTypeFromFileName("anything.pdf")

Siehe http://jersey.Java.net/nonav/apidocs/1.1.0-ea/contribs/jersey-multipart/com/Sun/jersey/multipart/file/DefaultMediaTypePredictor.CommonMediaTypes.html

In meinem Fall habe ich ein PDF Dokument auf einer anderen Seite gepostet:

FormDataMultiPart p = new FormDataMultiPart();
p.bodyPart(new FormDataBodyPart(FormDataContentDisposition
        .name("fieldKey").fileName("document.pdf").build(),
        new File("path/to/document.pdf"),
        DefaultMediaTypePredictor.CommonMediaTypes
                .getMediaTypeFromFileName("document.pdf")));

Dann wird p als zweiter Parameter an post () übergeben.

Dieser Link hat mir beim Zusammenstellen dieses Codeausschnitts geholfen: http://jersey.576304.n2.nabble.com/Multipart-Post-td4252846.html

5
Dovev Hefetz

Dies hat bei mir problemlos funktioniert. URL: http://example.com/rest/muqsith/get-file?filePath=C :\Users\I066807\Desktop\test.xml

@GET
@Produces({ MediaType.APPLICATION_OCTET_STREAM })
@Path("/get-file")
public Response getFile(@Context HttpServletRequest request){
   String filePath = request.getParameter("filePath");
   if(filePath != null && !"".equals(filePath)){
        File file = new File(filePath);
        StreamingOutput stream = null;
        try {
        final InputStream in = new FileInputStream(file);
        stream = new StreamingOutput() {
            public void write(OutputStream out) throws IOException, WebApplicationException {
                try {
                    int read = 0;
                        byte[] bytes = new byte[1024];

                        while ((read = in.read(bytes)) != -1) {
                            out.write(bytes, 0, read);
                        }
                } catch (Exception e) {
                    throw new WebApplicationException(e);
                }
            }
        };
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
        return Response.ok(stream).header("content-disposition","attachment; filename = "+file.getName()).build();
        }
    return Response.ok("file path null").build();
}
4
Muqsith

Ein weiterer Beispielcode, mit dem Sie eine Datei zum REST= Service hochladen können, der REST Service komprimiert die Datei und der Client lädt die Zip-Datei vom Server herunter. Dies ist ein gutes Beispiel für die Verwendung von binären Eingabe- und Ausgabestreams mit Jersey.

https://stackoverflow.com/a/32253028/15789

Diese Antwort wurde von mir in einem anderen Thread gepostet. Hoffe das hilft.

1