報表開發神器:phantomjs生成PDF ,Echarts圖片,自動生成word文檔實戰

報表開發神器:phantomjs生成網頁PDF ,Echarts報表實戰

一. 關於phantomjs

1.1 什麼是phantomjs?

(1)一個基於webkit內核的無頭瀏覽器,即沒有UI界面,即它就是一個瀏覽器,只是其內的點擊、翻頁等人爲相關操作需要程序設計實現。
(2)提供javascript API接口,即通過編寫js程序可以直接與webkit內核交互,在此之上可以結合java語言等,通過java調用js等相關操作,從而解決了以前c/c++才能比較好的基於webkit開發優質採集器的限制。
(3)提供windows、linux、mac等不同os的安裝使用包,也就是說可以在不同平臺上二次開發採集項目或是自動項目測試等工作。

1.2 phantomjs常用API介紹

  1. 常用內置幾大對象

    • var system=require(‘system’); //獲得系統操作對象,包括命令行參數、phantomjs系統設置等信息
    • var page = require(‘webpage’); //獲取操作dom或web網頁的對象,通過它可以打開網頁、接收網頁內容、request、response參數,其爲最核心對象。
    • var fs = require(‘fs’); //獲取文件系統對象,通過它可以操作操作系統的文件操作,包括read、write、move、copy、delete等。
  2. 常用API

    • page.onLoadStarted = function() {}//當page.open調用時,回首先執行該函數,在此可以預置一些參數或函數,用於後邊的回調函數中
    • page.onResourceError = function(resourceError) {} //page的所要加載的資源在加載過程中,出現了各種失敗,則在此回調處理
    • page.onResourceRequested = function(requestData, networkRequest) {} //page的所要加載的資源在發起請求時,都可以回調該函數
    • page.onResourceReceived = function(response) {} //page的所要加載的資源在加載過程中,每加載一個相關資源,都會在此先做出響應,它相當於http頭部分, 其核心回調對象爲response,可以在此獲取本次請求的cookies、userAgent等
    • page.onConsoleMessage = function (msg) {}//欲在執行web網頁時,打印一些輸出信息到控制檯,則可以在此回調顯示。
    • page.onAlert = function(msg) {} //phantomjs是沒有界面的,所以對alert也是無法直接彈出的,故phantomjs以該函數回調在page在執行過程中的alert事件
    • page.onError = function(msg, trace) {} //當page.open中的url,它自己(不包括所引起的其它的加載資源)出現了異常,如404、no route to web site等,都會在此回調顯示。
    • page.onUrlChanged = function(targetUrl) {} // 當page.open打開的url或是該url在打開過程中基於該URL進行了跳轉,則可在此函數中回調。
    • page.onLoadFinished = function(status){} // 當page.open的目標URL被真正打開後,會在調用open的回調函數前調用該函數,在此可以進行內部的翻頁等操作
    • page.evaluate(function(){});// 在所加載的web page內部執行該函數,像翻頁、點擊、滑動等,均可在此中執行
    • page.render("");//將當前page的現狀渲染成圖片,輸出到指定的文件中去。
  3. 注意事項

    • 區分phantomjs的對象和打開的web page的對象,如document、window等,兩者都有,在調用page.evaluate和不調用的時候,注意區分二者的範圍,容易在調試時出現很多的問題,且不好發現。

    • page.injectJs和page.includeJs的區別,前者側重本地的js文件,與libraryPath掛購,後者側重網絡js文件,尤其在引入jquery等第三方庫時,會經常遇到。

    • 編碼問題,兩個重要參數,–output-encoding,–script-encoding,前者爲輸出編碼,後者爲所使用js、參數配置文件的編碼,爲方便起鑑,建議均採用utf-8編碼,並注所應用到的目標文件的編碼,以免引起很不可思議的異常,又無從查起。

  4. 使用總結 : 主要是java se+js+phantomjs的應用,

    • 編寫好js腳文程序,預留出所有可配置參數,並提供json文件傳輸相關參數。

    • 通過java程序,定義相關參數並生成對應的json文件。

    • 通過java命令行調用API,調用phantomjs命令,並傳入js、配置文件路徑,從而開啓爬蟲。

    • 首先採集關鍵詞的搜索頁的鏈接集合,最後統一去遍歷採集具體的對象網頁。

1.3 使用phantomjs 能做什麼?

  • 能夠通過網頁url,獲取到此網頁的數據,進行數據採集,網站爬取;
  • 在本人實戰中,通過 phantomjs 和數據 生成圖表,如下:
    在這裏插入圖片描述
  • 在本人實戰中,可通過 phantomjs 截圖網頁頁面,並且生成樣式一模一樣的PDF文件,如下:
    在這裏插入圖片描述

生成的PDF基本還原了其原來的樣式,圖片和文字分開了,並非直接截圖;有生成PDF相關需求的,可以思考生成使用phantomjs 如何實現功能;本人有通過Html模板,生成Html頁面,然後將此頁面上傳至FastDfs服務器,然後通過返回的url直接生成此pdf,即完成了html頁面一致的pdf生成功能;

  • 在接下來的文檔中,本人將會詳細介紹如何使用 phantomjs 生成pdf 以及報表相關的圖片功能;

二. Windows下安裝 phantomjs

2.1 概述

  • Windows下安裝phantomjs比較簡單。(目前官方支持三種操作系統,包括Windows\Mac OS\Linux這三大主流的環境,根據自己的運行環境選擇要下載的包進行下載)
  • 總結來講就是 下載後解壓phantomjs配置環境變量

2.1 下載並安裝phantomjs

  • 進入官網,選擇自身電腦系統對應版本下載 官網地址
  • 下載好後,進入文件的bin 目錄,複製文件路徑,開始準備配置環境變量
  • 鼠標右擊__我的電腦__選擇 高級系統設置__然後點擊環境變量,再然後選擇__系統變量,點擊Path,將phantomjs的bin文件夾所在路徑添加至環境變量;如圖所示:
    • 在這裏插入圖片描述
  • 測試是否安裝成功:
    • 打開cmd 輸入phantomjs -v 顯示當前版本號,若顯示版本號則表示安裝成功!
    • 如圖所示:
      • 在這裏插入圖片描述

三. Linux下 安裝 phantomjs

3.1 概述

  • Linux下安裝有三個過程:1. 安裝 2.配置環境變量 3. 解決中文亂碼(生成圖片時可能會圖片內的中文亂碼)

3.2 安裝過程如下:

  • 依次執行以下命令:

       wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
    
       yum install bzip2 # 安裝bzip2
    
       tar -jxvf phantomjs-2.1.1-linux-x86_64.tar.bz2
    
       mv phantomjs-2.1.1-linux-x86_64 /usr/local/src/phantomjs
    
       ln -sf /usr/local/src/phantomjs/bin/phantomjs /usr/local/bin/phantomjs
    
       yum install fontconfig freetype2
    
       phantomjs -v # 測試版本號
    

    當執行完此命令時,phantomjs已安裝成功。可以開始配置環境變量了。

  • 配置環境變量
    1. 連接至Linux服務器,進入profile文件
      vim /etc/profile
      
    2. 在profile文件的最後一行中,添加安裝路徑path語句(注意路徑是phantomjs的安裝路徑)
      export PATH=${PATH}:/usr/local/src/phantomjs/bin/
      
    3. 如果是超級用戶,則配置:
      export PATH=$PATH:/root/phantomjs/bin
      
    4. 在Linux服務器的任意文件目錄中輸入命令: phantomjs
      • 如果能成功進入phantomjs的界面,則表示配置環境變量成功。成功如圖所示:
        在這裏插入圖片描述

      進入裏面後可執行js命令,如果需要退出,則按 Ctrl+C 強制退出

  • 解決中文亂碼(可選,可遇到此問題再行解決)
    1. 正常示例:(Windows上顯示正常如圖:)
      • 在這裏插入圖片描述
    2. 錯誤示例:(Linux上顯示中文亂碼如圖:)
      • 在這裏插入圖片描述
    3. 解決辦法:
      1. 在Linux中執行命令:
        yum install bitmap-fonts bitmap-fonts-cjk
        

        執行此命令後,可能只是中文顯示出來了,數字還是會顯示空格,如果出現數字顯示空格,則把windows所有字體導入Linux中,見下面。

      2. 導入字體:
        • 將Windows字體全部複製,導入到Linux中。
        • 在/usr/share/fonts/下新建micro文件夾。
        • 將字體全部放入micro中。

四. 利用Phantomjs生成Echarts圖片

4.1 概述:

  • 實現原理:
    • 在Windows下:
      • 在本地電腦中,我們首先安裝Phantomjs在本地電腦上,並配置好環境變量,可參照章節二教程;
      • 準備好 jquery.1.9.1.min.js,echarts-convert.js,echarts.min.js三個文件。
      • 編寫Demo程序,運行主Main方法
    • 在Linux 下:
      • 在Linux系統彙總,我們首先安裝Phantomjs在本地電腦上,並配置好環境變量,可參照章節三教程;
      • 其他操作與在Windows操作類似。

    WIndows與Linux環境下的區別:①配置好環境變量,因爲phantomjs的啓動方式,windows是執行exe文件,linux不是,所以配好環境變量後java在本機測試與在Linux下無需做任何修改;② Phantomjs執行生成Echarts圖片時,需要引用到 jquery.1.9.1.min.js ,echarts-convert.js, echarts.min.js 以及生成Echarts的js文件。這些js需要引用到,而當部署在Linux中時,生成的js文件在jar包中,不一定能讀取到,我們可以通過代碼將js文件複製生成到jar包同級目錄,然後通過路徑加載。路徑加載可以用如下代碼讀取並生成:
    ~~~java
    /* 將模板生成到指定的位置 判斷文件是否存在,如果不存在則創建 */
    File echartsfile = new File(System.getProperty(“user.dir”) + “\echarts-all.js”);
    if (!echartsfile.exists()) {
    FileUtil.file2file(“js/echarts-all.js”, System.getProperty(“user.dir”) + “\echarts-all.js”);
    }
    ~~~

4.2 筆者實現思路:

  • 第一步:寫出核心代碼:
        public static void main(String[] args) throws Exception {
        Runtime rt = Runtime.getRuntime();
        //windows 本地地址
        Process p = rt.exec("phantomjs " +"C:\\Code\\Demo\\echarts-convert.js" + " -infile " + "C:\\Code\\Demo\\Demo1\\src\\main\\resources\\echarts\\optionsjs\\" + "1187559506027646976.js -outfile " + "C:\\Demo\\" + "123.png -scale 0.01 -width 1200");
        InputStream is = p.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        StringBuffer sbf = new StringBuffer();
        String tmp = "";
        while ((tmp = br.readLine()) != null) {
            sbf.append(tmp);
        }
        System.out.println(sbf);
    }
    
  • 相關js文件下載
    • 如圖:
  • 第二步:整理思路:
  1. 生成需要生成的Echarts的js代碼:
    1. 找到相關Echarts圖片模板: Echarts官網
    2. 使用Framework以及其他技術:將模板+數據生成一個最終js文件;
      1. 使用Framework爲例:
        • 導入xml依賴:
            <!-- framework-->
          <dependency>
              <groupId>org.freemarker</groupId>
              <artifactId>freemarker</artifactId>
              <version>2.3.26-incubating</version>
          </dependency>
          
        • 代碼合成最終js文件示例:
          	    // 生成文件
          	    public  void createDocNew(Map<String,Object> map,String templatePath,String templateName,String outFilePath) throws Exception{
          	        try (Writer out=new FileWriter(outFilePath)){
          	            //創建一個配置對象,獲取該對象的版本
          	            Configuration configuration=new Configuration(Configuration.getVersion());
          	            //獲取模板所在目錄
          	            configuration.setDirectoryForTemplateLoading(new File(templatePath));
          	            //設置編碼集
          	            configuration.setDefaultEncoding("utf-8");
          	            //獲取模板對象
          	            Template template=configuration.getTemplate(templateName);
          	            //輸出文件至指定目錄
          	            template.process(map,out);
          	            //關閉流
          	        } catch (Exception e) {
          	            e.printStackTrace();
          	        }
          	    }
          
            > 這裏的代碼就是將map裏存儲的值以及模板地址,和outFilePath的生成地址接收,然後生成出最終的js文件。關於Framework的語法,可以去具體學習,這裏不做贅述;當然也可以使用別的方式或者別的模板生成方式;
          
  2. 將其他的三個js文件放到其他位置上,博主的做法是將這三個放到jar包目錄內,但是會存在phantomjs無法讀取和執行的情況(就是除開phantomjs的代碼可以讀取到內容,但phantomjs的執行無法引用讀取)。所以博主採取的是先讀取出來,再寫到jar包外面進行引用;這樣通過路徑,在Linux下也可以讀取了;讀取代碼示例:
                /*  將模板生成到指定的位置  判斷文件是否存在,如果不存在則創建 */
           File echartsfile = new File(System.getProperty("user.dir") + "\\echarts-all.js");
           if (!echartsfile.exists()) {
               FileUtil.file2file("js/echarts-all.js", System.getProperty("user.dir") + "\\echarts-all.js");
           }
    
           File jsfile = new File(outPathAndName);
           if (!jsfile.exists()) {
               FileUtil.string2File(outPathAndName, echartTemplate.getFileContent());         //  將js文件生成到指定的位置
           }
           File convertfile = new File(System.getProperty("user.dir") + "\\echarts-convert.js");
           String echartsPath = System.getProperty("user.dir") + "\\echarts-convert.js";
           if (!convertfile.exists()) {
               FileUtil.file2file("js/echarts-convert.js", echartsPath);
           }
           File jqueryfile = new File(System.getProperty("user.dir") + "\\jquery.1.9.1.min.js");
           if (!jqueryfile.exists()) {
               FileUtil.file2file("js/jquery.1.9.1.min.js", System.getProperty("user.dir") + "\\jquery.1.9.1.min.js");
           }
    

    重點代碼:System.getProperty(“user.dir”) 爲 Windows下或者Linux下的當前路徑 ,具體可百度其用法。

  3. 結合已經有的 echarts-convert.js 等文件+ 生成好的帶數據的Echarts.js 文件 和 Demo示例代碼可以生成出Echarts圖片了;我們可以將Echart圖片再上傳至Fastdfs等圖片服務器,就可以拿到網絡圖片url了;當然最後一步視業務需求而定;

五. 利用Phantomjs生成PDF文檔(HTML轉爲PDF)

5.1 概述

  • 生成PDF文檔的技術有很多種;使用Phantomjs生成PDF的優點在於:①操作簡單方便 ②生成的PDF質量高,與原來的一致,所見即所得 ③. 免費,無任何隱形廣告
  • 目前博主研究的的是HTML生成PDF,其他的還未研究,不知道是否可行,具體可百度。這裏講的也是將HTML轉爲PDF文檔
  • 示例代碼:
    • 核心示例demo:
          public static String parseHtml2Pdf2(String url) throws IOException {
          Runtime rt = Runtime.getRuntime();
          Process p = rt.exec("C:/App/phantomjs-2.1.1-windows/bin/phantomjs.exe "+  "C:\\Code\\demo\\parsers\\src\\main\\resources\\wordfiles\\js\\jstemplate\\1190147431954702336.js "+url);
          InputStream is = p.getInputStream();
          BufferedReader br = new BufferedReader(new InputStreamReader(is));
          StringBuffer sbf = new StringBuffer();
          String tmp = "";
          while ((tmp = br.readLine()) != null) {
              sbf.append(tmp);
          }
          String resultstr = sbf.toString();
          String[] arr = resultstr.split("\\$");
          String result = "";
          for(String s : arr){
              if(s.endsWith("pdf"))result = s;
          }
          return result;
      }
      
    • js模板(1190147431954702336.js):
      var page = require('webpage').create();
      var system = require('system');
      
      ////讀取命令行參數,也就是js文件路徑。
      if (system.args.length === 1) {
          console.log('Usage: loadspeed.js <some URL>');
      //這行代碼很重要。凡是結束必須調用。否則phantomjs不會停止
          phantom.exit();
      }
      page.settings.loadImages = true;  //加載圖片
      page.settings.resourceTimeout = 30000;//超過10秒放棄加載
      //截圖設置,
      //page.viewportSize = {
      //  width: 1000,
      //  height: 3000
      //};
      var address = system.args[1];
      page.open(address, function(status) {
      
          function checkReadyState() {//等待加載完成將頁面生成pdf
              setTimeout(function () {
                  var readyState = page.evaluate(function () {
                      return document.readyState;
                  });
      
                  if ("complete" === readyState) {
                      page.paperSize = { width:'297mm',height:'500mm',orientation: 'portrait',border: '1cm' };
                      var timestamp = Date.parse(new Date());
                      var outpathstr = 'C:/Demo/parsers/src/main/resources/wordfiles/pdf_file/1189813692544335872.pdf';
                      page.render(outpathstr);
                      //page.render("c://test.png");
                      //console.log就是傳輸回去的內容。
                      console.log("生成成功");
                      console.log("$"+outpathstr+"$");
                      phantom.exit();
                  } else {
                      checkReadyState();
                  }
              },1000);
          }
          checkReadyState();
      });
      

      這裏的 var outpathstr = ‘C:/Demo/parsers/src/main/resources/wordfiles/pdf_file/1189813692544335872.pdf’;需要我們去修改爲實際導出的地址,同時要注意在Linux下的路徑問題;

5.2 生成原理

  • 通過示例demo傳入的url (Html 頁面) + 引入的js內的導出地址(pdf導出地址)+ 示例Demo代碼,即可將html頁面轉換成PDF並保存在指定的地址上;
  • 這裏的pdf是通過 phantomjs(無頭瀏覽器) +加載Html頁面+ 使用phantomjs的截圖功能 然後生成PDF文件;生成的pdf文件無損 且與真實PDF一致,質量很高;

5.3 擴展思路

  • 雖然生成pdf是通過Html進行轉換的;當我們只需要pdf,不需要html的時候,也可以通過這種簡接的方式生成pdf,最後把html刪掉就可以啦;
  • PDF=HTML模板頁面+數據+模板化技術

六.利用Phantomjs+Poi.tl 生成Word文檔

6.1 概述

  • 通過Phantomjs 我們可以生成出Echarts圖片;
  • 通過Poi.tl我們可以生成出表格,文字,圖片等內容;
  • 通過Phantomjs+Poi.tl,我們就可以生成出帶Echarts圖片的報表了~!!
  • poi-tl使用介紹及簡單教程

6.2 思路

  • 通過Phantomjs生成Echarts圖片,並上傳至fastdfs服務器,我們就可以拿到圖片的網絡地址了;
  • 通過Pol.tl我們可以加載Echarts的網絡圖片,並且也可以使用表格,其他圖片,文字等信息;
  • 執行步驟:
    1. 當我們點擊生成報表的時候,就會先去請求相關的數據接口,拿到數據後,利用phantomjs生成Echarts圖片,並上傳至fastdfs服務器拿到圖片地址url;
    2. 需要生成表格等的數據,就利用Poi.tl生成表格;
    3. 利用poi.tl將文字以及Echarts等數據融入word文檔內;
    4. 利用poi.tl生成word文檔,並上傳至fastdfs,拿到下載url後返回給前端;
    5. 完成!
  • 生成界面如下:
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章