Java通过后台导出Echart图片
一,工具准备
phantomjs
由于Echart图片是通过浏览器的js生成在页面上,因此若不想通过前端生成Echart图片,需要使用其他工具,例如 phantomjs
,俗称为:*面的浏览器。
PhantomJS是一个基于 WebKit 的服务器端JavaScript API。它全面支持web而不需浏览器支持,支持各种Web标准:DOM处理,CSS选择器, JSON,Canvas,和SVG。
PhantomJS常用于页面自动化,网络监测,网页截屏,以及*面测试等。通常我们使用PhantomJS作为爬虫工具。传统的爬虫只能单纯地爬取html的代码,对于js渲染的页面,就无法爬取,如Echarts统计图。而PhantomJS正可以解决此类问题。
官网下载http://phantomjs.org/download.html 国内镜像http://npm.taobao.org/dist/phantomjs/
EChartsConvert
echart-convert.js可以配合phantomjs将图片截图下来
下载地址(个人自定义): https://gitee.com/lmchh/echartsconvert
网上地址:https://gitee.com/saintlee/echartsconvert
安装并运行
D:/Java/Echart/phantomjs-2.1.1-windows/bin/phantomjs.exe D:/Java/Echart/echartsconvert/echarts-convert.js -s -p 6666
命令參數:
- -s: 指通過服務器的方式
- -p:指定端口後,一般和 -s 一起使用
- -o:o即option,格式為 {…}
- -f:輸出路徑
- -t:圖片類型,有 file/base64 兩種,默認是base64
- -w:即width,圖片寬度
- -h:即height,圖片高度
二,所需依赖
<!-- Echart -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
三,实现代码
package com.lmc.excel.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import freemarker.template.TemplateException;
import sun.misc.BASE64Decoder;
import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName: EchartsUtil
* @author: Leemon
* @Description: TODO
* @date: 2021/6/14 15:43
* @version: 1.0
*/
public class EchartsUtil {
/**
* 临时文件夹路径
*/
public static final String TEMP_FILE_PATH = "D:/data/echart/";
private static final String SUCCESS_CODE = "1";
private static final String path = EchartsUtil.class.getClassLoader().getResource("json").getPath();
public static void main(String[] args) throws IOException, TemplateException {
// 获取option字符串
String option = getStringByFile(path + "/test.json");
JSONObject object = JSONObject.parseObject(option);
option = object.toJSONString();
// 根据option参数,width和height生成base64编码
String base64 = EchartsUtil.generateEchartsBase64(option, "1360", "800");
System.out.println("BASE64:" + base64);
generateImage(base64, TEMP_FILE_PATH, "test.png");
}
public static String generateEchartsBase64(String option, String width, String height) throws IOException {
String base64 = "";
if (option == null) {
return base64;
}
option = option.replaceAll("\\s+", "");//.replaceAll("\"", "");
JSONObject object = JSON.parseObject(option);
object.getJSONArray("series").getJSONObject(0).put("data", Arrays.asList(120, 200, 150, 80, 70, 110, 130));
String json = JSONObject.toJSONString(object);
object = JSON.parseObject(json);
// 将option字符串作为参数发送给echartsConvert服务器
if (width == null || "".equals(width)) {
width = "800";
}
if (height == null || "".equals(height)) {
height = "400";
}
Map<String, String> params = new HashMap<>();
params.put("opt", JSON.toJSONString(object));
params.put("width", width);
params.put("height", height);
String response = HttpUtil.post("http://localhost:6666", params, "utf-8");
System.err.println(response);
// 解析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
* @param fileName
* @throws IOException
*/
public static void generateImage(String base64, String path, String fileName) throws IOException {
BASE64Decoder decoder = new BASE64Decoder();
try (OutputStream out = new FileOutputStream(path + fileName)){
// 解密
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();
}
}
/**
* 将文件转化为字符串
* @param fileName
* @return
*/
public static String getStringByFile(String fileName) {
File file = new File("D:/Java/Echart/test.json");
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
try {
fis = new FileInputStream(file);
isr = new InputStreamReader(fis);
br = new BufferedReader(isr);
String line = null;
while (((line = br.readLine()) != null)) {
sb.append(line);
}
br.close();
isr.close();
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
return sb.toString();
}
}
}
test.json
{
"tooltip": {
"trigger": "axis",
"axisPointer": {
"type": "shadow"
}
},
"legend": {
"data": [
"直接访问",
"邮件营销",
"联盟广告",
"视频广告",
"搜索引擎",
"百度",
"谷歌",
"必应",
"其他"
]
},
"grid": {
"left": "3%",
"right": "4%",
"bottom": "3%",
"containLabel": true
},
"xAxis": [{
"type": "category",
"data": [
"周一",
"周二",
"周三",
"周四",
"周五",
"周六",
"周日"
]
}],
"yAxis": [{
"type": "value"
}],
"series": [{
"name": "直接访问",
"type": "bar",
"emphasis": {
"focus": "series"
},
"data": [
320,
332,
301,
334,
390,
330,
320
]
},
{
"name": "邮件营销",
"type": "bar",
"stack": "广告",
"emphasis": {
"focus": "series"
},
"data": [
120,
132,
101,
134,
90,
230,
210
]
},
{
"name": "联盟广告",
"type": "bar",
"stack": "广告",
"emphasis": {
"focus": "series"
},
"data": [
220,
182,
191,
234,
290,
330,
310
]
},
{
"name": "视频广告",
"type": "bar",
"stack": "广告",
"emphasis": {
"focus": "series"
},
"data": [
150,
232,
201,
154,
190,
330,
410
]
},
{
"name": "搜索引擎",
"type": "bar",
"data": [
862,
1018,
964,
1026,
1679,
1600,
1570
],
"emphasis": {
"focus": "series"
},
"markLine": {
"lineStyle": {
"type": "dashed"
},
"data": [
[{
"type": "min"
},
{
"type": "max"
}
]
]
}
},
{
"name": "百度",
"type": "bar",
"barWidth": 5,
"stack": "搜索引擎",
"emphasis": {
"focus": "series"
},
"data": [
620,
732,
701,
734,
1090,
1130,
1120
]
},
{
"name": "谷歌",
"type": "bar",
"stack": "搜索引擎",
"emphasis": {
"focus": "series"
},
"data": [
120,
132,
101,
134,
290,
230,
220
]
},
{
"name": "必应",
"type": "bar",
"stack": "搜索引擎",
"emphasis": {
"focus": "series"
},
"data": [
60,
72,
71,
74,
190,
130,
110
]
},
{
"name": "其他",
"type": "bar",
"stack": "搜索引擎",
"emphasis": {
"focus": "series"
},
"data": [
62,
82,
91,
84,
109,
110,
120
]
}
]
}
运行main函数,将会在 D:/data/echart/下生成 test.png 的堆栈柱状图。
四,传入参数方式
前面这种方式直接把test.json中整一个文件当做一个option,这样的话数据就是写死的方式,如果需要自定义数据的话,可以通过编辑json修改option
// 获取option字符串
String option = getStringByFile(path + "/test.json");
JSONObject object = JSONObject.parseObject(option);
object.getJSONObject("legend").put("data", Arrays.asList("直接访问","邮件营销","联盟广告","其他"));
option = object.toJSONString();
以上就是关于只通过后台生成Echart图表的方式。