【问题标题】:Preprocessing HTML CSS JS for iText为 iText 预处理 HTML CSS JS
【发布时间】:2018-11-28 20:27:49
【问题描述】:

我正在尝试使用嵌入在 Java 代码中的 iText 将使用 HTML/CSS/JS 构建的网页转换为 PDF。然而,iText 告诉我们,虽然 pdfHTML 支持 CSS,但它不支持 JS。他们建议使用预处理器来“运行”页面中的 Javascript 并取回原始 HTML。

没有 Javascript,iText 可以很好地生成 PDF。但是,我们需要能够将来自服务调用的数据注入 HTML。我使用 JQuery 来实现这一点。我们也在调用和使用 FusionCharts API 来渲染一些图表。在 PDF 生成之前,这些也一直有效。

有人知道这样的事情吗?它也需要能够从我们的 Java 后端调用。

谢谢!

【问题讨论】:

    标签: javascript java itext7


    【解决方案1】:

    有几种方法可以评估 HTML + CSS + JS 页面上的 JS 代码。为此,我们需要一个类似浏览器(或浏览器本身),因为使用 DOM 操作评估 JS 正是浏览器在呈现页面之前必须做的。

    选项 1

    使用HtmlUnit - “Java 程序的无 GUI 浏览器”。

    首先,我们需要添加依赖项(例如通过 Maven):

    <dependency>
      <groupId>net.sourceforge.htmlunit</groupId>
      <artifactId>htmlunit</artifactId>
      <version>2.32</version>
    </dependency>
    

    然后,打开页面,等待 JS 完成它的工作并将页面源提供给 iText pdfHTML:

    WebClient webClient = new WebClient();
    // You might need this configuration if HtmlUnit fails without it
    webClient.getOptions().setThrowExceptionOnScriptError(false);
    webClient.waitForBackgroundJavaScript(10 * 1000);
    HtmlPage page = webClient.getPage(url);
    String xml = page.asXml();
    
    ConverterProperties properties = new ConverterProperties().setBaseUri(url);
    HtmlConverter.convertToPdf(source, new PdfWriter("result.pdf"), properties);
    

    HtmlUnit 不完全支持 JS,因此在评估 JS 代码时可能会抛出错误。因此,您可能想要抑制它们(我已将此配置和关于它的注释添加到代码示例中)。当然,您的结果可能看起来不正确。但这是纯 Java 解决方案。

    选项 2

    向我们每天使用的现实世界浏览器寻求帮助

    我们每天使用的浏览器(Chrome、Firefox、Safari 等)对 JS 评估有最好的支持。您可以使用浏览器引擎,例如Selenium 网络自动化工具。我们要做的是在浏览器中打开一个页面,等待页面加载,然后使用源代码进行 HTML -> PDF 转换。我的示例适用于 Chrome,但您可以以类似的方式对其他浏览器执行此操作。首先,您需要 download 一个 Chrome 驱动程序并将其解压到您系统的某个位置。

    然后添加以下 Maven 依赖项:

    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-chrome-driver</artifactId>
      <version>3.14.0</version>
    </dependency>
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>3.14.0</version>
    </dependency>
    

    现在我们要写一些代码,类似于第一个选项:

    System.setProperty("webdriver.chrome.driver", "C:\\path\\to\\chromedriver.exe");
    ChromeDriver driver = new ChromeDriver();
    driver.get(url);
    new WebDriverWait(driver, 20).until(
            webDriver -> ((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete"));
    String source = driver.getPageSource();
    driver.close();
    
    ConverterProperties properties = new ConverterProperties().setBaseUri(url);
    HtmlConverter.convertToPdf(source, new PdfWriter("result.pdf"), properties);
    

    这个选项可能会慢一些,并且有更多的先决条件(浏览器、驱动程序),但它保证了防弹 JS 支持。

    【讨论】:

    • 哇,这是一个很棒的评论。感谢您花时间做这一切。我将在这周实施它,看看我是否可以让它工作,但这绝对是一个答案,所以我会接受它!
    • 是的,带有 Chrome 驱动程序的 Selenium 被证明是解决我们特定问题的最佳答案。再次感谢@Alexey
    猜你喜欢
    • 1970-01-01
    • 2011-07-24
    • 2014-11-04
    • 1970-01-01
    • 1970-01-01
    • 2015-10-05
    • 1970-01-01
    • 2013-03-18
    • 1970-01-01
    相关资源
    最近更新 更多