Java利用Itext实现根据模板生成PDF

2,813 阅读3分钟

1、 概述

在日常开发中,不可避免要实现自动生成一些业务文件,给相关部门人员使用, 常见的操作是生成word文档,但是由于使用者装的word文档版本/类型极度不统一,因此就衍生出了直接生成pdf的需求,下面介绍的是Java中,如何利用IText来操作pdf,实现根据pdf模板文件生成pdf功能。

2、 环境依赖

  • Word (office,非wps)
  • Java
  • Adobe Acrobat Pro (文中使用的是2019版本)

3、 开发流程

3.1 利用word构建基础文档

首先,我们利用word,构建一个最简单的word文档,如图所示

image-20200816155512821

编辑好后,我们另存为pdf文件,如下图所示

image-20200816155726808

3.2 利用Adobe Acrobat Pro 生成pdf模板文件

在这此操作中,我们利用Adobe acrobat pro 打开 上一个步骤生成的pdf_template.pdf文件,如下图所示:

image-20200816160004705

然后,我们在上图中标注为1处,输入表单,然后在出现的选项中选择编辑,在弹出的页面点击开始。即可出现以下界面:

image-20200816160408960

我们可以看到,adobe工具已经自动帮我们检测了表单中,会出现变量的地方,并自动生成了两个变量对应到对应的位置,我们通过修改修改,把fill_2删除,并添加图片域到原fill_2位置中,即可完成模板的设置。如图

image-20200816160728785

随后。我们右键此文件即可。

在pdf中,不仅仅只有图片域、文本域,还有条形码域等, 但是归纳来说,其实都是文字 + 图片

3.3 Java代码开发

maven依赖

<!--        PDF依赖开始-->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.itextpdf/itext-pdfa -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-pdfa</artifactId>
            <version>5.5.13</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.itextpdf/itext-xtra -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-xtra</artifactId>
            <version>5.5.13</version>
        </dependency>

代码开发

public static String generatorPdf(GeneratorInfo generatorInfo, String inPath, String outFolder,String outFileName) {
    if (!Files.exists(Paths.get(inPath))){
        //  原始PDF文件不存在。
        throw new RuntimeException("Input pdf not exist!");
    }
    if(!Files.isDirectory(Paths.get(outFolder))) {
        // 输出文件夹设置不正确
        throw new RuntimeException("Out Folder is not exist!");
    }
    String outFilePath = outFolder + File.separator + outFileName;


    PdfReader reader;
    FileOutputStream out;
    ByteArrayOutputStream bos;
    PdfStamper stamper;
    try {
        // 输出流
        out = new FileOutputStream(outFilePath);
        // 读取pdf模板
        reader = new PdfReader(inPath);
        bos = new ByteArrayOutputStream();
        stamper = new PdfStamper(reader, bos);
        AcroFields form = stamper.getAcroFields();


        // 设置表单字体(字体文件一定要在classpath根目录下)
        form.addSubstitutionFont(BaseFont.createFont("/msyh.ttf",BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED));
        // 设置表单的值
        //遍历数据
        Map<String,Object> datemap = generatorInfo.getTextData();
        for(String key : datemap.keySet()){
            String value = datemap.get(key).toString();
            form.setField(key,value);
        }

        //图片类的内容处理
        Map<String,byte[]> imgmap = generatorInfo.getImageData();
        for(String key : imgmap.keySet()) {
            if(form.getField(key) == null){
                continue;
            }
            byte[] value = imgmap.get(key);
            if (value == null || value.length == 0) {
                continue;
            }
            Rectangle signRect = form.getFieldPositions(key).get(0).position;
            //根据路径读取图片
            Image image = Image.getInstance(value);
            image.scaleToFit(signRect.getWidth(), signRect.getHeight());
            PushbuttonField newPushbuttonFromField = form.getNewPushbuttonFromField(key);

            newPushbuttonFromField.setImage(image);
            PdfFormField editFormField = newPushbuttonFromField.getField();
            form.replacePushbuttonField(key, editFormField);
        }
        // 如果为false,生成的PDF文件可以编辑,如果为true,生成的PDF文件不可以编辑
        stamper.setFormFlattening(true);
        stamper.close();
        Document doc = new Document();
        PdfCopy copy = new PdfCopy(doc, out);
        doc.open();
        PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);
        copy.addPage(importPage);
        doc.close();
        return outFilePath;
    } catch (IOException | DocumentException e) {
        e.printStackTrace();
    }
    return null;
}
@Data
public static class GeneratorInfo {
    private Map<String,Object> textData = new HashMap<>();
    private Map<String,byte[]> imageData = new HashMap<>();

}

测试功能

public static void main(String[] args) throws FileNotFoundException {
            GeneratorInfo generatorInfo = new GeneratorInfo();
            Map<String,Object> textData = Collections.singletonMap("username","大魔王");
            Map<String,byte[]> imageData = new HashMap<>();

            // 读取图片文件内容
            byte[] bytes = IoUtil.readBytes(new FileInputStream(new File("c://WechatQr.jpg")));
            imageData.put("photo",bytes);

            generatorInfo.setTextData(textData);
            generatorInfo.setImageData(imageData);

            		generatorPdf(generatorInfo,"C:\\Users\\12728\\Desktop\\pdf_template.pdf","C:\\Users\\12728\\Desktop","final.pdf");



        }

最终生成的图片如下所示,可以看出,跟我们的需求是一致的。

image-20200816162357839

4、总结

Itext的功能非常强大,现在只是用到了最简单的功能,一般来说,只要能替换 文字、图片, 就可以解决我们实际生活中非常多的问题。

对于一些特定模板样式要求,我们可以通过编辑word,或者编辑生成好的pdf模板,来达到样式效果, 毕竟在实际中,我们只是替换对应位置的变量。

最后、求关注