需求
后端批量导出一些个人评价报告的PDF,要和前端页面展示的报告格式一样。几个点:
1)渲染页面数据;
2) 后端需要渲染echarts图片;
3)需要导出PDF
解决方案
使用thymeleaf模板+phantomjs
思路是提供一个接口,用thymeleaf模板渲染数据,然后利用phantomjs 访问这个接口,将页面渲染成pdf,但是这样批量导出的效率不知好不好
使用thymeleaf生成静态文件,发给phantomjs渲染
这样需要设置好js的路径,需要额外生成文件发给phantomjs渲染,类似下面的例子
public class EchartsConvertUtils { // thymeleaf 渲染 html 引擎 private final static TemplateEngine templateEngine = new TemplateEngine(); // 无头浏览器驱动 private static PhantomJSDriver webDriver; static { try { webDriver = getPhantomJs(); } catch (Exception e) { e.printStackTrace(); } } /** * 使用 Thymeleaf 渲染 HTML * @param template HTML模板 * @param params 参数 * @return 渲染后的HTML */ public static String render(String template, Map params){ Context context = new Context(); context.setVariables(params); return templateEngine.process(template, context); } /** * 获取字符串格式的模板 * @param filePath * @return */ public static String getHtmlString(String filePath){ return FileUtil.readString(filePath,"UTF-8"); } /** * 获取 无界面浏览器路径,这里需要区分linux 还是 windows * @return */ private static String getPhantomJsPath() { String path = ""; //System.getProperty("phantomjs.binary.path"); if (path == null || "".endsWith(path)) { return "/usr/bin/phantomjs"; } else { return path; } } private static PhantomJSDriver getPhantomJs() { //设置必要参数 DesiredCapabilities dcaps = new DesiredCapabilities(); //ssl证书支持 dcaps.setCapability("acceptSslCerts", true); //截屏支持 dcaps.setCapability("takesScreenshot", true); //css搜索支持 dcaps.setCapability("cssSelectorsEnabled", true); //js支持 dcaps.setJavascriptEnabled(true); //驱动支持(第二参数表明的是你的phantomjs引擎所在的路径,which/whereis phantomjs可以查看) // fixme 这里写了执行, 可以考虑判断系统是否有安装,并获取对应的路径 or 开放出来指定路径 dcaps.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, getPhantomJsPath()); //创建无界面浏览器对象 return new PhantomJSDriver(dcaps); } /** * 将html 渲染为图片文件 * @param url * @return * @throws IOException */ public static BufferedImage renderHtml2Image(String url) throws IOException { if (webDriver != null) { webDriver.get(url); File file = webDriver.getScreenshotAs(OutputType.FILE); return ImageIO.read(file); } else { return null; } } /** * 将图片流写入到图片文件 * @param bi * @throws IOException */ public static void writeImageFile(BufferedImage bi,String filePath) throws IOException { File outputfile = new File(filePath+"saved.png"); ImageIO.write(bi, "png", outputfile); } public static String getProjectPath(){ String path = ClassUtils.getDefaultClassLoader().getResource("").getPath(); return path+"/templates/"; } /** * 以下是整个流程 */ public static void echartsConvert(String templatePath,Map params,String filePath){ // 首先加载模板引擎进行渲染 String html=render(getHtmlString(templatePath),params); // 将html写入文件,要必去能和js文件放到一起,这样才嫩保证PhantomJS 加载html 的时候找到 js String filename=filePath+UUID.randomUUID().toString().substring(0, 8); File file=new File(filename+".html"); FileUtil.writeString(html,file,"UTF-8"); BufferedImage img = null; try { for (int i = 0; i < 20; ++i) { long start = System.currentTimeMillis(); img = renderHtml2Image(filename+".html"); long end = System.currentTimeMillis(); System.out.println("cost: " + (end - start)); } writeImageFile(img,filename); System.out.println(Base64Util.encode(img, "png")); FileUtil.del(file); } catch (IOException e) { e.printStackTrace(); } }