Java使用iText7生成PDF,学到啦!
共 5667字,需浏览 12分钟
·
2021-11-14 09:09
点击上方蓝色字体,选择“标星公众号”
优质文章,第一时间送达
前言
我们之前使用js库html2canvas + jspdf实现html转PDF、图片,并下载(详情请戳:html页面转PDF、图片操作记录),大致原理是将页面塞到画布里,以图片的方式放到PDF中,生成的文件比较大,文本记录Java使用iText7生成PDF
iText 7是iText强大的PDF工具包的最新版本,用于PDF生成,PDF编程,处理和操作,如数字签名等
官方文档:
https://kb.itextpdf.com/home/it7kb/ebooks
简单生成PDF
官方文档:
https://kb.itextpdf.com/home/it7kb/ebooks/itext-7-jump-start-tutorial-for-java
根据文档说明,我们引入依赖
7.1.7
com.itextpdf
kernel
${itext7.version}
com.itextpdf
io
${itext7.version}
com.itextpdf
layout
${itext7.version}
com.itextpdf
forms
${itext7.version}
com.itextpdf
pdfa
${itext7.version}
代码
package cn.huanzi.qch.util;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.colors.Color;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.action.PdfAction;
import com.itextpdf.kernel.pdf.annot.PdfLinkAnnotation;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.Style;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.font.FontProvider;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.VerticalAlignment;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/**
* itextpdf 工具类
* iText 7是iText强大的PDF工具包的最新版本,用于PDF生成,PDF编程,处理和操作,如数字签名等。
* https://kb.itextpdf.com/home/it7kb/ebooks
*/
public class ITextPdfUtil {
//字体,我这里使用系统自带的simhei黑体
private static final String FONT = "C:/Windows/Fonts/simhei.ttf";
//html转pdf
public static void html2pdf(){
String html = "";
//从html文件读取内容
StringBuilder stringBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader("E:\\Java\\html2pdf.html"));){
for (Object o : reader.lines().toArray()) {
stringBuilder.append(o);
}
}catch (Exception e){
e.printStackTrace();
}
html = stringBuilder.toString();
try (PdfWriter writer = new PdfWriter("E:\\Java\\html2pdf.pdf");
PdfDocument pdf = new PdfDocument(writer);
){
//转换器属性设置
ConverterProperties props = new ConverterProperties();
//字体
props.setFontProvider(new FontProvider());
props.getFontProvider().addFont(ITextPdfUtil.FONT);
//为img图片配置基础路径
props.setBaseUri("D:\\XFT User\\Pictures\\");
//HtmlConverter.convertToDocument
Document document = HtmlConverter.convertToDocument(html, pdf, props);
//设置文档属性
pdf.getDocumentInfo().setAuthor("huanzi-qch");
pdf.getDocumentInfo().setTitle("IText测试html2pdf");
pdf.getDocumentInfo().setSubject("XXX公司");
pdf.getDocumentInfo().setMoreInfo("1","111");
pdf.getDocumentInfo().setCreator("huanzi");
pdf.getDocumentInfo().setKeywords("IText");
//注册事件监听
pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new MyEventHandler());
//设置字体
document.setFont(ITextPdfUtil.getPdfFont());
//页边距
document.setMargins(0, 0, 0, 0);
document.close();
System.out.println("操作完成!");
}catch (IOException e){
e.printStackTrace();
System.err.println("操作异常...");
}
}
//生成简单PDF
public static void test(){
//语法糖
try (PdfWriter writer = new PdfWriter("E:\\Java\\test.pdf");
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf, PageSize.A4.rotate());
){
//设置文档属性
pdf.getDocumentInfo().setAuthor("huanzi-qch");
pdf.getDocumentInfo().setTitle("IText测试PDF");
pdf.getDocumentInfo().setSubject("XXX公司");
pdf.getDocumentInfo().setMoreInfo("1","111");
pdf.getDocumentInfo().setCreator("huanzi");
pdf.getDocumentInfo().setKeywords("IText");
//注册事件监听
pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new MyEventHandler());
//设置字体
document.setFont(ITextPdfUtil.getPdfFont());
//页边距
document.setMargins(20, 20, 20, 20);
//简单文字
document.add(new Paragraph("简单文字"));
document.add(new Paragraph("Hello Word!").add(new Tab()).add(new Text("你好!").addStyle(new Style().setFontSize(24))));
//简单图片
document.add(new Paragraph("简单图片"));
document.add(new Image(ImageDataFactory.create("D:\\XFT User\\Pictures\\logo.png")));
//简单表格
document.add(new Paragraph("简单表格"));
Table table = new Table(new float[]{3, 3, 4});
PdfFont font = ITextPdfUtil.getPdfFont();
//标题、内容
process(table, "姓名;年龄;电话号码", font, true);
for (int i = 0; i < 5; i++) {
process(table, "张三"+i+";"+(18+i)+";1500000000"+i, font, false);
}
document.add(table);
//超链接
document.add(new Paragraph("超链接"));
PdfLinkAnnotation annotation = new PdfLinkAnnotation(new Rectangle(0, 0));
annotation.setAction(PdfAction.createURI("https://itextpdf.com/"));
Paragraph p = new Paragraph("更多精彩内容,猛戳:").add(new Link("这里", annotation));
document.add(p);
//换一页
//document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
document.close();
System.out.println("操作完成!");
} catch (IOException e) {
e.printStackTrace();
System.err.println("操作异常...");
}
}
//获取统一字体
public static PdfFont getPdfFont(){
PdfFont pdfFont = null;
try {
pdfFont = PdfFontFactory.createFont(ITextPdfUtil.FONT, PdfEncodings.IDENTITY_H,true);
} catch (IOException e) {
e.printStackTrace();
}
return pdfFont;
}
//设置表格内容
public static void process(Table table, String line, PdfFont font, boolean isHeader) {
String[] split = line.split(";");
for (String s : split) {
Cell cell = new Cell().add(new Paragraph(s).setFont(font));
if (isHeader) {
table.addHeaderCell(cell);
} else {
table.addCell(cell);
}
}
}
/**
* 自定义事件监听
*
* 背景颜色
* 页脚页眉
* 文字水印
*
* 也可以分成多个EventHandler
*/
protected static class MyEventHandler implements IEventHandler {
@Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdfDoc = docEvent.getDocument();
PdfPage page = docEvent.getPage();
int pageNumber = pdfDoc.getPageNumber(page);
Rectangle pageSize = page.getPageSize();
PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);
//背景颜色
Color backgroundColor = new DeviceRgb(245, 245, 245);;
pdfCanvas.saveState()
.setFillColor(backgroundColor)
.rectangle(pageSize.getLeft(), pageSize.getBottom(),pageSize.getWidth(), pageSize.getHeight())
.fill().restoreState();
//页脚页眉
PdfFont pdfFont = ITextPdfUtil.getPdfFont();
String header = "我是页眉";
String footer = "第 "+pageNumber+" 页";
pdfCanvas.beginText()
.setFontAndSize(pdfFont, 9)
.moveText((pageSize.getWidth() / 2) - (pdfFont.getWidth(header) / 200), pageSize.getTop() - 20)
.showText(header)
.moveText((pdfFont.getWidth(header) / 200) - (pdfFont.getWidth(footer) / 200), -pageSize.getTop() + 30)
.showText(footer)
.endText();
//文字水印
Canvas canvas = new Canvas(pdfCanvas, pdfDoc, page.getPageSize());
canvas.setFontColor(new DeviceRgb(200, 200, 200));
canvas.setProperty(20, 20);
canvas.setFont(pdfFont);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
canvas.showTextAligned(new Paragraph("我是文字水印").setOpacity(0.8f),(150 + i * 300), (160 + j * 150), pdfDoc.getPageNumber(page), TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
}
}
pdfCanvas.release();
}
}
//测试
public static void main(String[] args) {
test();
//html2pdf();
}
}
效果
生成的PDF
文档属性
HTML转PDF
官方文档:
https://kb.itextpdf.com/home/it7kb/ebooks/itext-7-converting-html-to-pdf-with-pdfhtml
pdfHTML是iText 7的一个附加组件,需要添加依赖
2.1.4
com.itextpdf
html2pdf
${itext7.html2pdf.version}
代码
代码同上,仅main测试函数不同!
//测试
public static void main(String[] args) {
//test();
html2pdf();
}
PS:html内容往下拉
效果
html页面
简单简历
"Content-Type" content="text/html; charset=utf-8" />
"cache-control" content="no-cache, no-store, must-revalidate"/>
"pragma" content="no-cache"/>
"expires" content="0"/>
"body" class="main">
"section">
"module">
"list1" style="margin: 0;">基本信息
"block">
XXX/男/25岁
本科/XX学校/XX专业/2014-2018
工龄:X年
手机:XXXXXXXXXX
邮箱:XXXXX@qq.com
GitHub:"https://github.com/huanzi-qch">https://github.com/huanzi-qch
博客园:"https://www.cnblogs.com/huanzi-qch">https://www.cnblogs.com/huanzi-qch
求职岗位:Java开发/目标城市:南宁市/期望薪资:面议
注:已离职,一个月可到岗
"position: relative;top: -350px;left: 500px;width: 100px;height: 130px;" src="logo.png"/>
"module">
"list1">技能清单
"block">
熟悉XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
熟悉XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
熟悉XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
熟悉XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
熟悉XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
熟悉XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
熟悉XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
熟悉XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
熟悉XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
熟悉XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
熟悉XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
"module">
"list1">工作经历
"block">
XXX技术有限公司/Java开发工程师/2018.01 - 至今
参与多个项目开发、测试、部署等工作,包括:
1、XXX。
2、XXX。
3、XXX。
"module">
"list1">项目经历
"block">
"list2">项目1
"block1">
项目名称:XXX(2020-11 —2021-11)
项目介绍:XXXXXXXXXXXXXXX。
技术架构:XXX + XXX + XXX。
职责描述:
1、XXXX。
2、XXXX。
3、XXXX。
4、XXXX。
"list2">项目2
"block1">
项目名称:XXX(2020-11 —2021-11)
项目介绍:XXXXXXXXXXXXXXX。
技术架构:SpringBoot + Vue + Element-UI + ECharts。
职责描述:
1、XXXX。
2、XXXX。
3、XXXX。
4、XXXX。
"module">
"list1">自我评价
"block">
1、XXXX;
2、XXXX;
3、XXXX;
生成的PDF
后记
不管是前端生成PDF,还是后端生成PDF,能实现需求就是好技术!
作者 | huanzi-qch
来源 | cnblogs.com/huanzi-qch/p/15540276.html
加锋哥微信: java3459 围观锋哥朋友圈,每天推送Java干货!