JERSEY ব্যবহার করে ইনপুট এবং আউটপুট বাইনারি স্ট্রিম?


111

আমি জার্সিকে একটি RESTful API বাস্তবায়ন করতে ব্যবহার করছি যা প্রাথমিকভাবে JSON এনকোডড ডেটা পুনরুদ্ধার এবং পরিবেশন করছে। তবে আমার কিছু পরিস্থিতি রয়েছে যেখানে আমাকে নিম্নলিখিতগুলি সম্পাদন করতে হবে:

  • ডাউনলোডযোগ্য ডকুমেন্টগুলি যেমন পিডিএফ, এক্সএলএস, জিপ বা অন্যান্য বাইনারি ফাইলগুলি রফতানি করুন।
  • মাল্টিপার্ট ডেটা, যেমন কিছু JSON প্লাস একটি আপলোড হওয়া XLS ফাইল পুনরুদ্ধার করুন

আমার কাছে একটি একক পৃষ্ঠার জিকুয়ারি-ভিত্তিক ওয়েব ক্লায়েন্ট রয়েছে যা এই ওয়েব পরিষেবায় আজেএক্স কলগুলি তৈরি করে। এই মুহুর্তে, এটি জমা দেয় না, এবং জিইটি এবং পোস্ট ব্যবহার করে (একটি জেএসওএন অবজেক্ট সহ)। ডেটা এবং সংযুক্ত বাইনারি ফাইল প্রেরণের জন্য কি আমার একটি ফর্ম পোস্ট ব্যবহার করা উচিত, বা আমি জেএসএন প্লাস বাইনারি ফাইলের সাথে একটি মাল্টিপার্ট অনুরোধ তৈরি করতে পারি?

আমার অ্যাপ্লিকেশনটির পরিষেবা স্তরটি যখন একটি পিডিএফ ফাইল জেনারেট করে তখন বাইটআর্যআউটপুট স্ট্রিম তৈরি করে। এই স্ট্রিমটি জার্সির মাধ্যমে ক্লায়েন্টের কাছে আউটপুট দেওয়ার সর্বোত্তম উপায় কী? আমি একটি বার্তাবাডিওয়াইটার তৈরি করেছি, তবে জার্সির উত্স থেকে এটি কীভাবে ব্যবহার করতে হয় তা আমি জানি না। এটা কি সঠিক পন্থা?

আমি জার্সির সাথে অন্তর্ভুক্ত নমুনাগুলি সন্ধান করছি, কিন্তু এখনও এমন কিছু খুঁজে পাইনি যা এইগুলির মধ্যে কোনটি কীভাবে করবে তা চিত্রিত করে। যদি এটি গুরুত্বপূর্ণ হয় তবে আমি জ্যাকসনের সাথে জার্সিকে এক্সএমএল পদক্ষেপ ছাড়াই অবজেক্ট-> জেএসএন করার জন্য ব্যবহার করছি এবং জ্যাকস-আরএসকে সত্যিই ব্যবহার করছি না।

উত্তর:


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

পিডিএফ জেনারেটর ক্লাস (পিডিএফ তৈরির জন্য আমার নিজস্ব ক্লাস) রাইটিং পদ্ধতি থেকে আউটপুট প্রবাহটি নিয়ে যায় এবং নতুন তৈরি হওয়া আউটপুট স্ট্রিমের পরিবর্তে সেইটিতে লেখায়।

এটি করার সর্বোত্তম উপায় কিনা তা জানেন না তবে এটি কার্যকর।


33
কোনও Responseবস্তুর সত্তা হিসাবে স্ট্রিমিংআউটপুট ফেরত পাওয়াও সম্ভব । আপনি মিডিয়াটাইপ, এইচটিটিপি রেসপন্স কোড ইত্যাদি সহজেই নিয়ন্ত্রণ করতে পারেন আপনি আমাকে কোড পোস্ট করতে চান কিনা তা আমাকে জানান।
হাঙ্ক


3
আমি এই থ্রেডের কোড উদাহরণগুলি রেফারেন্স হিসাবে ব্যবহার করেছি এবং খুঁজে পেয়েছি যে ক্লায়েন্টের জন্য আউটপুট নির্ভরযোগ্যভাবে গ্রহণ করার জন্য আমাকে স্ট্রিমিংআউটপুট.রাইটে () আউটপুট স্ট্রিমটি ফ্লাশ করা দরকার। অন্যথায় আমি মাঝে মাঝে শিরোনামগুলিতে "সামগ্রী-দৈর্ঘ্য: 0" পাইতাম এবং কোনও দেহই থাকত না, যদিও লগগুলি আমাকে বলেছিল যে স্ট্রিমিংআউটপুট সম্পাদন করছে।
জন স্টুয়ার্ট

@ জোনস্টেওয়ার্ট - আমি বিশ্বাস করি আমি জেনারেট পিডিএফ পদ্ধতিতে ফ্লাশ করছি।
মাইক TheReader

1
@ Dante617। আপনি কী ক্লায়েন্টের সাইড কোড পোস্ট করবেন কীভাবে জার্সি ক্লায়েন্ট বাইনারি স্ট্রিমটি সার্ভারে পাঠায় (জার্সি ২.x সহ)?
ডাবোরা

29

আমাকে আরটিএফ ফাইলটি ফিরতে হয়েছিল এবং এটি আমার পক্ষে কাজ করেছিল।

// 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

এখানে আরও একটি উদাহরণ। আমি একটি মাধ্যমে পিএনজি হিসাবে কিউআরকোড তৈরি করছি ByteArrayOutputStream। সংস্থানটি কোনও Responseবস্তু ফেরত দেয় এবং স্ট্রিমের ডেটা সত্তা entity

প্রতিক্রিয়া কোড হ্যান্ডলিং চিত্রিত করার জন্য, আমি ক্যাশে হেডার (এর হ্যান্ডলিং জুড়েছেন 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 পিএনজি ফাইলের জন্য কাজ করে ...


6
আমি মনে করি এটির একটি খারাপ স্ট্রিমিং উদাহরণ, কারণ আউটপুটে প্রত্যাবর্তিত অবজেক্টটি বাইট অ্যারে এবং স্ট্রিম নয়।
অ্যালিকেলজিন-কিলাকা

জিইটি সংস্থান অনুরোধের প্রতিক্রিয়া তৈরির জন্য ভাল উদাহরণ, স্ট্রিমের জন্য ভাল উদাহরণ নয়। এটি মোটেই স্রোত নয়।
রবার্ট ক্রিশ্চান

14

আমি আমার জার্সি ১.১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

এই উদাহরণটি দেখায় যে কীভাবে বিশ্রামের উত্সের মাধ্যমে JBoss এ লগ ফাইলগুলি প্রকাশ করা যায়। নোট করুন লগ ফাইলের সামগ্রীটি স্ট্রিমিংআউটপুট ইন্টারফেস ব্যবহার করে পান পদ্ধতিটি।

@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
কেবলমাত্র এফওয়াইআই: পাইপ পদ্ধতির পরিবর্তে আপনি আপাচি কমন্স আই / ও থেকে আইওউটিসকপি ব্যবহার করতে পারেন।
ডেভিড

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

@ জিইটি-র পরিবর্তে @ পোষ্ট দিয়ে কী করা সম্ভব?
SPR

@ এসপিআর আমি হ্যাঁ মনে করি, এটি সম্ভব। যখন সার্ভার পৃষ্ঠাটি প্রতিক্রিয়া জানায়, এটি ডাউনলোড উইন্ডোটি সরবরাহ করতে হবে
কমলাগিরাফা

5

আমি নিম্নলিখিতটি আমার কাছে সহায়ক বলে মনে করেছি এবং এটি আপনাকে বা অন্য কাউকে সহায়তা করে যদি আমি তা ভাগ করে নিতে চাই। আমি মিডিয়াটাইপ.পিডিএফ_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

আমার ক্ষেত্রে আমি একটি পিডিএফ ডকুমেন্ট অন্য সাইটে পোস্ট করছিলাম:

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

তারপরে পি পোস্ট করার দ্বিতীয় পরামিতি হিসাবে পাস হয় ()।

এই লিঙ্কটি এই কোড স্নিপেট একসাথে রাখার জন্য আমার পক্ষে সহায়ক ছিল: http://jersey.576304.n2.nabble.com/ মাল্টিরপার্ট- পোস্ট-td4252846.html


4

এটি আমার সাথে ইউআরএল: http://example.com/rest/muqsith/get-file?filePath=C : \ ব্যবহারকারীগণ \ I066807 \ ডেস্কটপ \ 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

আর একটি নমুনা কোড যেখানে আপনি আরআরএস সার্ভিসে কোনও ফাইল আপলোড করতে পারবেন, আরআরএসটি পরিষেবা জিপ ফাইলটি, এবং ক্লায়েন্ট সার্ভার থেকে জিপ ফাইলটি ডাউনলোড করে। জার্সি ব্যবহার করে বাইনারি ইনপুট এবং আউটপুট স্ট্রিমগুলি ব্যবহার করার এটি একটি ভাল উদাহরণ।

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

এই উত্তরটি আমার অন্য থ্রেডে পোস্ট করা হয়েছিল। আশাকরি এটা সাহায্য করবে.

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.