需求
在PDF文件中植入一些信息(pdf模版)
制作模版
可以看到下面红色箭头标注位置,这都是我们需要动态写入数据的表单域,可以使用wps等工具来制作
点击编辑表单,可以给对应空间添加表单域,表单域名称是key,在后续我们填充数据时以此来映射
实战
pdf编辑好以后我们就可以开始编写代码了,首先添加Maven坐标
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
添加pdf处理工具类
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.List;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
/**
* pdf电子合同工具
*/
public class PdfUtil {
/**
* 根据PDF模版生成PDF文件
*
* @param templateFilePath
* PDF模版文件路径
* @param data
* 表单数据
* @param imageData
* 图片数据 VALUE为图片文件路径
* @param formFlattening
* false:生成后的PDF文件表单域仍然可编辑 true:生成后的PDF文件表单域不可编辑
* @param pdfFilePath
* 生成PDF的文件路径
*/
public static void createPdf(String templateFilePath, HashMap<String, String> data,
HashMap<String, String> imageData, boolean formFlattening, String pdfFilePath) throws Exception {
PdfReader reader = null;
ByteArrayOutputStream bos = null;
PdfStamper pdfStamper = null;
FileOutputStream fos = null;
try {
// 读取PDF模版文件
reader = new PdfReader(templateFilePath);
// 输出流
bos = new ByteArrayOutputStream();
// 构建PDF对象
pdfStamper = new PdfStamper(reader, bos);
// 获取表单数据
AcroFields form = pdfStamper.getAcroFields();
// 使用中文字体 使用 AcroFields填充值的不需要在程序中设置字体,在模板文件中设置字体为中文字体 Adobe 宋体 std L
BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
form.addSubstitutionFont(bfChinese);
// 表单赋值
for (String key : data.keySet()) {
form.setField(key, data.get(key), true);
// 也可以指定字体
form.setFieldProperty(key, "textfont", bfChinese, null);
}
// 添加图片
if (null != imageData && imageData.size() > 0) {
for (String key : imageData.keySet()) {
List<AcroFields.FieldPosition> fieldPositions = form.getFieldPositions(key);
int pageNo = fieldPositions.get(0).page;
Rectangle signRect = form.getFieldPositions(key).get(0).position;
float x = signRect.getLeft();
float y = signRect.getBottom();
// 读图片
Image image = Image.getInstance(imageData.get(key));
// 获取操作的页面
PdfContentByte under = pdfStamper.getOverContent(pageNo);
// 根据域的大小缩放图片
image.scaleToFit(signRect.getWidth(), signRect.getHeight());
// 添加图片
image.setAbsolutePosition(x, y);
under.addImage(image);
}
}
// 如果为false那么生成的PDF文件还能编辑,一定要设为true
pdfStamper.setFormFlattening(formFlattening);
pdfStamper.close();
// 保存文件
fos = new FileOutputStream(pdfFilePath);
fos.write(bos.toByteArray());
fos.flush();
} finally {
if (null != fos) {
try {
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (null != bos) {
try {
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (null != reader) {
try {
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) throws Exception {
HashMap<String, String> data = new HashMap<>();
data.put("busLicenseName", "李四便利店");
data.put("provinceName", "李四");
data.put("cityName", "深圳");
data.put("areaName", "南山区");
data.put("address", "科兴科技园");
data.put("busLicenseNum", "XXXXXXX");
// busLicense 为多选框
data.put("busLicense", "Yes");
data.put("cardName", "李四");
data.put("phone", "手机");
data.put("mailbox", "123465798@qq.com");
data.put("crpExpY", "2028");
data.put("crpExpM", "06");
data.put("crpExpD", "10");
data.put("idCardNo", "李四身份证");
data.put("now", DateUtil.format(new Date(), DatePattern.CHINESE_DATE_PATTERN));
// HashMap<String, String> data = new HashMap<>();
HashMap<String, String> imageData = new HashMap<>();
// 在线签名网址:https://tools.kalvinbg.cn/txt/sign
imageData.put("signPic", "C:\\Users\\XXXX\\Downloads\\Kalvin在线工具签名.png");
String templateFilePath = "C:\\Users\\XXXX\\Downloads\\测试pdf.pdf";
String pdfFilePath = "C:\\Users\\XXXX\\Downloads\\new_" + "xxxx" + ".pdf";
File file = new File(pdfFilePath);
// 根据PDF模版生成PDF文件
PdfUtil.createPdf(templateFilePath, data, imageData, true, pdfFilePath);
}
最终生成如下,这里有用到文本域、多选按钮、签名植入,下面圈出多选框以及签名图片,文字大小样式可在制作pdf模版时指定