source

JUERGY를 사용한 입력 및 출력 바이너리 스트림

topadmin 2022. 10. 23. 10:37

JUERGY를 사용한 입력 및 출력 바이너리 스트림

Jersey를 사용하여 JSON 인코딩된 데이터를 주로 검색 및 제공하는 RESTful API를 구현하고 있습니다.하지만 다음 사항을 수행해야 하는 상황이 있습니다.

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

이 웹 서비스에 대한 AJAX 콜을 작성하는 단일 페이지 JQuery 기반 웹 클라이언트가 있습니다.현재 폼 제출은 하지 않고 GET 및 POST(JSON 개체 포함)를 사용합니다.Form Post를 사용하여 데이터와 첨부 바이너리 파일을 전송해야 합니까?아니면 JSON + 바이너리 파일로 멀티파트 요청을 작성할 수 있습니까?

현재 애플리케이션의 서비스 계층은 PDF 파일을 생성할 때 ByteArrayOutputStream을 생성합니다.저지를 통해 이 스트림을 클라이언트에 출력하는 가장 좋은 방법은 무엇입니까?MessageBodyWriter를 작성했는데 Jersey 리소스에서 사용하는 방법을 모릅니다.그게 올바른 접근법인가요?

Jersey에 포함된 샘플을 살펴봤지만, 이 둘 중 어느 것도 어떻게 하는지 알 수 있는 것은 아직 찾지 못했습니다.Jersey와 Jackson을 사용하여 Object->J를 하고 싶습니다.XML 스텝을 사용하지 않고 실제로 JAX-RS를 사용하고 있지 않다.

ZIP 파일 또는 PDF 파일을 확장하여 얻을 수 있었습니다.StreamingOutput물건.다음은 샘플 코드입니다.

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

PDF Generator 클래스(PDF 작성을 위한 나만의 클래스)는 새로 생성된 출력 스트림 대신 쓰기 메서드에서 출력 스트림을 가져와 여기에 씁니다.

이게 최선의 방법인지는 모르겠지만, 효과가 있어요.

나는 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리소스는 A를 반환합니다.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();
}

다음 예에서는 나머지 리소스를 통해 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();
    }
}    

}

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

저는 다음 내용이 저에게 도움이 된다는 것을 알았고, 혹시 여러분이나 다른 사람에게 도움이 될지 모르니 공유하고 싶었습니다.나는 Media Type 같은 것을 원했다.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

이 조작은, 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();
}

REST 서비스에 파일을 업로드하고 REST 서비스가 파일을 압축하고 클라이언트가 서버에서 zip 파일을 다운로드하는 또 다른 샘플코드입니다.이것은 Jersey를 사용한 바이너리 입력 및 출력 스트림을 사용하는 좋은 예입니다.

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

이 답변은 제가 다른 스레드에 올린 것입니다.이게 도움이 됐으면 좋겠다.

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