利用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