itext7生成pdf经验之谈
最近在工作中需要使用itext7.1.11在后端生成pdf,由于官方文档不全,很多样式设置都需要自己多次尝试,折磨了我将近两周时间终于实现了产品要求样式特复杂的pdf。在此把我实现过程做一个总结。
一.pom.xml文件中加入jar依赖
1.配置itex7版本号
<properties>
<itext.version>7.1.11</itext.version>
</properties>
2.配置相关jar包
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>io</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>layout</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>forms</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>pdfa</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>pdftest</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>font-asian</artifactId>
<version>${itext.version}</version>
</dependency>
二.制作pdf实现过程
1.引入静态文件
2.获取字体
3.初始化pdf
4.设置页眉页脚监听事件,以及页码监听事件
/**
* pdf页眉页脚监听事件
* @author :iyb-gaozhiqi
* @description :
* @date :2021-08-30 16:49:00
*/
public class HeaderAndFooterHandler implements IEventHandler {
/**
* 页眉
*/
private Image headerImage;
/**
* 页脚
*/
private Image footerImage;
/**
* 文档
*/
private Document doc;
/**
* 字体
*/
private PdfFont font;
/**
*监听事件
* @param headerImage
* @param footerImage
*/
public HeaderAndFooterHandler(Image headerImage, Image footerImage, Document doc, PdfFont font) {
this.footerImage = footerImage;
this.headerImage = headerImage;
this.doc = doc;
this.font = font;
}
/**
* 监听事件
* @param event
*/
@SneakyThrows
@Override
public void handleEvent(Event event) {
PdfDocumentEvent documentEvent = (PdfDocumentEvent) event;
PdfPage page = documentEvent.getPage();
int pageNum = documentEvent.getDocument().getPageNumber(page);
if (pageNum > 2) {
//加页码
headerImage.scaleAbsolute(620, 70);
Paragraph header = new Paragraph();
header.add(headerImage);
footerImage.scaleToFit(622, 60);
Paragraph footer = new Paragraph();
footer.add(footerImage);
Canvas canvas = new Canvas(documentEvent.getPage(), PageSize.A4);
if (pageNum > 13) {
canvas.setFont(font).showTextAligned(header, 295, PageSize.A4.getTop() - doc.getTopMargin() + 10,
TextAlignment.CENTER).showTextAligned(footer, 298, 0, TextAlignment.CENTER).close();
}
}
}
}
/**
* pdf页码监听事件
* @author :iyb-gaozhiqi
* @description :
* @date :2021-08-30 16:49:00
*/
public class PdfPageHandler implements IEventHandler {
/**
* pdf文档
*/
private PdfDocument pdf;
/**
* pdf字体
*/
private PdfFont font;
/**
* pdf样式
*/
private Integer pdfStyle;
/**
* 页码监听
* @param pdf
* @param font
* @param pdfStyle
*/
public PdfPageHandler(PdfDocument pdf, PdfFont font, Integer pdfStyle) {
this.pdf = pdf;
this.font = font;
this.pdfStyle = pdfStyle;
}
/**
* 监听事件
* @param event
*/
@SneakyThrows
@Override
public void handleEvent(Event event) {
PdfDocumentEvent documentEvent = (PdfDocumentEvent) event;
PdfPage page = documentEvent.getPage();
int pageNum = documentEvent.getDocument().getPageNumber(page);
Color color = null;
if(Objects.equals(PdfStyleEnum.FINANCE.getType(),pdfStyle)){
color = ServiceHelper.transColor("#965622");
}else{
color = ServiceHelper.transColor("#999999");
}
if (pageNum > 2) {
Canvas canvas = new Canvas(documentEvent.getPage(), PageSize.A4);
canvas.setFont(font).setFontColor(color)
.showTextAligned(String.valueOf(pdf.getNumberOfPages() - 3), 300, 30, TextAlignment.CENTER).close();
}
}
}
5.设置单元格方法
/**
* 给单元格设置行列和文本
* @param rowspan
* @param colspan
* @param text
* @return
*/
private Cell cell(int rowspan, int colspan, String text) {
Cell cell = new Cell(rowspan, colspan);
Border border = new SolidBorder(ServiceHelper.transColor("#cccccc"), 1);
cell.setBorder(border);
cell.setFont(font).setMinHeight(10).setTextAlignment(TextAlignment.CENTER)
.setHorizontalAlignment(HorizontalAlignment.CENTER).setVerticalAlignment(VerticalAlignment.MIDDLE);
Paragraph p = new Paragraph(text);
p.setFixedLeading(17);
cell.add(p);
return cell;
}
/**
* 给单元格设置文本
* @param text
* @return
*/
private Cell cell(String text) {
return cell(1, 1, text);
}
/**
* 给单元格设置文本
* @param paragraph
* @return
*/
private Cell cell(Paragraph paragraph) {
return cell(1, 1, paragraph);
}
/**
* 给单元格设置行列和文本
* @param rowspan
* @param colspan
* @param paragraph
* @return
*/
private Cell cell(int rowspan, int colspan, Paragraph paragraph) {
Cell cell = new Cell(rowspan, colspan);
Border border = new SolidBorder(ServiceHelper.transColor("#cccccc"), 1);
cell.setBorder(border);
cell.setFont(font).setMinHeight(10).setTextAlignment(TextAlignment.CENTER)
.setHorizontalAlignment(HorizontalAlignment.CENTER).setVerticalAlignment(VerticalAlignment.MIDDLE);
paragraph.setFixedLeading(17);
cell.add(paragraph);
return cell;
}
6.获取静态图片通用方法
/**
* 获取图片文件
* @param fileName
* @return
*/
private Image getImage(String fileName) {
String pathPrefix = "brand/";
Image image = new Image(
ImageDataFactory.create(this.getClass().getClassLoader().getResource(pathPrefix + fileName)));
return image;
}
/**
* 获取字体
* @param fileName
* @return
*/
private PdfFont getPdfFont(String fileName) throws IOException {
InputStream in = this.getClass().getClassLoader().getResourceAsStream("brand/" + fileName);
PdfFont font = PdfFontFactory.createFont(IOUtils.toByteArray(in), PdfEncodings.IDENTITY_H, true); // 使用自定义字体
return font;
}
/**
* 获取图片文件,并设置大小
* @param fileName
* @return
*/
private Image getArrowImage(String fileName) {
String pathPrefix = "brand/";
Image image = new Image(
ImageDataFactory.create(this.getClass().getClassLoader().getResource(pathPrefix + fileName)));
image.scaleAbsolute(20, 10);
return image;
}
7.设置表格内容
private void table(CreateReportPdfDto createReportPdfDto) {
//换页
doc.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
Paragraph p1 = new Paragraph();
p1.setHorizontalAlignment(HorizontalAlignment.LEFT);
p1.setWidth(UnitValue.createPercentValue(100));
p1.setHeight(UnitValue.createPercentValue(100));
p1.setCharacterSpacing(0.4f); // 字间距
p1.add(new Text("家庭风险保障额度总览\n").setFontColor(ServiceHelper.transColor("#009BD1")).setFontSize(28).setBold());
p1.add(new Text("表格中呈现的保额数据仅对应此报告的生成时间,责任额度依照聚合规则分类汇总,无法囊括所有特殊责任。")
.setFontColor(Color.convertRgbToCmyk(new DeviceRgb(51, 51, 51))).setFontSize(14));
Color rgb = ServiceHelper.transColor("#009BD1");
Color color = ServiceHelper.transColor("#FFFFFF");
doc.add(p1);
Div div = new Div();
div.setPaddings(20, 0, 20, 0);
java.util.List<SummaryDto> summaryList = createReportPdfDto.getSummaryList();
for (int i = 0; i < summaryList.size(); i++) {
SummaryDto summary = summaryList.get(i);
String[] insuredArr = summary.getInsuredList();
int insuredSize = insuredArr.length;
float[] colWidths = new float[insuredSize + 2];
colWidths[0] = 300;
colWidths[1] = 300;
float customHeaderWidth = (TABLE_WIDTH - 600) / insuredSize;
for (int j = 0; j < insuredSize; j++) {
colWidths[j + 2] = customHeaderWidth;
}
Table table = new Table(colWidths);
table.setFont(font);
table.setWidth(UnitValue.createPercentValue(100));
Cell head_11 = cell(2, 1, "责任类别").setFontColor(color).setBackgroundColor(rgb);
Cell head_12 = cell(2, 1, "责任细则").setFontColor(color).setBackgroundColor(rgb);
Cell head_13 = cell(1, insuredSize, "保障额度").setFontColor(color).setBackgroundColor(rgb);
table.addCell(head_11);
table.addCell(head_12);
table.addCell(head_13);
for (int j = 0; j < insuredSize; j++) {
Cell customHeaderCell = cell(insuredArr[j]).setFontColor(color).setBackgroundColor(rgb);
table.addCell(customHeaderCell);
}
java.util.List<FamilyDutyTypeDto> tableList = summary.getTable();
for (int j = 0; j < tableList.size(); j++) {
FamilyDutyTypeDto tableData = tableList.get(j);
java.util.List<DutyTypeDetailDto> subList = tableData.getSubList();
int subSize = subList.size();
Cell row_x1 = cell(subSize, 1, tableData.getMain());
table.addCell(row_x1);
for (int k = 0; k < subSize; k++) {
DutyTypeDetailDto sub = subList.get(k);
Cell row_x2 = cell(sub.getName());
table.addCell(row_x2);
String[] items = sub.getValues();
for (int m = 0; m < items.length; m++) {
Cell cell_xm = cell(items[m]);
table.addCell(cell_xm);
}
}
}
div.add(table);
if (i < summaryList.size() - 1) {
Paragraph spaceP = new Paragraph();
spaceP.setHeight(20);
div.add(spaceP);
}
}
//保障建议
if(CollectionUtils.isNotEmpty(createReportPdfDto.getAdvices())){
Paragraph p2 = new Paragraph();
p2.setHorizontalAlignment(HorizontalAlignment.LEFT);
p2.setWidth(UnitValue.createPercentValue(100));
p2.setHeight(UnitValue.createPercentValue(100));
p2.setCharacterSpacing(0.4f); // 字间距
p2.add(new Text("保障建议\n").setFontColor(ServiceHelper.transColor("#009BD1")).setFontSize(20).setBold());
div.add(p2);
for(int k = 0;k<createReportPdfDto.getAdvices().size();k++){
ReportAdviceDto reportAdviceDto = createReportPdfDto.getAdvices().get(k);
Color rgb2 = ServiceHelper.transColor("#F5FDFF");
float[] colWidths = {1};
Table table = new Table(UnitValue.createPercentArray(colWidths));
table.setWidth(526);
table.setBackgroundColor(rgb2);
table.setBorder(Border.NO_BORDER);
Cell head_11 = cell(1, 1, reportAdviceDto.getApplicant()).setTextAlignment(TextAlignment.LEFT).setFontColor(ServiceHelper.transColor("#009BD1"));
head_11.setBorder(Border.NO_BORDER);
Cell head_12 = cell(1, 1, reportAdviceDto.getText()).setTextAlignment(TextAlignment.LEFT);
head_12.setBorder(Border.NO_BORDER);
table.addCell(head_11);
table.addCell(head_12);
div.add(table);
if (k < createReportPdfDto.getAdvices().size() - 1) {
Paragraph spaceP = new Paragraph();
spaceP.setHeight(10);
div.add(spaceP);
}
}
}
doc.add(div);
}
8.制作pdf返回文件流
/**
*生成pdf
* @param createReportPdfDto
* @return
*/
private String generatePdf(CreateReportPdfDto createReportPdfDto) {
String result = "";
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();//构建字节输出流
//初始化pdf
init(baos);
Image headerImage = getImage("header.png");
Image footerImage = getImage("footer.png");
//增加页眉页脚监听事件
HeaderAndFooterHandler headerAndFooterHandler = new HeaderAndFooterHandler(headerImage, footerImage, doc,
font);
pdf.addEventHandler(PdfDocumentEvent.START_PAGE, headerAndFooterHandler);
//加页码监听事件
PdfPageHandler pdfPageHandler = new PdfPageHandler(pdf, font, createReportPdfDto.getPdfStyle());
pdf.addEventHandler(PdfDocumentEvent.END_PAGE, pdfPageHandler);
//pdf封面
cover(createReportPdfDto);
//目录
content(createReportPdfDto.getContents());
//平台介绍
cover1();
//合作公司
cover2();
//保通保险服务介绍
cover3();
//保通保险服务介绍-服务内容
cover31();
//保通保险服务介绍-家庭风险
cover32();
//保通保险服务介绍-企业风险
cover33();
//保通保险服务介绍-全能核
cover34();
//保通保险服务介绍-省心赔
cover35();
//保单托管服务价值
cover4();
//风险管理配置-人生七张保单
cover5();
//风险管理配置-家庭四大平衡账户
cover6();
//家庭年度保费总览
familyOverview(createReportPdfDto);
//年度保费清单
getFamilyPremiumList(createReportPdfDto);
//家庭年度保单/保费占比-投保人
policyRateByApplicant(createReportPdfDto.getDynamicImages().getPieChartList());
//家庭年度保单/保费占比-被保人
policyRateByInsured(createReportPdfDto.getDynamicImages().getPieChartList());
//保单交费查询
policyPaymentInquiry(createReportPdfDto.getStatisticsDate(), createReportPdfDto.getTotalFee(),
createReportPdfDto.getPayRecordList());
//家庭风险保障额度总览
table(createReportPdfDto);
//家庭保单管理
familyPolicyManage(createReportPdfDto.getTotalPolicy(), createReportPdfDto.getPolicyList());
//受益人
getBeneficiaryData(createReportPdfDto.getBenefitList());
//家庭财富风险顾问
familyRisk(createReportPdfDto.getDynamicImages(), createReportPdfDto.getAgent(), headerAndFooterHandler);
//封底
endCover(pdfPageHandler);
//关闭相关pdf
closePdf();
result = Base64Utils.encodeToString(baos.toByteArray());
} catch (Exception e) {
log.error("PDF异常", e);
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
log.error("PDF异常", e);
}
}
}
return result;
}
9.关闭文档
/**
* 关闭
*/
private void closePdf() {
if (null != doc) {
doc.close();
}
}