1、 概述
在日常开发中,不可避免要实现自动生成一些业务文件,给相关部门人员使用, 常见的操作是生成word文档,但是由于使用者装的word文档版本/类型极度不统一,因此就衍生出了直接生成pdf的需求,下面介绍的是Java中,如何利用IText来操作pdf,实现根据pdf模板文件生成pdf功能。
2、 环境依赖
- Word (office,非wps)
- Java
- Adobe Acrobat Pro (文中使用的是2019版本)
3、 开发流程
3.1 利用word构建基础文档
首先,我们利用word,构建一个最简单的word文档,如图所示

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

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

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

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

随后。我们右键此文件即可。
在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");
}
最终生成的图片如下所示,可以看出,跟我们的需求是一致的。

4、总结
Itext的功能非常强大,现在只是用到了最简单的功能,一般来说,只要能替换 文字、图片, 就可以解决我们实际生活中非常多的问题。
对于一些特定模板样式要求,我们可以通过编辑word,或者编辑生成好的pdf模板,来达到样式效果, 毕竟在实际中,我们只是替换对应位置的变量。