当前位置:  开发笔记 > 编程语言 > 正文

使用JERSEY输入和输出二进制流?

如何解决《使用JERSEY输入和输出二进制流?》经验,为你挑选了8个好方法。

我正在使用Jersey实现一个主要检索和提供JSON编码数据的RESTful API.但我有一些情况需要完成以下事项:

导出可下载的文档,例如PDF,XLS,ZIP或其他二进制文件.

检索多部分数据,例如一些JSON和上传的XLS文件

我有一个基于JQuery的单页Web客户端,它可以为这个Web服务创建AJAX调用.目前,它不进行表单提交,并使用GET和POST(使用JSON对象).我应该使用表单发送数据和附加的二进制文件,还是可以使用JSON plus二进制文件创建多部分请求?

我的应用程序的服务层当前在生成PDF文件时创建ByteArrayOutputStream.通过Jersey将此流输出到客户端的最佳方法是什么?我已经创建了一个MessageBodyWriter,但我不知道如何从Jersey资源中使用它.这是正确的方法吗?

我一直在查看泽西岛附带的样本,但还没有找到任何说明如何做这些事情的东西.如果重要的是,我正在使用泽西与杰克逊做没有XML步骤的对象 - > JSON,并没有真正使用JAX-RS.



1> MikeTheReade..:

我设法通过扩展StreamingOutput对象获得ZIP文件或PDF文件.以下是一些示例代码:

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

PDFGenerator类(我自己的用于创建PDF的类)从write方法获取输出流并写入而不是新创建的输出流.

不知道这是否是最佳方式,但它确实有效.


也可以将StreamingOutput作为实体返回到"Response"对象.这样你就可以轻松控制媒体类型,HTTP响应代码等.如果你想让我发布代码,请告诉我.
@MyTitle:见[例子](http://stackoverflow.com/questions/3496209/input-and-output-binary-streams-using-jersey/12573173#12573173)
我使用此线程中的代码示例作为参考,并发现我需要在StreamingOutput.write()中刷新OutputStream,以便客户端可靠地接收输出.否则我有时会在标题中找到"Content-Length:0"并且没有正文,即使日志告诉我StreamingOutput正在执行.

2> Abhishek Rak..:

我不得不返回一个rtf文件,这对我有用.

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


不太好,因为输出只有在完全准备好后才会发送.byte []不是流.
这会占用内存中的所有字节,这意味着大文件可能会导致服务器崩溃.流式传输的目的是避免将所有字节消耗到内存中.

3> Grégory..:

我正在使用此代码将excel(xlsx)文件(Apache Poi)作为附件导出.

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

}



4> Hank..:

这是另一个例子.我正在创建一个QRCode作为PNG ByteArrayOutputStream.资源返回一个Response对象,流的数据是实体.

为了说明响应代码处理,我已经添加了缓存头(处理If-modified-since,If-none-matches等等).

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

请不要打败我以防万一stream.toByteArray()没有记忆:)它适用于我的<1KB PNG文件......


我认为这是一个糟糕的流示例,因为输出中返回的对象是字节数组而不是流.

5> Daniel Szala..:

我一直在通过以下方式编写Jersey 1.17服务:

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

和客户,如果你需要它:

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



6> Jaime Casero..:

此示例显示如何通过rest资源在JBoss中发布日志文件.请注意,get方法使用StreamingOutput接口来流式传输日志文件的内容.

@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> 小智..:

使用Jersey 2.16文件下载非常简单.

以下是ZIP文件的示例

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



8> Dovev Hefetz..:

我发现以下内容对我有帮助,我希望分享以防万一它可以帮助您或其他人.我想要像MediaType.PDF_TYPE这样的东西,它不存在,但是这段代码做了同样的事情:

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

见 http://jersey.java.net/nonav/apidocs/1.1.0-ea/contribs/jersey-multipart/com/sun/jersey/multipart/file/DefaultMediaTypePredictor.CommonMediaTypes.html

就我而言,我将PDF文档发布到另一个站点:

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")));

然后p作为第二个参数传递给post().

这个链接对我将这段代码片段放在一起很有帮助:http: //jersey.576304.n2.nabble.com/Multipart-Post-td4252846.html

推荐阅读
k78283381
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有