相信大家都用過百度Ecahrts或者了解過,它是一個前端的圖形報表js插件,功能強大。不過,我們正常使用Echarts都是使用瀏覽器打開一個頁面進行渲染。
比如說,現在每天定時產生一些報表,發給誰誰誰,不可能手工去打開一個瀏覽器生產一個個報表再保存圖片再發送。
再比如說,列表有很多記錄,每條記錄都根據數據顯示不同形狀的報表,一般情況下,需打開某一條記錄查看某一報表。但現在有這樣的需求:我要批量導出選中報表(不需要一個個打開看)
針對這種需求我可以利用“無界面的瀏覽器”----phantomjs
我這里使用的是phantomjs-2.1.1-linux-x86_64,其實phantomjs也有windows版本。
下載地址:
PhantomJS官方API: http://phantomjs.org/api/。
PhantomJS官方示例: http://phantomjs.org/examples/。
PhantomJS GitHub: https://github.com/ariya/phantomjs/
鏈接:https://www.jianshu.com/p/8210a17bcdb8
來源:簡書

現在“無界面瀏覽器”安裝成功了,需提供數據才能產生效果
二、利用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服務器不掛,而且不好調試,本人試過日志無任何提示,但就是生成不了文件。
echartsconvert