利用phantomjs無界面生成Echarts報表


相信大家都用過百度Ecahrts或者了解過,它是一個前端的圖形報表js插件,功能強大。不過,我們正常使用Echarts都是使用瀏覽器打開一個頁面進行渲染。

比如說,現在每天定時產生一些報表,發給誰誰誰,不可能手工去打開一個瀏覽器生產一個個報表再保存圖片再發送。

再比如說,列表有很多記錄,每條記錄都根據數據顯示不同形狀的報表,一般情況下,需打開某一條記錄查看某一報表。但現在有這樣的需求:我要批量導出選中報表(不需要一個個打開看)

針對這種需求我可以利用“無界面的瀏覽器”----phantomjs

我這里使用的是phantomjs-2.1.1-linux-x86_64,其實phantomjs也有windows版本。

下載地址:

PhantomJS官方地址: http://phantomjs.org/
PhantomJS官方API: http://phantomjs.org/api/
PhantomJS官方示例: http://phantomjs.org/examples/
PhantomJS GitHub: https://github.com/ariya/phantomjs/
作者:HelloJames
鏈接:https://www.jianshu.com/p/8210a17bcdb8
來源:簡書

一、先在Linux環境安裝phantomjs插件
1、創建一個software文件夾,上傳phantomjs-2.1.1-linux-x86_64.zip,然后解壓到當前目錄
cd /
mkdir software 
unzip -zxvf phantomjs-2.1.1-linux-x86_64.zip  #解壓
2、授權
ln -s /software/phantomjs-2.1.1/bin/phantomjs /usr/bin/  
cd /software/phantomjs-2.1.1/bin  #進入到bin目錄,這里有一個phantomjs
chmod 777 phantomjs #給執行的權限
授權成功之后,輸入phantomjs,能看到以下界面證明安裝成功了

 

現在“無界面瀏覽器”安裝成功了,需提供數據才能產生效果

二、利用echarts-convert.js模板能力轉換對應json

官網:https://gitee.com/saintlee/echartsconvert

echarts-convert.js可以指定模板,因為我們不同的報表形狀和數據都不一樣,通常一個報表就對應一個模板。類似html頁面的js需要定制才能得到自己想要的Echarts報表

1、准備一般模板

cd /software/echarts

 

 2、自定js,拷貝一份自帶模板然后再改

 

其實也沒改什么,就是寬度和高度調整一下而已

DEFAULT_WIDTH: '1190',

DEFAULT_HEIGHT: '420'

 

3、自定義模板abilityLeida.ftl

自定義模板的目的就是模擬Echarts需要的Echart.setOption(option,true)

自定義模板:

 

 其中${pgyq}類型這種,是代碼替換用的,根據pgyq作為key,替換自己的value

{
    tooltip: {
    trigger: 'axis'
    },
    legend: {
        x: 'left',
        data:['能力要求','能力現狀']
    },
    radar: [
        {
            indicator: ${pgwd},
            center: ['50%','50%'],
            radius: 154
        }
    ],
    series: [
        {
            type: 'radar',
            tooltip: {
                trigger: 'item'
            },
            // itemStyle: {normal: {areaStyle: {type: 'default'}}},
            data: [
                {
                    name: '能力要求',
                    value: ${pgyq}
                },
                {
                    name:'能力現狀',
                    value:${pgxz}
                }
            ]
        }
    ]
}

 

 

 

下面就其中一個abilityLeida為例

 

三、 使用java代碼來執行phantomjs命名

1、配置文件的路徑config.properties

#echarts保存的路徑
echarts.savePath=/software/echarts
#phantomjs應用路徑
phantomjs.savePath=/software/phantomjs-2.1.1/bin/phantomjs
#echartscovert保存的路徑
echartsconvert.savePath=/software/echarts/echartsconvert

2、使用配置路徑

 @Value("${echarts.savePath}")
 private String savePath;

 @Value("${phantomjs.savePath}")
 private String phantomjsPath;

 @Value("${echartsconvert.savePath}")
 private String echartsconvertPath;

 

3、實體

@Data
public class AbilityResult implements Serializable {
    private static final long serialVersionUID = 9174076906312861702L;

    /**
     * 評估時間
     */
    private String date;

    /**
     * 測評崗位
     */
    private String zwshort;

    /**
     * 評估維度
     */
    private List<Dimension> pgwd;
    /**
     * 評估現狀值
     */
    private List<Double> pgxz;
    /**
     * 評估要求值
     */
    private List<Double> pgyq;

    /**
     * 評估文本
     */
    private List<String> pgwb;
    
    /**
     * 勝任度
     */
    private String competency;
    /**
     * 總體點評
     */
    private String assessment;

    // 評估維度
    @Data
    public class Dimension implements Serializable {
        private static final long serialVersionUID = -2508330173165063447L;
        String name;
        int max;
    }
}

4、FreemarkerUtil,將echart模板填充數據

public class FreemarkerUtil {

    private static final String path = FreemarkerUtil.class.getClassLoader().getResource("").getPath();

    /**
     * 將datas填充到指定ftl文件
     * @param templateFileName
     * @param datas
     * @return
     * @throws IOException
     * @throws TemplateException
     */
    public static String generateString(String templateFileName, Map<String, Object> datas)
            throws IOException, TemplateException {
        Configuration configuration = new Configuration(Configuration.VERSION_2_3_0);
        // 設置默認編碼
        configuration.setDefaultEncoding("UTF-8");
        // 設置模板所在文件夾
        configuration.setDirectoryForTemplateLoading(new File(path + "/template"));
        // 生成模板對象
        Template template = configuration.getTemplate(templateFileName);
        // 將datas寫入模板並返回
        try (StringWriter stringWriter = new StringWriter()) {
            template.process(datas, stringWriter);
            stringWriter.flush();
            return stringWriter.getBuffer().toString();
        }
    }

}

5、調用phantomjs命令生產報表

public class EchartGenerate {
    protected final static Logger logger=LoggerFactory.getLogger(EchartGenerate.class);

    /**
     * 通過http調用phantomjs的地址
     */
    private static String url = "http://localhost:6666";
    private static final String SUCCESS_CODE = "1";

    public static void main(String[] args) {
        //String optiona = "{\"title\":{\"text\":\"電流圖\",\"subtext\":\"電流圖\",\"x\":\"left\"},\"toolbox\":{\"feature\":{\"saveAsImage\":{\"show\":true,\"title\":\"保存為圖片\",\"type\":\"png\",\"lang\":[\"點擊保存\"]}},\"show\":true},\"tooltip\":{\"trigger\":\"axis\"},\"legend\":{\"data\":[\"郵件營銷\",\"聯盟廣告\",\"視頻廣告\"]},\"xAxis\":[{\"type\":\"category\",\"boundaryGap\":false,\"data\":[\"周一\",\"周二\",\"周三\",\"周四\",\"周五\",\"周六\",\"周日\"]}],\"yAxis\":[{\"type\":\"value\"}],\"series\":[{\"name\":\"郵件營銷\",\"type\":\"line\",\"stack\":\"總量\",\"data\":[120,132,101,134,90,230,210]},{\"name\":\"聯盟廣告\",\"type\":\"line\",\"stack\":\"總量\",\"data\":[220,182,191,234,290,330,310]},{\"name\":\"視頻廣告\",\"type\":\"line\",\"stack\":\"總量\",\"data\":[150,232,201,154,190,330,410]}]}";
        //System.out.println(generateEChart(optiona,JSpath));
    }

    /**
     * 生成echart圖片
     * @param pernr 工號
     * @param options echarts需要的options
     * @param phantomjsPath phantomjs路徑
     * @param echartsconvert 轉換js文件
     * @param savePath 圖片保存的路徑
     * @return
     */
    public static String generateEChart(String pernr,String options,String phantomjsPath,String echartsconvert,String savePath) {
        //保存成json文件
        String dataPath = optionSave2Json(options,savePath);
        String fileName= pernr+"-"+UUID.randomUUID().toString().substring(0, 8) + ".png";
        String path = savePath+File.separator+"echarts" +File.separator+fileName;
        try {
            /*File file = new File(path);     //文件路徑(路徑+文件名)
            if (!file.exists()) {   //文件不存在則創建文件,先創建目錄
                File dir = new File(file.getParent());
                dir.mkdirs();
                file.createNewFile();
            }*/
            //使用phantomjs生成echart圖片
            //String cmd = "phantomjs " + JSpath + " -infile " + dataPath + " -outfile " + path;
            String cmd = phantomjsPath + " " + echartsconvert + " -infile " + dataPath + " -outfile " + path;
            logger.info("執行命令,生成echart圖片:{}",cmd);
            Process process = Runtime.getRuntime().exec(cmd);
            BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line = "";
            while ((line = input.readLine()) != null) {
                logger.info(line);
            }
            input.close();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //用完json之后,刪掉
            FileUtil.delFile(dataPath);
        }
        return path;
    }


    /**
     * 將options保存成json文件
     * @param options
     * @return
     */
    public static String optionSave2Json(String options,String savePath) {
        //return "F:\\echart\\json\\a.json";
        String dataPath=savePath+File.separator+"jsons"+File.separator+ UUID.randomUUID().toString().substring(0, 8) +".json";
        try {
            /* 寫入Txt文件 */
            File writename = new File(dataPath); // 相對路徑,如果沒有則要建立一個新的output.txt文件
            if (!writename.exists()) {   //文件不存在則創建文件,先創建目錄
                File dir = new File(writename.getParent());
                dir.mkdirs();
                writename.createNewFile(); // 創建新文件
            }
            BufferedWriter out = new BufferedWriter(new FileWriter(writename));
            out.write(options); // \r\n即為換行
            out.flush(); // 把緩存區內容壓入文件
            out.close(); // 最后記得關閉文件
        } catch (IOException e) {
            e.printStackTrace();
        }
        return dataPath;
    }

    /**
     * 生成echarts的base64字符串,不過這個方法使用的是http請求,使用不方便
     * @param option
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static String generateEchartsBase64(String option) throws ClientProtocolException, IOException {
        String base64 = "";
        if (option == null) {
            return base64;
        }
        option = option.replaceAll("\\s+", "").replaceAll("\"", "'");

        // 將option字符串作為參數發送給echartsConvert服務器
        Map<String, String> params = new HashMap<>();
        params.put("opt", option);
        String response ="";
        //String response = HttpUtil.post(url, params, "utf-8");

        // 解析echartsConvert響應
        JSONObject responseJson = JSON.parseObject(response);
        String code = responseJson.getString("code");

        // 如果echartsConvert正常返回
        if (SUCCESS_CODE.equals(code)) {
            base64 = responseJson.getString("data");
        }
        // 未正常返回
        else {
            String string = responseJson.getString("msg");
            throw new RuntimeException(string);
        }
        return base64;
    }

    /**
     * base64轉圖片
     * @param base64
     * @param path
     * @throws IOException
     */
    public static void generateImage(String base64, String path) throws IOException {
        BASE64Decoder decoder = new BASE64Decoder();
        try (OutputStream out = new FileOutputStream(path)) {
            // 解密
            byte[] b = decoder.decodeBuffer(base64);
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {
                    b[i] += 256;
                }
            }
            out.write(b);
            out.flush();
        }
    }
}

 

打印的命令如下:

執行命令,生成echart圖片:/software/phantomjs-2.1.1/bin/phantomjs /software/echarts/echartsconvert/echarts-convert-abilityLeida.js -infile /software/echarts/jsons/f4d71487.json -outfile /software/echarts/echarts/30227701-a64dc66a.png

其實就是我上面注釋的代碼:String cmd = "phantomjs " + JSpath + " -infile " + dataPath + " -outfile " + path;

phantomjs:phantomjs的命令,直接使用bin/phantomjs

JSpath:使用convert.js

infile:輸入文件,我這里是json文件

outfile:輸出文件,這里就直接輸出圖片

產生的圖片;

 

 

 


 

 

 

 

 

總結:其實主要看cmd命名,需求提供文件和輸出什么文件。

phantomjs還支持開啟服務(類型一個tomcat,有地址和端口)給其它人調用,一樣的輸入文件,然后產生文件的方式,只不過個人還是覺得以上這種方式必將靠譜,因為如果需要訪問一個網址的方式,相當於要保障phantomjs服務器不掛,而且不好調試,本人試過日志無任何提示,但就是生成不了文件。

phantomjs開啟服務的方式參考:  https://www.jianshu.com/p/dfc28fd7d786

 

echartsconvert


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM