为iText预处理HTML CSS JS

时间:2018-11-28 20:27:50

标签: javascript java itext7

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

没有Javascript,iText可以很好地生成PDF。但是,我们需要能够将来自服务调用的数据注入HTML。我使用JQuery完成此任务。我们还调用并使用FusionCharts API渲染一些图表。这些也将一直工作到生成PDF。

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

谢谢!

1 个答案:

答案 0 :(得分: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支持。