IT story

JERSEY를 사용하여 입력 및 출력 이진 스트림?

hot-time 2020. 8. 3. 17:38
반응형

JERSEY를 사용하여 입력 및 출력 이진 스트림?


Jersey를 사용하여 주로 JSON 인코딩 데이터를 검색하고 제공하는 RESTful API를 구현하고 있습니다. 그러나 다음과 같은 상황이 필요합니다.

  • PDF, XLS, ZIP 또는 기타 이진 파일과 같은 다운로드 가능한 문서를 내 보냅니다.
  • 일부 JSON 및 업로드 된 XLS 파일과 같은 멀티 파트 데이터 검색

이 웹 서비스에 대한 AJAX 호출을 생성하는 단일 페이지 JQuery 기반 웹 클라이언트가 있습니다. 현재는 양식 제출을 수행하지 않으며 JSON 객체와 함께 GET 및 POST를 사용합니다. 양식 게시물을 사용하여 데이터와 첨부 된 이진 파일을 보내야합니까, 아니면 JSON과 이진 파일로 멀티 파트 요청을 만들 수 있습니까?

내 응용 프로그램의 서비스 계층은 현재 PDF 파일을 생성 할 때 ByteArrayOutputStream을 만듭니다. Jersey를 통해이 스트림을 클라이언트에 출력하는 가장 좋은 방법은 무엇입니까? MessageBodyWriter를 만들었지 만 Jersey 리소스에서 사용하는 방법을 모르겠습니다. 이것이 올바른 접근입니까?

Jersey에 포함 된 샘플을 살펴 보았지만 이러한 작업 중 하나를 수행하는 방법을 보여주는 내용은 아직 찾지 못했습니다. 중요한 경우 XML 단계없이 Object-> JSON을 수행하기 위해 Jackson과 Jersey를 사용하고 있으며 실제로 JAX-RS를 사용하지 않습니다.


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 메소드에서 출력 스트림을 가져 와서 새로 작성된 출력 스트림 대신 출력 스트림에 기록합니다.

그것이 최선의 방법인지 모르겠지만 작동합니다.


나는 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();

이 코드를 사용하여 저지의 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();

}

또 다른 예가 있습니다. 를 통해 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 파일에서 작동합니다 ...


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

This example shows how to publish log files in JBoss through a rest resource. Note the get method uses the StreamingOutput interface to stream the content of the log file.

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

}


Using Jersey 2.16 File download is very easy.

Below is the example for the ZIP file

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

I found the following helpful to me and I wanted to share in case it helps you or someone else. I wanted something like MediaType.PDF_TYPE, which doesn't exist, but this code does the same thing:

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

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

In my case I was posting a PDF document to another site:

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

Then p gets passed as the second parameter to post().

This link was helpful to me in putting this code snippet together: http://jersey.576304.n2.nabble.com/Multipart-Post-td4252846.html


This worked fine with me 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();
}

Another sample code where you can upload a file to the REST service, the REST service zips the file, and the client downloads the zip file from the server. This is a good example of using binary input and output streams using Jersey.

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

This answer was posted by me in another thread. Hope this helps.

참고URL : https://stackoverflow.com/questions/3496209/input-and-output-binary-streams-using-jersey

반응형