相信大家都用过百度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