最近在做pdf模板时,遇到这么一个情况,一部分是固定数据-A,一部分是动态集合数据-B。
刚开始也没注意到会有动态数据,就设置pdf模板进行文本域处理,也是到后来对数据的时候才发现B是
动态数据,但是已经做完模板文本域处理了,不想再纯java生成pdf了。
于是就想能不能把动态数据放到最后,先对固定数据A按照模板填充数据生成临时pdf,然后把填充过数据的临时pdf和动态数据则动态拼接到最终pdf上。
第一步-----生成临时pdf:先把固定数据填充到pdf模板生成临时pdf
/**
* 填充pdf数据
* @param inPath pdf模板路径
* @param outPath 填充数据的pdf路径
* @param templateMap
*/
public static void writePdfModel(String inPath, String outPath, HashMap<String, String> templateMap) {
FileOutputStream fos = null;
PdfReader reader = null;
PdfStamper stamper = null;
BaseFont base = null;
try {
byte[] file = FileUtils.readFileToByteArray(new File(inPath));
fos = new FileOutputStream(outPath);
reader = new PdfReader(file);
stamper = new PdfStamper(reader, fos);
stamper.setFormFlattening(true);
//简体中文字体
base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
AcroFields acroFields = stamper.getAcroFields();
for (String key : acroFields.getFields().keySet()) {
acroFields.setFieldProperty(key, "textfont", base, null);
}
if (templateMap != null) {
for (String fieldName : templateMap.keySet())
{
if (StringUtils.isNotBlank(templateMap.get(fieldName)))
{
acroFields.setField(fieldName, templateMap.get(fieldName));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
stamper.close();
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
reader.close();
IOUtils.closeQuietly(fos);
}
}
第二步----生成最终pdf:拿临时pdf和动态集合数据拼接成最终的pdf
有需要在页眉生成图片logo的可以使用 Header类,不需要生成则可以去除这个类
/**
* 生成最终版本的pdf
* @param outPath 已写入数据的临时pdf模板路径
* @param finalPath 最终版本的pdf生成路径
* @throws Exception
*/
public static void getFinalPdf(String outPath, 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(outPath);
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();
//设置logo
PdfPTable table=new PdfPTable(1);
Header header = new Header(table);
header.setTableHeader(writer);
document.add(table);
//页眉和table之间的间距
Paragraph blank = new Paragraph(" ");
document.add(blank);
//填充动态集合数据填充
List<对象> 集合1=new ArrayList();
Paragraph paragraph = generatePdfATATable(集合1);
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<对象> 集合1) throws Exception {
BaseFont bfChinese = BaseFont.createFont("STSong-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);
PdfPTable tableBox = new PdfPTable(4);
tableBox.setWidths(new float[] { 0.5f, 0.5f, 0.5f,0.5f });// 每个单元格占多宽
//设置总宽度
tableBox.setWidthPercentage(95f);
// 创建表格格式及内容
tableBox.addCell(getCell(new Phrase("药物名称", fontChinese), false, 1, 1));
tableBox.addCell(getCell(new Phrase("剂量", fontChinese), false, 1, 1));
tableBox.addCell(getCell(new Phrase("用法", fontChinese), false, 1, 1));
tableBox.addCell(getCell(new Phrase("频次", fontChinese), false, 1, 1));
for (集合 ata : 集合1) {
tableBox.addCell(getCell(new Phrase(ata.getA(), fontChinese1), false, 1, 1));
tableBox.addCell(getCell(new Phrase(String.valueOf(ata.getB()), fontChinese1), false, 1, 1));
tableBox.addCell(getCell(new Phrase(String.valueOf(ata.getC()), fontChinese1), false, 1, 1));
tableBox.addCell(getCell(new Phrase(String.valueOf(ata.getD()), fontChinese1), false, 1, 1));
}
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());
}
/**
* 设置页眉
*
* @param writer
* @throws Exception
*/
public void setTableHeader(PdfWriter writer) throws Exception {
// String filePath = HomeAssessmentPdfUtil.class.getResource("/static/file/pdflogo.png").getPath();
URL url=Thread.currentThread().getContextClassLoader().getResource("static/file/pdflogo.png");
PdfPTable table = new PdfPTable(1);
table.setTotalWidth(530);
PdfPCell cell = new PdfPCell();
cell.setBorder(0);
Image image01;
image01 = Image.getInstance(url); // 图片自己传
// image01.scaleAbsolute(355f, 10f);
image01.setWidthPercentage(20);
// cell.setPaddingLeft(30f);
cell.setPaddingTop(-20f);
cell.addElement(image01);
//1 带下划线 0不带下划线
cell.setBorderWidthBottom(0);
table.addCell(cell);
Header event = new Header(table);
writer.setPageEvent(event);
}
}
本来我的想法是在临时pdf上拼接动态集合数据而不是重新生成pdf,但是这样会把临时pdf数据给覆盖掉的一个效果。
好了,今天的分享到这结束了,有需要的可以自取代码。