kizawa tomaru
kizawa tomaru

Reputation: 145

generate zip file grouping multiple pdf, using servlet and itext 7

I'm trying to put multiple generated pdf into a zip from servlet using itext7, I've managed to put one pdf in a zip file but not more. Here is the code:

private void printMore(HttpServletRequest req, HttpServletResponse resp) throws SQLException {
        String masterPath = req.getServletContext().getRealPath("/assets/template/templateStatement.pdf");
        try (PdfReader reader = new PdfReader(masterPath);
             ZipOutputStream zipFile = new ZipOutputStream(resp.getOutputStream());
             PdfWriter writer = new PdfWriter(zipFile);
             PdfDocument pdf = new PdfDocument(reader, writer);
             Document doc = new Document(pdf)) {

            List<Student> studentList = getFactoryDAO().getStatementDAO().selectStudentHasBalance();
            for (Student student : studentList){

                // Generate PDF for the student

                PdfPage page = pdf.getPage(1);
                PdfCanvas canvas = new PdfCanvas(page);

                FontProgram fontProgram = FontProgramFactory.createFont();
                PdfFont font = PdfFontFactory.createFont(fontProgram, "utf-8", true);
                canvas.setFontAndSize(font, 10);

                canvas.beginText();

                canvas.setTextMatrix(178, 650); // student code
                canvas.showText(student.getS_Code());

                canvas.setTextMatrix(200, 610); // Date of Statement
                canvas.showText(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));

                canvas.endText();

                float[] pointsWidth = {60f,120f,70f,70f};
                Table table = new Table(pointsWidth);
                table.setMarginTop(280);
                table.setMarginLeft(70);
                table.setFont(font);
                table.setFontSize(10);
                table.setTextAlignment(TextAlignment.CENTER);
                //Header Table
                table.addCell(new Cell().add("Date Inscription"));
                table.addCell(new Cell().add("Name"));
                table.addCell(new Cell().add("Fees"));
                table.addCell(new Cell().add("Observation"));
                //Detail Table
                table.addCell(new Cell().add(student.getTxnDate()));
                table.addCell(new Cell().add(student.getS_FullName));
                table.addCell(new Cell().add(student.getFees));
                table.addCell(new Cell().add(student.getObservation));
                

                doc.add(table);


                ZipEntry zipEntry = new ZipEntry(student.getS_Code() + "_" + student.getS_LName() + ".pdf");
                zipFile.putNextEntry(zipEntry);
                //zipFile.write(); Shall I use it?

            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        resp.setHeader("Content-disposition","attachement; filename=test.zip");
        resp.setContentType("application/zip");
    }

I've based on this this post and this post but doesn't work. I already check more post like this but the version of itext7 has no PdfWriter.getInstance as mentionned. I've tried more thing but can't managed to go furthermore.

UPDATED :

After Enterman suggestion i updated it like this :

String masterPath = req.getServletContext().getRealPath("/assets/template/templateStatement.pdf");
        try (PdfReader reader = new PdfReader(masterPath);
             ZipOutputStream zipFile = new ZipOutputStream(resp.getOutputStream());
             PdfWriter writer = new PdfWriter(zipFile);
             PdfDocument pdf = new PdfDocument(reader, writer)
             ) {

            List<Student> studentList = getFactoryDAO().getStatementDAO().selectStudentHasBalance();
            for (Student student : studentList){

                try (Document doc = new Document(pdf)){
                       // Generate PDF for the student

                PdfPage page = pdf.getPage(1);
                PdfCanvas canvas = new PdfCanvas(page);

                FontProgram fontProgram = FontProgramFactory.createFont();
                PdfFont font = PdfFontFactory.createFont(fontProgram, "utf-8", true);
                canvas.setFontAndSize(font, 10);

                canvas.beginText();

                canvas.setTextMatrix(178, 650); // student code
                canvas.showText(student.getS_Code());

                canvas.setTextMatrix(200, 610); // Date of Statement
                canvas.showText(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));

                canvas.endText();

                float[] pointsWidth = {60f,120f,70f,70f};
                Table table = new Table(pointsWidth);
                table.setMarginTop(280);
                table.setMarginLeft(70);
                table.setFont(font);
                table.setFontSize(10);
                table.setTextAlignment(TextAlignment.CENTER);
                //Header Table
                table.addCell(new Cell().add("Date Inscription"));
                table.addCell(new Cell().add("Name"));
                table.addCell(new Cell().add("Fees"));
                table.addCell(new Cell().add("Observation"));
                //Detail Table
                table.addCell(new Cell().add(student.getTxnDate()));
                table.addCell(new Cell().add(student.getS_FullName));
                table.addCell(new Cell().add(student.getFees));
                table.addCell(new Cell().add(student.getObservation));
                

                doc.add(table);


                ZipEntry zipEntry = new ZipEntry(student.getS_Code() + "_" + student.getS_LName() + ".pdf");
                zipFile.putNextEntry(zipEntry);
                //zipFile.write(); Shall I use it?
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        resp.setHeader("Content-disposition","attachement; filename=test.zip");
        resp.setContentType("application/zip");

But still no luck.

Your help is welcome.

Upvotes: 2

Views: 526

Answers (3)

Cristian Yamamoto
Cristian Yamamoto

Reputation: 16

To anyone who is wondering if the solution works using OpenPDF instead of itext, what kizawa brought can be adapted and it works.

The code I wrote, looks like this:

    public boolean generateMultiple(HttpServletResponse response, User user, List<Chat> closedChats) throws IOException {

        try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {

            Account account = user.getAccount();
            List<File> listFile = new ArrayList<>();

            for (Chat chat : closedChats){

                String endDate = DateTimeFormatter.ofPattern("yyyy-MM-dd").format(chat.getEndDate());

                File file = new File("transcript_" +
                        account.getName().replaceAll(" ", "_") +
                        "_" + endDate + "_" +
                        chat.getVisitor().getName().replaceAll(" ", "_") + ".pdf");

                Document document = new Document(PageSize.A4);
                PdfWriter.getInstance(document, new FileOutputStream(file));

                document.open();

                Paragraph title =  new Paragraph(account.getName() + " - " + "Chat Transcript", new Font(Font.HELVETICA, 20, Font.BOLD));
                title.setAlignment(Paragraph.ALIGN_CENTER);
                title.setSpacingAfter(10);

                PdfPTable header = getHeader(chat);

                document.add(title);
                document.add(header);
                addMessages(chat, document);

                document.addTitle(file.getName());
                document.close();
                listFile.add(file);

            }

            File zipFile = createZip(listFile, account);

            ZipEntry zipEntry = new ZipEntry(zipFile.getName());
            zipOut.putNextEntry(zipEntry);
            FileInputStream fis = new FileInputStream(zipFile);
            byte[] bytes = new byte[1024];
            int length;
            while((length = fis.read(bytes)) >= 0) {
                zipOut.write(bytes, 0, length);
            }
            fis.close();

            response.setHeader("Content-disposition","attachement; filename=" + zipFile);
            response.setContentType("application/zip");
            if(!zipFile.delete()){
                logger.info("generateMultiple() | file {} was not deleted", zipFile.getName());
            }

        } catch (IOException e) {
            logger.error("Invalid Input", e);
        }

        return true;
    }

While using the same but slightly adapted createZip() from BenjaminD:

    private File createZip(List<File> forZip, Account account) {

        String zipName = account.getName().replaceAll(" ", "_") + "_transcript" + ".zip";

        FileOutputStream fos;
        try {
            fos = new FileOutputStream(zipName);
            ZipOutputStream zipOut = new ZipOutputStream(fos);
            for (File srcFile : forZip) {
                FileInputStream fis = new FileInputStream(srcFile);
                ZipEntry zipEntry = new ZipEntry(srcFile.getName());
                zipOut.putNextEntry(zipEntry);

                byte[] bytes = new byte[1024];
                int length;
                while((length = fis.read(bytes)) >= 0) {
                    zipOut.write(bytes, 0, length);
                }
                fis.close();
                if(!srcFile.delete()){
                    logger.info("createZip() | file {} was not deleted", srcFile.getName());
                }
            }
            zipOut.closeEntry();
            zipOut.close();
            fos.close();
        } catch (IOException e) {
            logger.error("createZip()", e);
        }

        return new File(zipName);
    }

Upvotes: 0

kizawa tomaru
kizawa tomaru

Reputation: 145

Special thanks for BenjaminD, Enterman for their support and all stack community.

I post this answer for those who has faced the same problem as me. (I've been stuck for 4 days). "Generating multiple PDF with itext 7 and servlets"

As Enterman said : "need new Instance of Document". In addition need PdfDocument also. And as BenjaminD instruction : "Generate a file PDF first, after put them into a zip".

String masterPath = req.getServletContext().getRealPath("/assets/template/templateStatement.pdf");
        try (ZipOutputStream zipOut = new ZipOutputStream(resp.getOutputStream())) {

            Liste<File> listFile = new ArrayList<>();
            List<Student> studentList = getFactoryDAO().getStatementDAO().selectStudentHasBalance();
            for (Student student : studentList){
                
                File file = new File(student.getS_Code()+"_"+new SimpleDateFormat("yyyy-MM-dd").format(new Date())+".pdf");
                try (PdfDocument pdf = new PdfDocument(new PdfReader(masterPath), new PdfWriter(file.getName()))
                     Document doc = new Document(pdf)){
                       // Generate PDF for the student

                PdfPage page = pdf.getPage(1);
                PdfCanvas canvas = new PdfCanvas(page);

                FontProgram fontProgram = FontProgramFactory.createFont();
                PdfFont font = PdfFontFactory.createFont(fontProgram, "utf-8", true);
                canvas.setFontAndSize(font, 10);

                canvas.beginText();

                canvas.setTextMatrix(178, 650); // student code
                canvas.showText(student.getS_Code());

                canvas.setTextMatrix(200, 610); // Date of Statement
                canvas.showText(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));

                canvas.endText();

                float[] pointsWidth = {60f,120f,70f,70f};
                Table table = new Table(pointsWidth);
                table.setMarginTop(280);
                table.setMarginLeft(70);
                table.setFont(font);
                table.setFontSize(10);
                table.setTextAlignment(TextAlignment.CENTER);
                //Header Table
                table.addCell(new Cell().add("Date Inscription"));
                table.addCell(new Cell().add("Name"));
                table.addCell(new Cell().add("Fees"));
                table.addCell(new Cell().add("Observation"));
                //Detail Table
                table.addCell(new Cell().add(student.getTxnDate()));
                table.addCell(new Cell().add(student.getS_FullName));
                table.addCell(new Cell().add(student.getFees));
                table.addCell(new Cell().add(student.getObservation));
                

                doc.add(table);


                listFile.add(file);
                }

            }
            
            File zipFile = createZip(listFile, 
            newSimpleDateFormat("yyyy-MM-dd").format(new Date())); //BenjaminD source in answer

            ZipEntry zipEntry = new ZipEntry(zipFile.getName);
            zipEntry.putNextEntry(zipEntry);
            fileInputStream fis = new FileInputStream(zipFile);
            byte[] bytes = new byte[1024];
            int length;
            while((length = fis.read(bytes)) >= 0) {
                zipOut.write(bytes, 0, length);
            }
            fis.close();

            resp.setHeader("Content-disposition","attachement; filename=" + zipFile);
            resp.setContentType("application/zip");

        } catch (IOException e) {
            e.printStackTrace();
        }     

It will put the zip in a zip (can Directly use FileOutpuStream to not put it again in a zip).

Thank you again.

Upvotes: 1

BenjaminD
BenjaminD

Reputation: 554

You should try using a FileInputStream, like below (code of my own, working well in production)

private File createZip(List<File> forZip, LocalDate date) {

    String zipName = Constants.ORDER_FILE_PATH + date.getYear() +"-" + date.getMonth().getValue() + "-" + date.getMonth().getDisplayName(TextStyle.FULL, Locale.FRENCH) + ".zip";

    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(zipName);
        ZipOutputStream zipOut = new ZipOutputStream(fos);
        for (File srcFile : forZip) {
            FileInputStream fis = new FileInputStream(srcFile);
            ZipEntry zipEntry = new ZipEntry(srcFile.getName());
            zipOut.putNextEntry(zipEntry);

            byte[] bytes = new byte[1024];
            int length;
            while((length = fis.read(bytes)) >= 0) {
                zipOut.write(bytes, 0, length);
            }
            fis.close();
            //srcFile.delete();
        }
        zipOut.close();
        fos.close();
    } catch (IOException e) {
        logger.error("createZip", e);
    }

    return new File(zipName);
}

Upvotes: 1

Related Questions