java输出自定义模板的pdf文件(插件:itext)
采用itext插件动态生成pdf文件(语言:java)
·
1、模板制作
需求:java使用插件生成form表单与表格结合的pdf文件。本文采用的插件为itext。采用Adobe编辑模板的表单域域名。
可以用word快速制作动态模板,将模板转为pdf文件并用adobe打开,点击adobe的更多工具,点击准备表单,打开表单域编辑。
一般在word制作的表格转换为pdf时,准备表单时表单域存在文本域。
注意:表单域中的字段名一定要跟代码中的对应。
2、maven依赖
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.2.1</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
<!-- 3.0.1-->
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.2</version>
</dependency>
3、代码实现
(1)form域填充
这里指的是form域是静态模板,无需动态生成。此为获取表单域字段并相应填充的实现代码,其中有插入图片的需求,不需要图片可以省略insertImage这个方法,此段代码为参考,引用的原文在末尾有注。在form表单域的字段填充中,打印出的pdf字体粗细不统一,可以再逐一填充表单字段时做如下设定,以setFieldProperty设置字段属性。
for (Map.Entry<String, String> entry : fieldMap.entrySet()) {
if (entry.getValue() != null) {
form.setFieldProperty(entry.getKey(), "textfont", bf, null);
form.setFieldProperty(entry.getKey(), "textsize", 12f, null);
form.setField(entry.getKey(), entry.getValue(), true);
}
}
import com.itextpdf.text.*;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.*;
public class DevPdfFGenerator {
public static boolean fillPdfTemplate( String template_path, String output_path, Map<String, String> fieldMap, Map<String, String> imageMap,int width, int height) {
boolean success = true;
OutputStream os = null;
PdfStamper ps = null;
PdfReader reader = null;
AcroFields form = null;
try {
os = Files.newOutputStream(new File(output_path).toPath());
reader = new PdfReader(template_path);
ps = new PdfStamper(reader, os);
form = ps.getAcroFields();
// 添加中文字体支持(可选)
BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
form.addSubstitutionFont(bf);
// 填充表单字段
for (Map.Entry<String, String> entry : fieldMap.entrySet()) {
if (entry.getValue() != null) {
form.setField(entry.getKey(), entry.getValue(), true);
}
}
// 插入图片
for (Map.Entry<String, String> entry : imageMap.entrySet()) {
if (entry.getValue() != null) {
insertImage(form, ps, entry.getKey(), entry.getValue());
}
}
} catch (Exception e) {
success = false;
e.printStackTrace(); // 可以根据实际情况处理异常
} finally {
try {
if (ps != null) ps.close();
if (reader != null) reader.close();
if (os != null) os.close();
} catch (IOException | DocumentException e) {
throw new RuntimeException(e);
} finally {
System.out.println("文件导出完成!");
}
}
return success;
}
//插入图片的函数,fieldName为字段名,imageUrl为图片路径
private static void insertImage(AcroFields form, PdfStamper ps, String fieldName, String imageUrl) throws IOException, DocumentException {
if (imageUrl != null) {
//获取fieldName所在的页码
int pageNo = form.getFieldPositions(fieldName).get(0).page;
Rectangle signRect = form.getFieldPositions(fieldName).get(0).position;
float x = signRect.getLeft();
float y = signRect.getBottom();
Image image = Image.getInstance(imageUrl);
// 获取操作的页面
PdfContentByte overContent = ps.getOverContent(pageNo);
// 根据域的大小缩放图片
image.scaleToFit(signRect.getWidth(), signRect.getHeight());
// 添加图片
image.setAbsolutePosition(x, y);
overContent.addImage(image);
ps.setFormFlattening(true);
}
}
}
(2)动态列表的生成
这里需要特别注意的是:1、最开始没有特意用这段代码标识字段,中文字段并没有显示在表格中,itext可能默认不显示中文字段(有待查阅)
new PdfPCell(new Phrase("测试1", fontChinese1))
2、表格列设置为9列,但要填充的列可能不足,若不予以填充,就无法显示内容,有两种解决方法,第一种就是默认给剩余列填充一个字符,第二种是将列合并,本文采用的是第一种方法,于列表末尾也有添加合并的字段。
注:参考的原文代码在文末有引用。
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.jeesite.modules.sdms.entity.SdmsDeviceInspection;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
public class GetDynamicTable {
// @Test
public static void getFinalPdf(List<SdmsDeviceInspection> tableList,String template_path,String finalPath) {
PdfReader reader = null;// 读取pdf模板
Document document = null;
PdfWriter writer = null;
FileOutputStream outputStream = null;
FileOutputStream fos = null;
try {
outputStream = new FileOutputStream(finalPath);
reader = new PdfReader(template_path);
Rectangle pageSize = reader.getPageSize(1);
document = new Document(pageSize);
writer = PdfWriter.getInstance(document, outputStream);
document.open();
PdfContentByte cbUnder = writer.getDirectContentUnder();
PdfImportedPage pageTemplate = writer.getImportedPage(reader, 1);
cbUnder.addTemplate(pageTemplate, 0, 0);
//新创建一页来存放后面生成的表格
document.newPage();
//页眉和table之间的间距
Paragraph blank = new Paragraph(" ");
document.add(blank);
//填充动态集合数据填充
Paragraph paragraph = generatePdfATATable(tableList);
document.add(paragraph);
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
document.close();
reader.close();
}
}
/**
* 生成pdf表格
*
* @return
* @see
*/
private static Paragraph generatePdfATATable(List<SdmsDeviceInspection> tableList) throws Exception {
// 宋体
BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
//浅色不加粗
Font fontChinese1 = new Font(bfChinese, 11F, Font.NORMAL);// 五号
//黑色加粗
Font fontChinese = new Font(bfChinese, 11F, Font.BOLD);// 五号
Paragraph ret = new Paragraph("设备控制记录表(附页)", fontChinese1);
// 居中
ret.setAlignment(Element.ALIGN_CENTER);
PdfPTable tableBox = new PdfPTable(9);
tableBox.setWidths(new float[]{0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f});// 每个单元格占多宽
//设置总宽度
tableBox.addCell(new PdfPCell(new Phrase("测试1", fontChinese1)));
PdfPCell nameValue = new PdfPCell(new Phrase("测试2", fontChinese1));
nameValue.setColspan(2);
tableBox.addCell(nameValue);
tableBox.addCell(new Phrase("测试3", fontChinese1));
PdfPCell ecepdiNoValue = new PdfPCell(new Phrase("测试4", fontChinese1));
ecepdiNoValue.setColspan(2);
tableBox.addCell(ecepdiNoValue);
tableBox.addCell(new Phrase("测试5", fontChinese1));
PdfPCell prjName = new PdfPCell(new Phrase("测试6", fontChinese1));
prjName.setColspan(2);
tableBox.addCell(prjName);
for (int i = 0; i < 3; i++) {
tableBox.addCell(new Phrase("日期", fontChinese1));
tableBox.addCell(new Phrase("状态", fontChinese1));
tableBox.addCell(new Phrase("使用人", fontChinese1));
}
tableBox.setWidthPercentage(95f);
// 创建表格格式及内容
for (SdmsDeviceInspection ata : tableList) {
tableBox.addCell(new Phrase(ata.getPhase(), fontChinese1));
tableBox.addCell(new Phrase(ata.getName(), fontChinese1));
tableBox.addCell(new Phrase(ata.getEcepdiNo(), fontChinese1));
}
if (tableList.size() % 3!= 0) {
int index = 9 - tableList.size()%3 * 3;
while (index > 0) {
tableBox.addCell(new PdfPCell(new Phrase("", fontChinese1))); // 空单元格
index--;
}
}
PdfPCell lastText = new PdfPCell(new Phrase("注释", fontChinese1));
lastText.setColspan(9);
tableBox.addCell(lastText);
ret.add(tableBox);
return ret;
}
/**
* 设置页眉信息;填充logo
*/
private static class Header extends PdfPageEventHelper {
public static PdfPTable header;
public Header(PdfPTable header) {
Header.header = header;
}
@Override
public void onEndPage(PdfWriter writer, Document document) {
// 把页眉表格定位
header.writeSelectedRows(0, -1, 30, 806, writer.getDirectContent());
}
}
方法调用
注意:这里的表单生成的模板文件为原始模板,而动态列表需要采用表单生成的pdf文件。(后续会会再优化,大家有什么优化的方法可以一起讨论 欢迎指正)
public String getPdf( SdmsDeviceReturn sdmsDeviceReturn ) throws FileNotFoundException {
String output_path = "/D:/###/text.pdf";
String template_path ="/static/common/测试模板-表格.pdf";
//表单中的文本数据map
Map<String, String> form = new HashMap<>();
//表单中图片map
Map<String, String> image = new HashMap<>();
//表单内容
form.put("fill5","1");
//图片
image.put("imgUser", "D:/###/测试图片.jpg");
image.put("imgCustodian", "D:/###/测试图片.jpg");
image.put("imgApply", "D:/###/测试图片.jpg");
DevPdfFGenerator.fillPdfTemplate(template_path, output_path, form, image, 300, 300);
//列表内容
List<SdmsDeviceInspection> tableList = new ArrayList<>();
SdmsDeviceInspection inspection = new SdmsDeviceInspection();
inspection.setEcepdiNo("ceshi");
inspection.setName("测试名称");
tableList.add(inspection);
String templatePath="/D:/###/text.pdf";
String finalPath="/D:/###/text2.pdf";
// 表格数据渲染
GetDynamicTable.getFinalPdf(tableList,templatePath,finalPath);
return "pdf生成成功";
}
4、最终呈现
下图为form表单呈现效果
下图为动态生成列表呈现效果。

form引用:JAVA操作Itext向pdf模板中填充数据,图片,复选框!_java填充pdf-CSDN博客和Java使用itext按模板生成PDF文件_51CTO博客_java生成pdf文件 动态表格引用:java操作pdf模板并添加动态集合列表数据_java 动态表格 pdf-CSDN博客
更多推荐
所有评论(0)