使用IText导出复杂pdf

1、问题描述 

        需要将发票导出成pdf,要求每页都必须包含发票信息和表头行。

使用IText导出复杂pdf_第1张图片

 

 

2、解决方法

        使用IText工具实现PDF导出

        IText8文档:Examples (itextpdf.com)

 

3、我的代码

      使用IText导出复杂pdf_第2张图片

 使用IText导出复杂pdf_第3张图片

 

        引入Itext依赖,我这里用的是8.0.1版本

 
            com.itextpdf
            itext7-core
            8.0.1
            pom
        
MyItextpdfUtils.java
package com.easyexcel.util;


import com.easyexcel.handler.PaginationEventHandler;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.properties.AreaBreakType;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * @author Wulc
 * @date 2023/8/10 17:08
 * @description
 */
@Component
public class MyItextpdfUtils {

    public void createPDF() throws java.io.IOException {
        Resource resource = new ClassPathResource("/");
        String path = resource.getFile().getPath();
        //设置中文字体 C:\Windows\Fonts
        //PdfFont chineseFont =getFont();
        //PdfFont chineseFont = PdfFontFactory.createFont(this.getClass().getClassLoader().getResource("simsun.ttf").getPath());
        PdfFont chineseFontForTemplate = PdfFontFactory.createFont("D:\\学习资料\\后端\\STSONG.TTF");
        PdfFont chineseFontForContent = PdfFontFactory.createFont("D:\\学习资料\\后端\\STSONG.TTF");
        //创建每页的共有模板
        //*********************每页的共有模板*********************************
        String templatePath = path + "\\template.pdf";
        PdfDocument pdfDocumentTemplate = new PdfDocument(new PdfWriter(templatePath));
        //Document documentTemplate = new Document(pdfDocumentTemplate, PageSize.A4).setFont(chineseFontForTemplate);
        Document documentTemplate = new Document(pdfDocumentTemplate, PageSize.A4);
        //插入logo图片
        Table logoTemplateTable = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth().setBorder(Border.NO_BORDER);
        ImageData imageData = ImageDataFactory.create(this.getClass().getClassLoader().getResource("logo.png"));
        Image image = new Image(imageData);
        image.setHeight(50);
        image.setWidth(100);
        logoTemplateTable.addCell(new Cell().setBorder(Border.NO_BORDER).add(image));
        //插入logo图片下方的一些信息
        Table logoInfoTable = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth().setBorder(Border.NO_BORDER);
        logoInfoTable.addCell(new Cell().setBorder(Border.NO_BORDER).setPadding(1).setFontSize(10).add(new Paragraph("Description1")));
        logoInfoTable.addCell(new Cell().setBorder(Border.NO_BORDER).setPadding(1).setFontSize(10).add(new Paragraph("Description2")));
        logoInfoTable.addCell(new Cell().setBorder(Border.NO_BORDER).setPadding(1).setFontSize(10).add(new Paragraph("Description3")));
        //插入标题
        Table titleTable = new Table(UnitValue.createPercentArray(4)).useAllAvailableWidth().setBorder(Border.NO_BORDER);
        titleTable.addCell(new Cell(1, 4).setBorder(Border.NO_BORDER).setPadding(1).setFontSize(15).add(new Paragraph("TITLE")).setTextAlignment(TextAlignment.CENTER));
        //插入标题下的一些信息
        Table titleInfoTable = new Table(UnitValue.createPercentArray(4)).useAllAvailableWidth();
        titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("QuestionA")));
        titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("AnswerA")));
        titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("QuestionB")));
        titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("AnswerB")));
        titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("QuestionC")));
        titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("AnswerC")));
        titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("QuestionD")));
        titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("AnswerD")));
        titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("QuestionE")));
        titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("AnswerE")));
        titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("QuestionF")));
        titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("AnswerF")));

        documentTemplate.add(logoTemplateTable);
        documentTemplate.add(logoInfoTable);
        documentTemplate.add(titleTable);
        documentTemplate.add(titleInfoTable);
        //*********************每页的共有模板*********************************


        //*********************每页的内容************************************
        String contentPath = path + "\\content.pdf";
        PdfDocument pdfDocumentContent = new PdfDocument(new PdfWriter(contentPath));
        //把内容使用共有模板
        pdfDocumentContent.addEventHandler(PdfDocumentEvent.END_PAGE, new PaginationEventHandler(pdfDocumentTemplate.getFirstPage().copyAsFormXObject(pdfDocumentContent)));
        Document documentContent = new Document(pdfDocumentContent, PageSize.A4).setFont(chineseFontForContent);
        //每页的content距离上面的template的距离
        documentContent.setTopMargin(250);
        Table contentTable = new Table(UnitValue.createPercentArray(6)).useAllAvailableWidth();
        //插入清单表格标题
        contentTable.addHeaderCell(new Cell().setFontSize(8).add(new Paragraph("No")));
        contentTable.addHeaderCell(new Cell().setFontSize(8).add(new Paragraph("title1")));
        contentTable.addHeaderCell(new Cell().setFontSize(8).add(new Paragraph("title2")));
        contentTable.addHeaderCell(new Cell().setFontSize(8).add(new Paragraph("title3")));
        contentTable.addHeaderCell(new Cell().setFontSize(8).add(new Paragraph("title4")));
        contentTable.addHeaderCell(new Cell().setFontSize(8).add(new Paragraph("title5")));
        for (int i = 0; i < 300; i++) {
            contentTable.addCell(new Cell().setFontSize(8).add(new Paragraph(String.valueOf(i))));
            contentTable.addCell(new Cell().setFontSize(8).add(new Paragraph("content1")));
            contentTable.addCell(new Cell().setFontSize(8).add(new Paragraph("content2")));
            contentTable.addCell(new Cell().setFontSize(8).add(new Paragraph("content3")));
            contentTable.addCell(new Cell().setFontSize(8).add(new Paragraph("content4")));
            contentTable.addCell(new Cell().setFontSize(8).add(new Paragraph("content5")));
        }
        //尾页
        Table lastInfoTable = new Table(UnitValue.createPercentArray(3)).setWidth(300);
        lastInfoTable.addCell(new Cell(1, 3).setPadding(1).setFontSize(8).add(new Paragraph("Total:")));
        lastInfoTable.addCell(new Cell(1, 1).setPadding(1).setFontSize(8).add(new Paragraph("统计A:")));
        lastInfoTable.addCell(new Cell(1, 2).setPadding(1).setFontSize(8).add(new Paragraph("1234567")));
        lastInfoTable.addCell(new Cell(1, 1).setPadding(1).setFontSize(8).add(new Paragraph("统计B:")));
        lastInfoTable.addCell(new Cell(1, 2).setPadding(1).setFontSize(8).add(new Paragraph("7654321")));
        //*********************每页的内容************************************

        documentContent.add(contentTable);
        //尾页新开一页
        documentContent.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
        documentContent.add(lastInfoTable);
        documentTemplate.close();
        documentContent.close();
    }


}

 

PDFTest.java​​​​​​​
package com.easyexcel;

import com.easyexcel.util.MyItextpdfUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;

/**
 * @author Wulc
 * @date 2023/8/10 17:52
 * @description
 */
@SpringBootTest(classes = SpringbootApplication.class)
@RunWith(SpringRunner.class)
public class PDFTest {
    @Autowired
    private MyItextpdfUtils myItextpdfUtils;

    @Test
    public void test6() throws IOException {
        myItextpdfUtils.createPDF();
    }
}

        测试一下:

使用IText导出复杂pdf_第4张图片

 

4、总结

        IText8不支持中文,需要引入外部字体文件,如果是以其中一个pdf作为每页的背景模板生成PDF这种方式(copyAsFormXObject),它只能支持其中一个pdf中文,另一个就不支持了。

Document documentTemplate = new Document(pdfDocumentTemplate, PageSize.A4).setFont(chineseFontForTemplate);
Document documentContent = new Document(pdfDocumentContent, PageSize.A4).setFont(chineseFontForContent);

如上代码,虽然我同时把背景版和内容同时都设置了中文字体,但是template和content合一块的时候,template的背景版pdf的中文字体就会失效了。

使用IText导出复杂pdf_第5张图片

         不过还好,因为是海外的发票都是英文的,因此不需要考虑支持中文的问题。

        希望哪位大佬能帮忙解决一下IText8 copyAsFormXObject中文兼容性问题!!!

5、参考资料

https://www.cnblogs.com/sky-chen/p/13026203.html#autoid-1-4-5-0-0-0
https://kb.itextpdf.com/home/it7kb/examples/repeating-parts-of-a-form
https://zhuanlan.zhihu.com/p/537723847
https://blog.csdn.net/weixin_43409994/article/details/118157694
https://blog.csdn.net/u012397189/article/details/126345744
https://blog.csdn.net/Thinkingcao/article/details/84988392

 

 

你可能感兴趣的:(工作,后端,pdf,java,ITextPDF)