前言
- 项目背景:还是帮助老师做了一个项目,然后有一个功能,从ES中拿到数据,导出到PDF中,之前没有做过导出PDF,所以通过网上五花八门的资料学习,决定整合
itextpdf
(也成为itext,4版本之前itext,之后就是itextpdf)来导出PDF,这里也做了一下记录,以便后续使用。 - itextpdf 官网:https://itextpdf.com/
- 5.x 版本的 api文档:https://itextpdf.com/resources/api-documentation/itext-5-java
- 7.x 版本的 api文档:https://itextpdf.com/resources/api-documentation/itext-7-java
一、java 导出PDF 的几个工具
从知乎上,找到下面这张照片,从点击次数可以看出,itext 处于首位,使用最多,依次是PDF Box、 JasperReports。剩下的就没有太过于了解了
1. PDF Box
- 官网:没有找到,有知道的朋友可以留言补上,感激
- 学习文档:
http://www.vue5.com/pdfbox/pdfbox_quick_guide.html
- maven依赖:
http://www.vue5.com/pdfbox/pdfbox_environment.html
最下面就是
看学习文档的最左边发现,box的功能有点局限性,主要亮点 是分析、读取PDF,于我自己的需求(写入HTML)不大匹配,也是轻量级的,就pass掉了。
但后来需求有改动,写入文本,也是可以考虑的,但就就没有探索了。
2. JasperReports/jFreeReport导出 报表 PDF
请注意:JasperReport 和 jFreeReport 是两个开源工具
- JasperReports官网:
https://community.jaspersoft.com/project/jasperreports-library
- jFreeReport官网:
https://java-source.net/open-source/pdf-libraries/jfreereport
- 学习文档:
- maven 依赖:看下面的博文
这个工具的最大的优点是写入报表到PDF中,也是很好的工具,但不适合我的需求,但在找资料的时候,也找到了一些不错的博文,放在下面以便学习
3. itextpdf 导出PDF(敲重点)
这个工具是我本次需要所选择的工具,也是重点所讲的工具
- 官网:itextpdf 官网:https://itextpdf.com/
- 历史版本区别:网上能看到很多资料,一会儿itext,一会儿itextpdf,为啥嘞,接着看:
itext.jar-(0.99-4.2.2)
是旧版本,itextpdf.jar-(5.0以后的)
是新版本,现在更是推出了7.x版本;两个是同一个东西,新版只不过某些api变了,学习成本没增加多少,网上一搜一大把新版的api使用,以前旧的系统类似EJB系统大部分用的itext.jar,现在新的系统比如用spring搭起来的系统用的都是itextpdf.jar - 5.x 学习文档
- 7.x 学习文档
从网上找了几个基础入门的博文链接,写的也不错,放下面啦
- https://blog.csdn.net/qq_26296197/article/details/79348081
- Itextpdf5 基础知识:https://blog.csdn.net/qq_39181568/article/details/80003903
- Itextpdf5 基础知识:https://blog.csdn.net/weixin_43164309/article/details/120068686
二、springboot整合itextpdf
- springboot项目直接创建即可
导入maven依赖```
<!--生成pdf--> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.11</version> </dependency> <!--中文字体--> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency> <!--html xml 转为pdf--> <dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.5.11</version> </dependency>
```
springboot整合itextpdf 到此结束,接下来就是学习和导出PDF啦
三、两个案例
两个接口可以直接使用
1. 写入HTML到PDF需要自定义工具类
package com.example.demo_fengfanli.utils;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.tool.xml.ElementList;
import com.itextpdf.tool.xml.XMLWorker;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.itextpdf.tool.xml.css.CssFile;
import com.itextpdf.tool.xml.css.StyleAttrCSSResolver;
import com.itextpdf.tool.xml.html.CssAppliers;
import com.itextpdf.tool.xml.html.CssAppliersImpl;
import com.itextpdf.tool.xml.html.Tags;
import com.itextpdf.tool.xml.parser.XMLParser;
import com.itextpdf.tool.xml.pipeline.css.CSSResolver;
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline;
import com.itextpdf.tool.xml.pipeline.end.ElementHandlerPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class MyXMLWorkerHelper {
public static class MyFontsProvider extends XMLWorkerFontProvider {
public MyFontsProvider() {
super(null, null);
}
@Override
public Font getFont(final String fontname, String encoding, float size, final int style) {
try {
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);//中文字体
return new Font(bfChinese, size, style);
} catch (Exception ex) {
return new Font(Font.FontFamily.UNDEFINED, size, style);
}
}
}
public static ElementList parseToElementList(String html, String css) throws IOException {
// CSS
CSSResolver cssResolver = new StyleAttrCSSResolver();
if (css != null) {
CssFile cssFile = XMLWorkerHelper.getCSS(new ByteArrayInputStream(css.getBytes()));
cssResolver.addCss(cssFile);
}
// HTML
MyFontsProvider fontProvider = new MyFontsProvider();
CssAppliers cssAppliers = new CssAppliersImpl(fontProvider);
HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
htmlContext.autoBookmark(false);
// Pipelines
ElementList elements = new ElementList();
ElementHandlerPipeline end = new ElementHandlerPipeline(elements, null);
HtmlPipeline htmlPipeline = new HtmlPipeline(htmlContext, end);
CssResolverPipeline cssPipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
// XML Worker
XMLWorker worker = new XMLWorker(cssPipeline, true);
XMLParser p = new XMLParser(worker);
html = html.replace("<br>", "<br/>").replace("<hr>", "<hr/>").replace("<img>", "").replace("<param>", "").replace("<link>", "");//不支持单独标签
p.parse(new ByteArrayInputStream(html.getBytes()));
return elements;
}
}
2. html 写入pdf 到本地
这个就是将生成的PDF直接放到了
@GetMapping("/createPdfSaveFile")
public String createPdfSaveFile(){
String path = "d:\\upload\\textffff.pdf";
try {
// 判断路径中文件夹是否存在,不存在则自动创建,防止因为文件夹不存在而报错
creatNewFile(path);
// 创建文档
Document document = new Document(PageSize.A4,60,60,15,40);
// 创建输入流
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(path));
document.open();
// 制作大文本数据
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i <= 100; i++){
stringBuilder.append("如果说荷兰是橙色的,那阿姆斯特丹就是缤纷的彩色。");
}
// 添加数据
String pocketDescription = "<html><body><p class=\"\" style=\"\">如果说荷兰是橙色的,那阿姆斯特丹就是缤纷的彩色。"+stringBuilder.toString()+"</p> <p class=\"\" style=\"\"><strong>游玩建议</strong><br>游玩整个阿姆斯特丹大约需2-3天</p></body></html>";
Paragraph context = new Paragraph();
// html 的处理
ElementList elementList = MyXMLWorkerHelper.parseToElementList(pocketDescription, null);
// 写入到 段落 Paragraph
for (Element element : elementList) {
context.add(element);
}
context.setSpacingBefore(10f);
document.add(context);
document.close();
writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (DocumentException e) {
throw new RuntimeException(e);
}
return "ok";
}
/**
* 检查是否存在文件夹并创建
*
* @param path
* @throws IOException
*/
public static File creatNewFile(String path) throws IOException {
File file = new File(path);
File fileParent = file.getParentFile();
if (!fileParent.exists()) {
fileParent.mkdirs();
}
file.createNewFile();
return file;
}
- 浏览器请求
http://localhost:8084/pdf/createPdfSaveFile
,如下: - 资源管理器
- PDF
3. 文本写到PDF下载使用
@GetMapping("/createPdfDownload")
public String createPdfToDownload(HttpServletResponse response) throws IOException {
// 生成 pdf 名称
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = simpleDateFormat.format(date);
String datetime = str.replace("-", "").replace(" ", "").replace(":","");
String filename = "pdf_"+datetime+"_content.pdf";
// 创建PDF
Document document = new Document(PageSize.A4,60,60,15,40);
try {
// 设置响应头,控制浏览器下载该文件
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
//常用的有paragraph段落、phrase语句块、chunk最小单位块
OutputStream out = response.getOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, out);
// 打开文档
document.open();
BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
for(int n = 0; n<2; n++){
// 添加文字水印
PdfContentByte cb = writer.getDirectContent();
cb.beginText(); // 开始
// 设置透明度
PdfGState gs = new PdfGState();
gs.setFillOpacity(0.2f);
cb.setGState(gs);
cb.setFontAndSize(bfChinese,100);
cb.showTextAligned(Element.ALIGN_CENTER, "北京交通大学", 340, 410 , 60);
cb.endText(); // 结束
// 添加标题
//通过Font去设置字体的基本属性:大小,加粗等等
Font font = new Font(bfChinese, 15, Font.NORMAL, BaseColor.BLACK);
// 创建段落
Paragraph title = new Paragraph("我是 title ", font);
title.setAlignment(Element.ALIGN_CENTER);
title.setSpacingBefore(40f);
document.add(title);
// 制作大文本数据
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i <= 100; i++){
stringBuilder.append("如果说荷兰是橙色的,那阿姆斯特丹就是缤纷的彩色。");
}
Font font1 = new Font(bfChinese, 10, Font.NORMAL, BaseColor.BLACK);
Paragraph context = new Paragraph(stringBuilder.toString(), font1);
context.setFirstLineIndent(20);
context.setLeading(12);
context.setSpacingBefore(10f);
document.add(context);
// 开启新的一页
document.newPage();
//显示空内容的页
writer.setPageEmpty(false);
}
// 关闭流
document.close();
writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (DocumentException e) {
throw new RuntimeException(e);
}
return "ok";
}
- 请求:
http://localhost:8084/pdf/createPdfDownload
- 结果:
- 内容:
四、基础知识学习
这里没时间写啦,可以看2.3中的其他博主的博文,也写的挺好。
使用itex生成pdf文件并下载总结:https://blog.csdn.net/qxy15997826736/article/details/125585884
itextpdf 写入 html
:
http://t.zoukankan.com/mvilplss-p-5646675.html
https://blog.csdn.net/lingbo89/article/details/76187582