【问题标题】:How can I put 2 ByteArrayOutputStreams into a zip file for download?如何将 2 ByteArrayOutputStream 放入 zip 文件以供下载?
【发布时间】:2017-05-29 04:17:07
【问题描述】:

我试图生成 2 个 PDF 数据并将其放入 ZIP 文件中以供下载(通过 response.getOutputStream),但我不知道如何正确执行:

public void export() {
    String fileName = "B2B_Price_List.zip";
    String fileNameUSD = "B2B_Price_List_USD.pdf";
    String fileNameEU = "B2B_Price_List_EU.pdf";

    String contentTypePDF = "application/pdf";
    String[] headerPDF = new String[2];
    headerPDF[0] = "Content-disposition";
    headerPDF[1] = "attachment; filename=\"" +  fileNameUSD + "\"";
    headerPDF[2] = "attachment; filename=\"" +  fileNameEU + "\"";

    String contentTypeZIP = "application/zip";
    String[] headerZIP = new String[1];
    headerZIP[0] = "Content-disposition";
    headerZIP[1] = "attachment; filename=\"" +  fileName + "\"";

    ByteArrayOutputStream outUSD = new ByteArrayOutputStream();
    outUSD = CSVHandler.downloadPriceListPDF(outUSD, fileNameUSD, ListToPDFMap(productsUSD), true);

    ByteArrayOutputStream outEU = new ByteArrayOutputStream();
    outEU = CSVHandler.downloadPriceListPDF(outEU, fileNameEU, ListToPDFMap(productsEU), false);
    // ZIP CODING GOES HERE
}

此函数返回 ByteArrayOutputStream 供以后使用:

public static ByteArrayOutputStream downloadPriceListPDF
    (ByteArrayOutputStream output, final String filename,
     Map<String, Map<String, List<B2BProductData>>> datas,
     boolean amerCustomer) {
    try {
        PdfDocument pdfDoc = null;
        try {
            pdfDoc = new PdfDocument(new PdfWriter(output));    

            PageSize pageSize = new PageSize(PageSize.A4);
            Document doc = new Document(pdfDoc, pageSize, false);
            PdfCanvas canvas = new PdfCanvas(pdfDoc.addNewPage());

            String coverImage = COVER_IMAGE;
            if(!amerCustomer) {
                coverImage = COVER_IMAGE_1;
            }

            canvas.addImage(ImageDataFactory.create(CSVHandler.class.getClassLoader().getResource(coverImage).getPath()), pageSize, false);

            // loop thru category
            int pageNo = 2;
            Map<String, List<B2BProductData>> inputDatas = new LinkedHashMap<>();
            for(String category : datas.keySet()) {
                Map<String, List<B2BProductData>> prods = datas.get(category);

                while(true) {
                    inputDatas = new LinkedHashMap<>();                 
                    Map<String, List<B2BProductData>> remaindatas = filterDatas(inputDatas, prods);

                    if(inputDatas.size() > 0) {
                        createPDFPage(pdfDoc, doc, category, inputDatas, pageNo ++, amerCustomer);
                    }

                    if(remaindatas.size() > 0) {
                        prods =  remaindatas;
                    } else {
                        break;
                    }
                }
            }           

            doc.close();

            return output;
        } catch (IOException e) {
            LOG.error(e.getMessage());
            return output;
        }
    }
    catch (final Exception ex) {
        LOG.error("Export Products got error: " + ex.getMessage());
        return output;
    }
}

【问题讨论】:

  • 您可能还想编辑您的问题以删除您的 iText 标签和 iText 代码,因为您的问题仅与 zip 有关,传递给它的内容并不重要。
  • 同意,更改您的标题和标签以吸引更多可能提供帮助的观众。
  • @Sorfiend 我寻求的答案与链接中的答案完全不同。我还是回答了我自己的问题。

标签: java zip bytearrayoutputstream


【解决方案1】:

我是这样设计的:

声明了稍后使用的文件名。

                String fileName = "B2B_Price_List.zip";
                String fileNameUSD = "B2B_Price_List_USD.pdf";
                String fileNameEU = "B2B_Price_List_EU.pdf";

声明一个新的 ByteArrawOutputStream 类并使用“new”进行初始化。

                ByteArrayOutputStream outUSD = new ByteArrayOutputStream();
                ByteArrayOutputStream outEU = new ByteArrayOutputStream();

生成PDF文件后,返回值ByteArrayOutputStream,赋值给前面声明的ByteArrayStream。

                if (hasUSD) outUSD = CSVHandler.generatePriceListPDF(outUSD, ListToPDFMap(productsUSD), true, true);
                if (hasEU) outEU = CSVHandler.generatePriceListPDF(outEU, ListToPDFMap(productsEU), false, true);

声明一个输出流用于保存响应对象的输出流。

                OutputStream responseOutputStream;

声明要分配给响应对象的标题数据的标题字符串。在这种情况下,对于 zip 文件,MIME 类型将是 application/zipfileName (B2B_Price_List.zip) 也用于定义下载的文件名。

                    String contentTypeZIP = "application/zip";
                    String[] headerZIP = new String[1];
                    headerZIP[0] = "Content-disposition";
                    headerZIP[1] = "attachment; filename=\"" +  fileName + "\"";

设置响应对象的标题。

                    response.setContentType(contentTypeZIP);
                    response.setHeader(headerZIP[0], headerZIP[1]);

将 responseOutputStream 设置为保存 response 对象的输出流。

                    responseOutputStream = response.getOutputStream();

声明一个 ZipOutputStream 并使用响应的输出流作为参数初始化 new。参数将用于写入此处写入稍后要下载的文件,在本例中为ZIP文件。

                    ZipOutputStream zos = new ZipOutputStream(responseOutputStream);

声明要放入 ZIP 文件中的 ZipEntry 对象。使用文件名字符串作为参数初始化 new。在这种情况下,例如,我们会将 2 个文件放入 ZIP 文件中。

                    ZipEntry zipEntryUSD = new ZipEntry(fileNameUSD);
                    ZipEntry zipEntryEU = new ZipEntry(fileNameEU);

一次放置一个条目(或文件),在为条目调用 putNextEntry 之后,假设下一个调用的 .write 将是写入之前的 put 条目。

在这种情况下,我们使用 ByteArrayOutputStream.toByteArray() 调用 .write 以转换为 ByteArray 作为参数。不要忘记通过调用 .closeEntry() 关闭条目,然后使用之前相同的过程继续到下一个文件。

                    zos.putNextEntry(zipEntryUSD);
                    zos.write(outUSD.toByteArray());
                    zos.closeEntry();

                    zos.putNextEntry(zipEntryEU);
                    zos.write(outEU.toByteArray());
                    zos.closeEntry();

在 ZIP 中写入您需要的条目(文件)后,不要忘记关闭 ZipOutputStream(在本例中为 zos)。

                    zos.close();

在您刷新 / 关闭 响应的输出流后,该文件将继续下载。您可以忽略 flush,但可以肯定的是,我还是将其包含在内。

                    responseOutputStream.flush();
                    responseOutputStream.close();

代码块结束


CSVHandler.generatePriceListPDF

现在这是用于生成 PDF 到 > ByteArrayOutputStream 的函数。我们从前面传递了 output 对象 ByteArrayOutputStream 以在此函数之外重新分配给传递的 ByteArrayOutputStream 对象。

示例:

outUSD = CSVHandler.generatePriceListPDF(outUSD, ListToPDFMap(productsUSD), true, true);

功能块开始

public static ByteArrayOutputStream downloadPriceListPDF
    (ByteArrayOutputStream output, final String filename,
     Map<String, Map<String, List<B2BProductData>>> datas,
     boolean amerCustomer, boolean autoCloseByteArrayOutputStream) {
    try {
        PdfDocument pdfDoc = null;
        try {

使用 ByteArrayOutputStream 作为参数将 writer 初始化为新的 PdfWriter,在本例中是函数参数中的 output 对象。

            PdfWriter writer = new PdfWriter(output);

pdfDoc 初始化为新的 PdfDocument,在这种情况下使用 PdfWriter 对象 writer 作为参数。这指示 pdfDoc 直接写入 ByteArrayOutputStream (output) 对象

            pdfDoc = new PdfDocument(writer);    

初始化PDF文档的大小等参数。

            PageSize pageSize = new PageSize(PageSize.A4);
            Document doc = new Document(pdfDoc, pageSize, false);
            PdfCanvas canvas = new PdfCanvas(pdfDoc.addNewPage());

这是您编写 PDF 的部分,包含数据、图像或任何内容。

            // YOUR OWN PDF WRITE OPERATION HERE

写完后别忘了关闭 PDF 文档。

            doc.close();

我添加的函数参数autoCloseByteArrayOutputStream boolean决定了是要在这个函数内部关闭ByteArrayOutputStream,还是要在外面补充内容就关闭。您的选择,但不要忘记始终关闭 ByteArrayOutputStream

        If (autoCloseByteArrayOutputStream) {
            output.flush();
            output.close();
        }

返回输出 ByteArrayOutputStream

            return output;
        } catch (IOException e) {

如果发生异常,请务必在所有代码路径上返回一个对象。在这种情况下,如果发生错误,我们会返回一个 nullByteArrayOutputStream

            LOG.error(e.getMessage());
            return output;
        }
    }
    catch (final Exception ex) {

同样,错误返回 null ByteArrayOutputStream 以防出错。

        LOG.error("Export Products got error: " + ex.getMessage());
        return output;
    }
}

功能块结束

【讨论】:

  • 请在您的回答中添加一些解释
  • 为您服务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-21
  • 1970-01-01
  • 2013-10-27
  • 2015-01-19
  • 1970-01-01
  • 1970-01-01
  • 2011-01-18
相关资源
最近更新 更多