前言

  1. 项目背景:还是帮助老师做了一个项目,然后有一个功能,从ES中拿到数据,导出到PDF中,之前没有做过导出PDF,所以通过网上五花八门的资料学习,决定整合 itextpdf(也成为itext,4版本之前itext,之后就是itextpdf)来导出PDF,这里也做了一下记录,以便后续使用。
  2. itextpdf 官网:https://itextpdf.com/
  3. 5.x 版本的 api文档:https://itextpdf.com/resources/api-documentation/itext-5-java
  4. 7.x 版本的 api文档:https://itextpdf.com/resources/api-documentation/itext-7-java

一、java 导出PDF 的几个工具

从知乎上,找到下面这张照片,从点击次数可以看出,itext 处于首位,使用最多,依次是PDF Box、 JasperReports。剩下的就没有太过于了解了
在这里插入图片描述

1. PDF Box

  1. 官网:没有找到,有知道的朋友可以留言补上,感激
  2. 学习文档:http://www.vue5.com/pdfbox/pdfbox_quick_guide.html
  3. maven依赖:http://www.vue5.com/pdfbox/pdfbox_environment.html 最下面就是

看学习文档的最左边发现,box的功能有点局限性,主要亮点 是分析、读取PDF,于我自己的需求(写入HTML)不大匹配,也是轻量级的,就pass掉了。
但后来需求有改动,写入文本,也是可以考虑的,但就就没有探索了。

2. JasperReports/jFreeReport导出 报表 PDF

  1. 请注意:JasperReport 和 jFreeReport 是两个开源工具
  2. JasperReports官网:https://community.jaspersoft.com/project/jasperreports-library
  3. jFreeReport官网:https://java-source.net/open-source/pdf-libraries/jfreereport
  4. 学习文档:
  5. maven 依赖:看下面的博文

这个工具的最大的优点是写入报表到PDF中,也是很好的工具,但不适合我的需求,但在找资料的时候,也找到了一些不错的博文,放在下面以便学习

  1. 介绍itext 和JasperReports(主要)
  2. JFreeReport- Java报表工具
  3. JasperReport和jFreeReport的比较

3. itextpdf 导出PDF(敲重点)

这个工具是我本次需要所选择的工具,也是重点所讲的工具

  1. 官网:itextpdf 官网:https://itextpdf.com/
  2. 历史版本区别:网上能看到很多资料,一会儿itext,一会儿itextpdf,为啥嘞,接着看:
    itext.jar-(0.99-4.2.2)是旧版本,itextpdf.jar-(5.0以后的)是新版本,现在更是推出了7.x版本;两个是同一个东西,新版只不过某些api变了,学习成本没增加多少,网上一搜一大把新版的api使用,以前旧的系统类似EJB系统大部分用的itext.jar,现在新的系统比如用spring搭起来的系统用的都是itextpdf.jar
  3. 5.x 学习文档
  4. 7.x 学习文档

从网上找了几个基础入门的博文链接,写的也不错,放下面啦

  1. https://blog.csdn.net/qq_26296197/article/details/79348081
  2. Itextpdf5 基础知识:https://blog.csdn.net/qq_39181568/article/details/80003903
  3. Itextpdf5 基础知识:https://blog.csdn.net/weixin_43164309/article/details/120068686

二、springboot整合itextpdf

  1. springboot项目直接创建即可
  2. 导入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>
    
  3. 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;
    }
  1. 浏览器请求http://localhost:8084/pdf/createPdfSaveFile,如下:
    在这里插入图片描述
  2. 资源管理器
    在这里插入图片描述
  3. 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";
    }
  1. 请求:http://localhost:8084/pdf/createPdfDownload
  2. 结果:
    在这里插入图片描述
  3. 内容:
    在这里插入图片描述

四、基础知识学习

这里没时间写啦,可以看2.3中的其他博主的博文,也写的挺好。

itextpdf 到处pdf 创建下载链接:https://blog.csdn.net/man_18483633325/article/details/116988895

使用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

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐