登录
    Technology changes quickly but people's minds change slowly.

后端生成pdf报告的解决方案探讨

技术宅 破玉 562次浏览 0个评论

需求

  后端批量导出一些个人评价报告的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();
        }
    }

华裳绕指柔, 版权所有丨如未注明 , 均为原创|转载请注明后端生成pdf报告的解决方案探讨
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址