1

I was trying to generate 2 PDF data and put it inside a ZIP file for download (through response.getOutputStream) but I don't have idea how to do it properly:

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
}

This function returns ByteArrayOutputStream to be used later:

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;
    }
}
Amedee Van Gasse
  • 7,280
  • 5
  • 55
  • 101
jestrange
  • 271
  • 3
  • 15
  • 1
    You probably also want to edit your question to remove your iText tags and iText code because your question is about zip only and it doesn’t really matter what you pass to it. – sorifiend May 29 '17 at 04:24
  • Possible duplicate of [compress file with Java ByteArrayOutputstream](https://stackoverflow.com/questions/26482779/compress-file-with-java-bytearrayoutputstream) – sorifiend May 29 '17 at 04:26
  • Agreed, change your title and tags to attract more viewers who may be able to help. – Amedee Van Gasse May 29 '17 at 05:55
  • @Sorifiend The answer I seek is quite different from the one in the link. I answered my own question anyway. – jestrange May 29 '17 at 11:01

1 Answers1

3

I made it like this:

Declared the Filenames to be used later.

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

Declare a new ByteArrawOutputStream class and initialize with "new".

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

After generating a PDF file, return the value ByteArrayOutputStream and assign to the ByteArrayStream declared earlier.

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

Declare an outputstream to be used to hold response object's OutputStream.

                OutputStream responseOutputStream;

Declare the header strings to be assigned to the response object's header data. In this case the MIME type would be application/zip for zip file. The fileName (B2B_Price_List.zip) is also used to define the download's filename.

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

Set the response object's headers.

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

Set the responseOutputStream to hold the response object's outputstream.

                    responseOutputStream = response.getOutputStream();

Declare a ZipOutputStream and initialize new with the response's outputstream as a parameter. The parameter will be used to write to write here the file to be downloaded later, in this case, the ZIP file.

                    ZipOutputStream zos = new ZipOutputStream(responseOutputStream);

Declare the ZipEntry objects to be put inside the ZIP file. Initialize new with the filename string as a parameter. In this case, we'll put 2 files inside the ZIP file for example.

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

Put each entries (or files) one at a time, after the putNextEntry is called for an entry, it is then assumed that the next .write called will be written to the previously put entry.

In this case we called the .write with the ByteArrayOutputStream.toByteArray() to convert to ByteArray as a parameter. Don't forget to close the entry by calling .closeEntry(), then proceed to the next file(s) with the same procedure earlier.

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

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

After writing the entries (files) you needed inside the ZIP, don't forget to close the ZipOutputStream (zos in this case).

                    zos.close();

The file will then proceed for download after you flush / close the response's output stream. You may ignore flush but to be sure, I included it anyway.

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

END OF CODE BLOCK


CSVHandler.generatePriceListPDF

Now this is the function used to generate PDF > to > ByteArrayOutputStream. We passed the output object ByteArrayOutputStream from earlier to be re-assigned to the passed ByteArrayOutputStream object outside this function.

example:

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

FUNCTION BLOCK START

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 {

Initialize writer as new PdfWriter with the ByteArrayOutputStream as a parameter, in this case the output object from the function parameter.

            PdfWriter writer = new PdfWriter(output);

Initialize pdfDoc as new PdfDocument with the PdfWriter object writer in this case as parameter. This instructs the pdfDoc to write directly to the ByteArrayOutputStream (output) object

            pdfDoc = new PdfDocument(writer);    

Initialize PDF document parameters such as sizes and such.

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

This is the part where you write your PDF, with data, images or anything up to you.

            // YOUR OWN PDF WRITE OPERATION HERE

Don't forget to close your PDF Document after you finish writing stuff.

            doc.close();

The function parameter autoCloseByteArrayOutputStream boolean I added determines if you want to close the ByteArrayOutputStream inside this function, or close it outside if you want to supplement the content outside. Your choice, but don't forget to close ByteArrayOutputStream all the time anyway.

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

Return the output ByteArrayOutputStream.

            return output;
        } catch (IOException e) {

If an exception occur, it's important to return an object on all code paths. In this case we return a null value ByteArrayOutputStream in an event of error.

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

Same here, errors return null ByteArrayOutputStream in case of error.

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

END OF FUNCTION BLOCK

jestrange
  • 271
  • 3
  • 15