JERSEY का उपयोग करके इनपुट और आउटपुट बाइनरी स्ट्रीम?


111

मैं जर्सी का उपयोग एक RESTful एपीआई को लागू करने के लिए कर रहा हूं जो मुख्य रूप से JSON एन्कोडेड डेटा को पुनः प्राप्त और सेवा करता है। लेकिन मेरे पास कुछ परिस्थितियां हैं जहां मुझे निम्नलिखित की आवश्यकता है:

  • PDF, XLS, ZIP, या अन्य बाइनरी फ़ाइलों जैसे डाउनलोड करने योग्य दस्तावेज़ों को निर्यात करें।
  • मल्टीपार्ट डेटा को पुनः प्राप्त करें, जैसे कि कुछ JSON प्लस एक अपलोड की गई XLS फ़ाइल

मेरे पास एक एकल पेज JQuery- आधारित वेब क्लाइंट है जो इस वेब सेवा के लिए AJAX कॉल करता है। फिलहाल, यह फॉर्म सबमिट नहीं करता है, और GET और POST (JSON ऑब्जेक्ट के साथ) का उपयोग करता है। क्या मुझे डेटा और एक संलग्न बाइनरी फ़ाइल भेजने के लिए एक फॉर्म पोस्ट का उपयोग करना चाहिए, या क्या मैं JSON प्लस बाइनरी फ़ाइल के साथ एक मल्टीपार्ट अनुरोध बना सकता हूं?

मेरे एप्लिकेशन की सर्विस लेयर इस समय एक बाइटएयरऑउटपुटस्ट्रीम बनाती है, जब वह एक पीडीएफ फाइल बनाती है। जर्सी के माध्यम से क्लाइंट को इस स्ट्रीम को आउटपुट करने का सबसे अच्छा तरीका क्या है? मैंने एक MessageBodyWriter बनाया है, लेकिन मुझे पता नहीं है कि इसे एक जर्सी संसाधन से कैसे उपयोग किया जाए। क्या यह सही तरीका है?

मैं जर्सी के साथ शामिल नमूनों के माध्यम से देख रहा हूं, लेकिन अभी तक कुछ भी नहीं मिला है जो बताता है कि इन चीजों में से कैसे करें। यदि यह मायने रखता है, तो मैं XML- स्टेप के बिना JSON पर ऑब्जेक्ट-> JSON के साथ जर्सी का उपयोग कर रहा हूं और वास्तव में JAX-RS का उपयोग नहीं कर रहा हूं।

जवाबों:


109

मैं 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);
            }
        }
    };
}

PDFGenerator वर्ग (पीडीएफ बनाने के लिए मेरी अपनी कक्षा) लेखन विधि से आउटपुट स्ट्रीम लेता है और एक नए बनाए गए आउटपुट स्ट्रीम के बजाय इसे लिखता है।

पता नहीं कि यह करने का सबसे अच्छा तरीका है, लेकिन यह काम करता है।


33
किसी Responseऑब्जेक्ट के लिए StreamingOutput को इकाई के रूप में वापस करना भी संभव है । इस तरह आप आसानी से mediatype, HTTP response code आदि को नियंत्रित कर सकते हैं। मुझे बताएं कि क्या आप चाहते हैं कि मैं कोड पोस्ट करूं।
हांक


3
मैंने एक संदर्भ के रूप में इस उदाहरण में कोड उदाहरणों का उपयोग किया, और पाया कि मुझे आउटपुट प्राप्त करने के लिए क्लाइंट के लिए StreamingOutput.write () में आउटपुटस्ट्रीम को फ्लश करने की आवश्यकता है। अन्यथा मुझे कभी-कभी हेडर और कोई बॉडी में "कंटेंट-लेंथ: 0" मिलता है, हालांकि लॉग्स ने मुझे बताया कि स्ट्रीमिंगऑटपुट निष्पादित हो रहा था।
जॉन स्टीवर्ट

@JonStewart - मेरा मानना ​​है कि मैं जेनरेटडीएफ विधि के भीतर फ्लश कर रहा था।
माइक। रायडर

1
@ Dante617। क्या आप क्लाइंट साइड कोड पोस्ट करेंगे कि कैसे जर्सी क्लाइंट सर्वर के लिए बाइनरी स्ट्रीम (जर्सी 2.x के साथ) भेजेगा?
डेबोरा

29

मुझे एक 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();

26
यह अच्छा नहीं है, क्योंकि पूरी तरह से तैयार होने के बाद ही आउटपुट भेजा जाता है। एक बाइट [] एक स्ट्रीम नहीं है।
java.is.for.desktop

7
यह मेमोरी में सभी बाइट्स का उपभोग करता है, जिसका अर्थ है कि बड़ी फाइलें सर्वर को नीचे ला सकती हैं। स्ट्रीमिंग का उद्देश्य मेमोरी में सभी बाइट्स का सेवन करने से बचना है।
रॉबर्ट क्रिश्चियन

22

मैं इस कोड को एक्सेल में एक्सल (xlsx) फ़ाइल (अपाचे पोई) को अटैचमेंट के रूप में निर्यात करने के लिए उपयोग कर रहा हूं।

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

}

15

यहाँ एक और उदाहरण है। मैं एक PNG के माध्यम से एक QRCode बना रहा हूँ a 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 फ़ाइलों के लिए काम करता है ...


6
मुझे लगता है कि यह एक बुरा स्ट्रीमिंग उदाहरण है, क्योंकि आउटपुट में दी गई वस्तु एक बाइट सरणी है और स्ट्रीम नहीं है।
एलिकएल्ज़िन-किलाका

जीईटी संसाधन अनुरोध के जवाब के निर्माण के लिए अच्छा उदाहरण, धारा के लिए अच्छा उदाहरण नहीं। यह एक धारा नहीं है।
रॉबर्ट क्रिश्चियन

14

मैं अपनी जर्सी 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();
}

7

यह उदाहरण दिखाता है कि जेबीओस में लॉग फ़ाइलों को एक आराम संसाधन के माध्यम से कैसे प्रकाशित किया जाए। नोट करें कि विधि लॉग फ़ाइल की सामग्री को स्ट्रीम करने के लिए 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();
    }
}    

}


1
बस FYI करें: पाइप विधि के बजाय आप Apache commons I / O से IOUtils.copy का उपयोग कर सकते हैं।
डेविड

7

जर्सी 2.16 फ़ाइल डाउनलोड का उपयोग करना बहुत आसान है।

नीचे ज़िप फ़ाइल के लिए उदाहरण है

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

1
एक जादू की तरह काम करता है। इस स्ट्रीमिंग सामग्री के बारे में कोई विचार है जो मुझे काफी समझ में नहीं आता है ...
ओलिवर

1
यह सबसे आसान तरीका है अगर आप जर्सी का उपयोग करते हैं, धन्यवाद
ganchito55

क्या @GET की जगह @POST के साथ करना संभव है?
एसपीआर

@ एसआरआर मुझे लगता है कि हाँ, यह संभव है। जब सर्वर पृष्ठ जवाब देता है, तो उसे डाउनलोड विंडो
नारंगीगिराफ

5

मुझे मेरे लिए निम्नलिखित मददगार लगी और मैं चाहता था कि अगर यह आपकी या किसी और की मदद करे। मुझे MediaType.PDF_TYPE जैसा कुछ चाहिए था, जो मौजूद नहीं है, लेकिन यह कोड समान काम करता है:

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

Http://jersey.java.net/nonav/apidocs/1.1.0-ea/contribs/jersey-multipart/com/sun/jult/multipart/file/DefaultMediaTredPredictor.CommonMediaTypes.html देखें

मेरे मामले में मैं एक अन्य साइट पर एक पीडीएफ दस्तावेज़ पोस्ट कर रहा था:

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 पोस्ट करने के लिए दूसरे पैरामीटर के रूप में पास हो जाता है ()।

इस कोड को एक साथ स्निपेट में डालने के लिए यह लिंक मेरे लिए उपयोगी था: http://jersey.576304.n2.nabble.com/Multipart-Post-td4252846.html


4

इसने मेरे साथ ठीक काम किया 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();
}

1
के बारे में निश्चित नहीं है Response.ok("file path null").build();, क्या यह वास्तव में ठीक है? आपको शायद कुछ का उपयोग करना चाहिए जैसेResponse.status(Status.BAD_REQUEST).entity(...
क्रिस्टोफ़े रूसो

1

एक अन्य नमूना कोड जहां आप REST सेवा में फ़ाइल अपलोड कर सकते हैं, REST सेवा फ़ाइल को ज़िप करती है, और क्लाइंट सर्वर से ज़िप फ़ाइल डाउनलोड करता है। यह जर्सी का उपयोग करके बाइनरी इनपुट और आउटपुट स्ट्रीम का उपयोग करने का एक अच्छा उदाहरण है।

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

यह उत्तर मेरे द्वारा दूसरे सूत्र में पोस्ट किया गया था। उम्मीद है की यह मदद करेगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.