参考资料:
- iText+in+Action+2nd+Edition(Itext作者编写)
- ITEXT官网: https://itextpdf.com/en
- GitHub-Itext: https://github.com/itext
最终效果图:
package org.example;
import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
public class App {
// 模板路径
static String SrcDir = "./src/test/resources/pdfs/";
// 生成的新文件路径
static String DestDir = "./target/sandbox/pdfs/";
public static void main(String[] args) {
HashMap<String, Object> classHashMap = new HashMap<>();
ArrayList<HashMap<String, Object>> listData = new ArrayList<>();
classHashMap.put("ClassName", "三班");
classHashMap.put("ClassLeaderName", "王小明");
classHashMap.put("Grade", "FirstGrade");
classHashMap.put("BeiJing", "Yes");
classHashMap.put("NanJing", "Yes");
classHashMap.put("HeFei", "Yes");
classHashMap.put("Introduce", "这是一个非常友好的班级\n我爱这个班级");
classHashMap.put("ContactTel", "18075400516");
classHashMap.put("ContactMail", "27972829@qq.com");
classHashMap.put("List", listData);
HashMap<String, Object> rowMap = new HashMap<>();
rowMap.put("List_No", 1);
rowMap.put("List_Name", "黄小明");
rowMap.put("List_ID", "372925199019028939");
rowMap.put("List_Addr", "上海市长宁区北新泾剑河路101弄1002室上海市长宁区北新泾剑河路101弄1002室");
listData.add(rowMap);
rowMap = new HashMap<>();
rowMap.put("List_No", 2);
rowMap.put("List_Name", "李小明");
rowMap.put("List_ID", "372925199019028939");
rowMap.put("List_Addr", "上海市普陀区延安西路100弄1001室");
listData.add(rowMap);
rowMap = new HashMap<>();
rowMap.put("List_No", 3);
rowMap.put("List_Name", "田明小");
rowMap.put("List_ID", "372925199019038939");
rowMap.put("List_Addr", "上海市长宁区北新泾剑河路100弄1001室上海市长宁区北新泾剑河路100弄1001室");
listData.add(rowMap);
rowMap = new HashMap<>();
rowMap.put("List_No", 4);
rowMap.put("List_Name", "黄明小");
rowMap.put("List_ID", "372925199019028939");
rowMap.put("List_Addr", "上海市长宁区北新泾剑河路101弄1002室");
listData.add(rowMap);
rowMap = new HashMap<>();
rowMap.put("List_No", 5);
rowMap.put("List_Name", "李小明");
rowMap.put("List_ID", "372925199019028939");
rowMap.put("List_Addr", "上海市普陀区延安西路100弄1001室");
listData.add(rowMap);
rowMap = new HashMap<>();
rowMap.put("List_No", 6);
rowMap.put("List_Name", "明田小");
rowMap.put("List_ID", "372925199019038939");
rowMap.put("List_Addr", "上海市长宁区北新泾剑河路100弄1001室上海市长宁区北新泾剑河路100弄1001室");
listData.add(rowMap);
String srcName = "ClassList.pdf";//"Class.pdf";
try {
File file = new File(SrcDir);
if (!file.exists()) {
file.mkdirs();
}
file = new File(DestDir);
if (!file.exists()) {
file.mkdirs();
}
new App().manipulatePdf(classHashMap, srcName);
} catch (Exception e) {
e.printStackTrace();
}
}
/***
* 单个HashMap生成一页PDF
* @param hashMap
* @param srcName
* @throws Exception
*/
protected void manipulatePdf(HashMap<String, Object> hashMap, String srcName) throws Exception {
String Src = SrcDir + srcName;
String Temp = DestDir + srcName.substring(0, srcName.indexOf(".")) + ".tmp";
String Dest = DestDir + srcName.substring(0, srcName.indexOf(".")) + System.currentTimeMillis() + ".pdf";
FileOutputStream fos = new FileOutputStream(Temp);
PdfReader pReader = new PdfReader(Src);// 读取pdf模板
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(pReader, baos);
AcroFields form = stamper.getAcroFields();//获取form域
BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
form.addSubstitutionFont(bfChinese);
//base on hashmap's keys
float tLeft = 0, tTop = 0, tWidth = 0, cHeight = 0;//表格的左上角、顶部坐标,表宽度、每行高度
float[] floats = null;//每列列宽集合
ArrayList<HashMap<String, Object>> listData = null;//列表数据
String[] itemKeys = null;//列表中的key
float[] itemLefts = null;//列表中每列的左边坐标
for (String key : hashMap.keySet()) {
if (key.contains("List")) {
listData = (ArrayList<HashMap<String, Object>>) hashMap.get(key);//列表数据
HashMap<String, Object> firstRow = listData.get(0);//头行--表格项
itemKeys = new String[firstRow.keySet().size()];
itemLefts = new float[firstRow.keySet().size()];
//根据position,对items进行排序
firstRow.keySet().toArray(itemKeys);//所有表格项
for (int i = 0; i < itemKeys.length; i++) {
AcroFields.FieldPosition fPos = form.getFieldPositions(itemKeys[i]).get(0);
itemLefts[i] = fPos.position.getLeft();
}
//冒泡排序
float max = 0;
String temp;
for (int i = 0; i < itemKeys.length; i++) {
for (int j = 0; j < itemKeys.length - 1 - i; j++) {
if (itemLefts[j] > itemLefts[j + 1]) {
max = itemLefts[j];
itemLefts[j] = itemLefts[j + 1];
itemLefts[j + 1] = max;
temp = itemKeys[j];
itemKeys[j] = itemKeys[j + 1];
itemKeys[j + 1] = temp;
}
}
}
//列表数据处理:根据首行filed,计算出每列列宽集合
floats = new float[itemKeys.length];
for (int i = 0; i < itemKeys.length; i++) {
AcroFields.FieldPosition fPos = form.getFieldPositions(itemKeys[i]).get(0);
if (i == 0) {//首列的左边坐标 = 表格左边坐标
tLeft = fPos.position.getLeft();
tTop = fPos.position.getBottom();
}
floats[i] = (float) (fPos.position.getWidth() + 0.7 * 2);//border+padding=0.7
tWidth += fPos.position.getWidth() + 0.7 * 2;
}
} else {
form.setField(key, hashMap.get(key) == null ? "" : hashMap.get(key).toString());
}
}
stamper.setFormFlattening(true);
stamper.close();
fos.write(baos.toByteArray());
fos.flush();
fos.close();
baos.close();
/***
* read stream from temp file and write list to destination pdf
*/
FileOutputStream outputStream = new FileOutputStream(Dest);
PdfReader reader = new PdfReader(Temp);
Rectangle pageSize = reader.getPageSize(1);
Document document = new Document(pageSize);
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
PdfContentByte cbUnder = writer.getDirectContentUnder();
PdfImportedPage formPage;
//将模板中的form数据,读取过来,支持多页。
for (int i = 0; i < reader.getNumberOfPages(); i++) {
if (i != 0) {
document.newPage();
}
formPage = writer.getImportedPage(reader, i + 1);
cbUnder.addTemplate(formPage, 0, 0);
}
if (listData != null && listData.size() > 0) {
//BaseFont
Font fontChinese = new Font(bfChinese, 10.5F, Font.NORMAL);// 五号
PdfPTable table = table = new PdfPTable(floats);
table.setTotalWidth(tWidth);
PdfPCell cell = new PdfPCell();
float bWidth = cell.getBorderWidth();
int rowNum = 0;//初始row号为0
float pageHeight = document.getPageSize().getHeight();
float formHeight = pageHeight - tTop;
float tTopMargin = 10, tBottomMargin = 10, rowHeight = 0;//每页上下留出10px的margin
float tHeight = formHeight + tBottomMargin;//初始表高:Form高+底边框高,之后每新建一页,先把顶部和底部边框计算进来
int preRowPage = (int) (tHeight / pageHeight) + 1; //上一个行所属页,从最后form所在页算起
int curRowPage = 0;
HashMap<Integer, Integer> pageMap = new HashMap<>();//<K,V>=<pageNum,endPageNo>
for (HashMap<String, Object> rowMap : listData) {
//handle row-cells
for (String K : itemKeys) {
cell = new PdfPCell();
cell.addElement(new Phrase(rowMap.get(K).toString(), fontChinese));
table.addCell(cell);
}
//计算哪些行处于分页处
rowHeight = table.getRowHeight(rowNum);
//preRowPage = (int) (tHeight / pageHeight) + 1; //上一个行所属页
curRowPage = (int) ((tHeight + rowHeight + bWidth) / pageHeight) + 1; //如果添加当前行后,所属的页
if (preRowPage < curRowPage) { //当前行处于分页处,为下一页的第一行
pageMap.put(preRowPage, rowNum); //rowNum:从0开始计算,rowNum:下一页的第一行码
tHeight += tTopMargin + tBottomMargin + bWidth * 2; //换页处的行,添加每页的上、下边距、头部第一个边框
preRowPage = curRowPage;
}
tHeight += rowHeight + bWidth * 2;
rowNum++;//下一行的行码:从0开始
}
//分页处理:
int pageCount = (int) (tHeight / pageHeight) + 1;
for (int pageNo = 1; pageNo <= pageCount; pageNo++) {
if (pageNo == 1) {//首页中,table要偏移
table.writeSelectedRows(0, pageMap.get(pageNo) == null ? -1 : pageMap.get(pageNo),
tLeft, tTop, cbUnder);
} else {
document.newPage();
table.writeSelectedRows(pageMap.get(pageNo - 1), pageMap.get(pageNo) == null ? -1 : pageMap.get(pageNo),
tLeft, pageHeight - tTopMargin, cbUnder);
}
}
}
document.close();
reader.close();
//将临时文件删除掉
File temp = new File(Temp);
if (temp.exists()) {
if (temp.isFile()) {
temp.delete();
}
}
}
}
pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- add all iText 7 modules -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>${itext.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>forms</artifactId>
<version>7.1.9</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.0</version>
<!--5.5.9对于checkbox的形状显示会出问题-->
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
</dependencies>
来源:CSDN
作者:cschroc
链接:https://blog.csdn.net/cschroc/article/details/104558445