Preface
In the project, I encountered such a requirement: export pdfs in batches according to a single template, and the pdfs exported in batches should be combined into one pdf for printing. Two problems: 1. Generate pdf based on the template. 2. PDF merge
1. Preparatory work (preparing pdf template)
This problem can be achieved using itextpdf and Adobe Acrobat.
1. Generate the pdf template style based on the provided word.
2. Convert it to pdf, which can be operated by wps.
3. Open the pdf with Adobe Acrobat.
4. Select the tool to open the form
. 5. Some fields are automatically detected but incomplete. We You can add and edit related attributes yourself
2. Integration projects
1. Generate pdf
1.1 Project dependencies
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.4.3</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
1.2 Put the prepared template pdf into the project
1.3 Related code
1. Read the template and set the font
File schoolRollQRCode = QrCodeUtil.generate(studentPdfVo.getSchoolRoll(), 300, 300, FileUtil.file("/qrcode" + imageNumber + ".jpg"));
map.put("schoolRollQRCode", schoolRollQRCode.getPath());
org.springframework.core.io.Resource resource = new ClassPathResource("pdf_template/student.pdf");
PdfReader reader = new PdfReader(resource.getInputStream());
BaseFont bf = BaseFont.createFont();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, bos);
AcroFields form = stamper.getAcroFields();
form.addSubstitutionFont(bf);
float bigFontSize = 10;
// false可编辑
stamper.setFormFlattening(true);
2. Entry of ordinary data, that is, entry of a single field corresponding to the text field in the template:
Map<String, String> map1 = new HashMap<>(32);
imageNumber++;
File schoolRollQRCode = QrCodeUtil.generate(studentPdfVo.getSchoolRoll(), 300, 300, FileUtil.file("/qrcode" + imageNumber + ".jpg"));
map.put("schoolRollQRCode", schoolRollQRCode.getPath());
map.put("schoolRoll", studentPdfVo.getSchoolRoll());
map.put("name", studentPdfVo.getName());
map.put("gradeName", studentPdfVo.getGradeName());
map.forEach((key, value) -> {
try {
if ("schoolRollQRCode".equals(key)) {
int pageNo = stamper.getAcroFields().getFieldPositions(key).get(0).page;
Rectangle signRect = stamper.getAcroFields().getFieldPositions(key).get(0).position;
float x = signRect.getLeft();
float y = signRect.getBottom();
// 读图片
Image image = Image.getInstance(map.get(key));
// 获取操作的页面
PdfContentByte under = stamper.getOverContent(pageNo);
// 根据域的大小缩放图片
image.scaleToFit(signRect.getWidth(), signRect.getHeight());
// 添加图片
image.setAbsolutePosition(x, y);
under.addImage(image);
} else {
//设置这个表单域的字体
form.setFieldProperty(key, "textfont", bfChinese, null);
//设置这个表单域的字体大小
form.setFieldProperty(key, "textsize", bigFontSize, null);
form.setField(key, value);
}
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
});
3. Input of QR code pictures
int pageNo = stamper.getAcroFields().getFieldPositions(key).get(0).page;
Rectangle signRect = stamper.getAcroFields().getFieldPositions(key).get(0).position;
float x = signRect.getLeft();
float y = signRect.getBottom();
// 读图片
Image image = Image.getInstance(map.get(key));
// 获取操作的页面
PdfContentByte under = stamper.getOverContent(pageNo);
// 根据域的大小缩放图片
image.scaleToFit(signRect.getWidth(), signRect.getHeight());
// 添加图片
image.setAbsolutePosition(x, y);
under.addImage(image);
4. Entry of collections
Map<String, List<String>> listMap = new HashMap<>(4);
if (CollectionUtil.isNotEmpty(nameList)) {
listMap.put("Box1", nameList);
}
listMap.forEach((key, value) -> {
if (CollectionUtil.isNotEmpty(value)) {
int pageNo = form.getFieldPositions(key).get(0).page;
PdfContentByte pcb = stamper.getOverContent(pageNo);
Rectangle signRect = form.getFieldPositions(key).get(0).position;
//表格位置
int column = 2;
int row = value.size();
PdfPTable table = new PdfPTable(column);
float totalWidth = signRect.getRight() - signRect.getLeft();
float[] width = new float[2];
width[0] = (totalWidth / 9) * 2;
width[1] = (totalWidth / 9) * 7;
try {
table.setTotalWidth(width);
} catch (DocumentException e) {
e.printStackTrace();
}
table.setLockedWidth(true);
table.setKeepTogether(true);
table.setSplitLate(false);
table.setSplitRows(true);
Font fontProve = new Font(bfChinese, 13, 0);
//表格数据填写
for (int i = 0; i < row; i++) {
// 第一列
String name = value.get(i);
Phrase phrase;
if ("体检项目".equals(name)) {
phrase = new Phrase(name, new Font(bfChinese, 17, 0));
} else {
phrase = new Phrase(name, fontProve);
}
PdfPCell cell = new PdfPCell(phrase);
cell.setBorderWidth(1);
cell.setBorderWidthRight(0);
cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
cell.setVerticalAlignment(Element.ALIGN_CENTER);
cell.setLeading((float) 3.0, (float) 1.0);
cell.setMinimumHeight(30f);
table.addCell(cell);
// 第二列
Phrase phrase2 = new Phrase(null, fontProve);
PdfPCell cell2 = new PdfPCell(phrase2);
cell2.setBorderWidth(1);
cell2.setBorderWidthLeft(0);
cell2.setHorizontalAlignment(Element.ALIGN_CENTER);
cell2.setVerticalAlignment(Element.ALIGN_CENTER);
cell2.setLeading((float) 3.0, (float) 1.0);
cell2.setMinimumHeight(30f);
table.addCell(cell2);
}
table.writeSelectedRows(0, value.size(), signRect.getLeft(), signRect.getTop(), pcb);
}
});
5. Export results
2. PDF merge
2.1 Project dependencies
<dependency>
<groupId>com.luhuiguo</groupId>
<artifactId>aspose-pdf</artifactId>
<version>23.1</version>
</dependency>
2.2 Related code
OutputStream out = response.getOutputStream();
InputStream[] inputStreams = new InputStream[outputStreams.size()];
int i = 0;
for (ByteArrayOutputStream byteArrayOutputStream : outputStreams) {
// 将输出流转化成输入流
ByteArrayInputStream swapStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
inputStreams[i] = swapStream;
i++;
}
// 合并pdf
PdfFileEditor pdfFileEditor = new PdfFileEditor();
pdfFileEditor.concatenate(inputStreams, out);
2.3 Final effect display