准备工作:
1、maven工程引入selenium-firefox-driver。当然也可以引入selenium-java,jar包更全一点。
另外引入jsoup和flying-saucer-pdf-itext5。做为格式化html和html转pdf
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-firefox-driver</artifactId>
<version>3.141.59</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-itext5</artifactId>
<version>9.1.20</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
2、电脑安装firefox浏览器和下载firefox驱动geckodriver.exe。以windows系统为例,在代码中设置两个可执行程序的环境变量。为了解决中文乱码,把字体包放到资源文件中。我们使用宋体。
System.setProperty("webdriver.firefox.bin", "D:\\Program Files\\Mozilla Firefox\\firefox.exe");
System.setProperty("webdriver.gecko.driver", "D:\\Program Files\\Mozilla Firefox\\geckodriver.exe");
3、html页面中的echarts图表中,一定设置关闭动画,一定设置关闭动画,一定设置关闭动画---animation : false。同时。在把生成的图表生成base64的图片,同时关闭图片工具栏的显示。
由于html转pdf的时候。需要指定中文字体。不然会出现中文乱码。我们以宋体为例。在css样式中指定全文的中文字体为宋体。
var imgObj = new Image();
imgObj.src = myChart.getDataURL({type:'png',excludeComponents:['toolbox']});
document.getElementById("container").innerHTML = '<img src="'+ imgObj.src + '"/>';
css设置字体
<style type="text/css">
* {
font-family: SimSun;
margin: 0;
padding: 0;
}
</style>
4、Talk is cheap. Show me the code
public class PDFGenerator {
public static void topdf(String content, String path) throws DocumentException, IOException {
ITextRenderer renderer = new ITextRenderer();
ITextFontResolver fontResolver = renderer.getFontResolver();
fontResolver.addFont("font/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
renderer.setScaleToFit(true);
renderer.setDocumentFromString(content);
renderer.layout();
renderer.createPDF(new FileOutputStream(new File(path)));
}
}
@RequestMapping("/echart")
public String echart(HttpServletRequest request) {
return "view/echart";
}
@RequestMapping(value = "/view")
@ResponseBody
public Map<String, Object> view(HttpServletRequest request, HttpServletResponse response) {
Map<String, Object> result = new HashMap<>(4);
System.setProperty("webdriver.firefox.bin", "D:\\Program Files\\Mozilla Firefox\\firefox.exe");
System.setProperty("webdriver.gecko.driver", "D:\\Program Files\\Mozilla Firefox\\geckodriver.exe");
String path = request.getContextPath();
String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/index/echart";
FirefoxOptions option = new FirefoxOptions();
option.setHeadless(true); // 无界面浏览器
WebDriver webDriver = new FirefoxDriver(option);
webDriver.manage().deleteAllCookies(); // 删除cookies
webDriver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
webDriver.get(url); // 打开echarts页面
String res = webDriver.getPageSource();
Document html = Jsoup.parse(res);
html.outputSettings().syntax(Syntax.xml); // 用jsoup格式化html代码,以防止标签没有关闭导致的转换报错。
String filePath = "d:/" + UUID.randomUUID() + ".pdf";
try {
PDFGenerator.topdf(html.toString(), filePath);
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
webDriver.close();
}
result.put("path", filePath);
return result;
}
5、最后效果图
6、项目还可以改造。把生成的pdf直接上传到文件服务器,以减少每次都生成pdf的漫长等待。如果不想使用本地的webdriver,可以考虑使用docker安装RemoteWebDriver,配置一个webdriver.url: http://*.*.*.*:4444/wd/hub.
如下所示
WebDriver driver = null;
try {
DesiredCapabilities capabilities = DesiredCapabilities.chrome();
capabilities.setCapability("headless", true);
driver = new RemoteWebDriver(new URL(webdriver.url), capabilities);
driver.manage().deleteAllCookies();
} catch (MalformedURLException e) {
e.printStackTrace();
}