添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
勤奋的柿子  ·  Removing named ...·  2 月前    · 
胡子拉碴的饼干  ·  ImageModel QML Type | ...·  2 月前    · 
爱搭讪的烤面包  ·  Explicit interface ...·  3 月前    · 
帅气的毛衣  ·  vue elementUI ...·  4 月前    · 

在电商、金融等场景中,经常需要把一些合同、账单等生成PDF文件,相比使用一些PDF的类库直接进行创建和生成,使用html进行转换有以下两个优点:

  • 样式美观,可以通过熟悉的html和css直接生成相对整齐美观的样式
  • 后期修改和维护简单,html的生成可以使用freemarker等模板引擎,做到数据和样式的分离

下面的方式为面向普通内部项目免费合规的使用方式,iText(>=5.0)及需要其他商业授权的方案不在考虑范围。

核心类库

FlyingSaucer ( https://github.com/flyingsaucerproject/flyingsaucer ))

支持输入XML/XHtml + CSS2.1,除转换为PDF外,还支持转换为图片等其他格式。生成PDF支持选择使用不同的类库,这里选择openpdf(基于iText4版本,授权协议为LGPL和MPL)。

准备工作

  1. maven依赖
<dependency>
    <groupId>org.xhtmlrenderer</groupId>
    <artifactId>flying-saucer-pdf-openpdf</artifactId>
    <version>9.1.22</version>
</dependency>

因为flyingsaucer只接受xml/xhtml,所以如果不能确保html内容严格遵守xml或者xhtml,需要使用JSoup或者JTidy进行解析和转化。

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.15.4</version>
</dependency>

或者

<dependency>
    <groupId>com.github.jtidy</groupId>
    <artifactId>jtidy</artifactId>
    <version>1.0.3</version>
</dependency>

2. 需要转换html的文件

src/main/resources/doc.html:

注意:样式中设置的字体名称(font-family),需要与实际字体一致。

<html>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <style>
        body{
            font-family: MiSans;
    </style>
</head>
<body style="text-align: center">
<h1>订单信息</h1>
<table align="center">
    <tr><td>订单号</td> <td>金额</td></tr>
    <tr><td>200323323344</td><td>1004.32</td></tr>
    <tr><td>200323323345</td><td>1004.32</td></tr>
</table>
</body>
</html>

3.  中文字体

这里使用小米的可以免费商用的MiSans( 下载地址

解压后,复制MiSans-Regular.ttf到 src/main/resources 下。

代码实现

1.  转换普通html到xhtml。

因为FlyingSaucer只支持xml和xhtml,而我们的html一般不会完全遵守xhtml,所以先进行格式转换。

使用JTidy

    public static String convertHtmlToXhtmlUsingJTidy(String html){
        Tidy tidy = new Tidy();
        tidy.setXHTML(true);
        tidy.setQuiet(true);
        tidy.setShowWarnings(false);
        StringWriter stringWriter =new StringWriter();
        tidy.parse(new StringReader(html), stringWriter);
        return stringWriter.toString();
    }

也可以使用Jsoup

    public static String convertHtmlToXHtmlUsingJsoup(String html){
        Document doc = Jsoup.parse(html);
        doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml);
        return doc.html();
    }

2. 转换xhtml到PDF

在这里指定了使用的中文字体,输入为格式化后的xhtml,输出PDF格式的byte数组。

public static byte[] convertHtmlToPDFData(String xhtml) throws IOException {
        ITextRenderer renderer = new ITextRenderer();
        renderer.getFontResolver().addFont("/MiSans-Regular.ttf", BaseFont.IDENTITY_H,true);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        renderer.setDocumentFromString(xhtml);
        renderer.layout();
        renderer.createPDF(outputStream);
        return outputStream.toByteArray();
    }

3. 把html文件保存生成到一个pdf文件。

        String htmlFileName = "/doc.html";
        String pdfFileName = "result.pdf";
        String html = IOUtils.resourceToString(htmlFileName, StandardCharsets.UTF_8);
        String xhtml = HtmlUtils.convertHtmlToXhtmlUsingJTidy(html);
        byte[] pdfData = convertHtmlToPDFData(xhtml);
        FileUtils.writeByteArrayToFile(new File(pdfFileName), pdfData);

文件效果预览:

补充说明

  1. 包含以上功能的完整代码示例: https://gitee.com/maceve_demo/html2pdf , 有问题可以随时 创建issue
  2. 在添加字体时,也可以使用指定的字体名称覆盖字体原来的名称,便于在html中指定字体,具体可以参考ITextRenderer.addFont的其他签名方法。