文章目录很多时候需要自动生成一些文档,并在文档中插入一些图片,一般B/S系统中图片由Echarts生成,但文档在java后台生成,这时怎样在后台调用Echarts的功能呢?答案是phantomJS。
- 1.安装phantomJS
- 2.下载EchartsConvert
- 3.运行phantomJS
- 4.引入依赖
- 5.httpclient工具类
- 6.freemarker工具类
- 7.图像工具类
- 8.Echarts工具类
- 9.模板opt.ftl
- 10.测试
- 11.生成的图片
- 12.生成折线图
- 13.Java使用Echarts工具生成option
- (1)首先引入Echarts依赖
- (2)生成option
- (3)生成图片
- (4) 生成的图片
下载地址:https://bitbucket.org/ariya/phantomjs/downloads/,国内镜像地址:http://npm.taobao.org/dist/phantomjs/
有各种版本的,我这里以windows为例。
下载地址:https://gitee.com/saintlee/echartsconvert
3.运行phantomJS可以使用两种方式生成图片,直接在本地调用命令行或者使用远程服务,下面以远程服务为例。
在phantomJS解压后的bin目录中通过命令行运行phantomjs.exe
如下图所示:
通过maven或gradle引入httpclient、freemark和fastjson的依赖,我这里略过了
5.httpclient工具类package com.iscas.base.biz.util.echarts;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.HttpEntity;
import org.apache.http.NamevaluePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNamevaluePair;
import org.apache.http.util.EntityUtils;
public class HttpUtil {
public static String post(String url, Map params, String charset)
throws ClientProtocolException, IOException {
String responseEntity = "";
// 创建CloseableHttpClient对象
CloseableHttpClient client = HttpClients.createDefault();
// 创建post方式请求对象
HttpPost httpPost = new HttpPost(url);
// 生成请求参数
List namevaluePairs = new ArrayList<>();
if (params != null) {
for (Entry entry : params.entrySet()) {
namevaluePairs.add(new BasicNamevaluePair(entry.getKey(), entry.getValue()));
}
}
// 将参数添加到post请求中
httpPost.setEntity(new UrlEncodedFormEntity(namevaluePairs, charset));
// 发送请求,获取结果(同步阻塞)
CloseableHttpResponse response = client.execute(httpPost);
// 获取响应实体
HttpEntity entity = response.getEntity();
if (entity != null) {
// 按指定编码转换结果实体为String类型
responseEntity = EntityUtils.toString(entity, charset);
}
// 释放资源
EntityUtils.consume(entity);
response.close();
return responseEntity;
}
}
6.freemarker工具类
package com.iscas.base.biz.util.echarts;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.lang3.StringUtils;
public class FreemarkerUtils {
public static String generateString(String templateFileName, String templateDirectoryPath, Map datas)
throws IOException, TemplateException {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_0);
// 设置默认编码
configuration.setDefaultEncoding("UTF-8");
if (templateDirectoryPath.startsWith("classpath:")) {
//设置类加载器
configuration.setClassLoaderForTemplateLoading(Thread.currentThread().getContextClassLoader(),
StringUtils.substringAfter(templateDirectoryPath, "classpath:"));
} else {
// 设置模板所在文件夹
configuration.setDirectoryForTemplateLoading(new File(templateDirectoryPath));
}
// 生成模板对象
Template template = configuration.getTemplate(templateFileName);
// 将datas写入模板并返回
try (StringWriter stringWriter = new StringWriter()) {
template.process(datas, stringWriter);
stringWriter.flush();
return stringWriter.getBuffer().toString();
}
}
}
7.图像工具类
public class ImageUtils {
private ImageUtils() {
}
public static void convertbase64ToImage(String base64, OutputStream os) throws IOException {
base64.Decoder decoder = base64.getDecoder();
// 解密
byte[] b = decoder.decode(base64);
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {
b[i] += 256;
}
}
os.write(b);
os.flush();
}
}
8.Echarts工具类
package com.iscas.base.biz.util.echarts;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.client.ClientProtocolException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class EchartsUtils {
private static final String SUCCESS_CODE = "1";
public static String generateEchartsbase64(String phantomjsUrl, String option) throws ClientProtocolException, IOException {
String base64 = "";
if (option == null) {
return base64;
}
option = option.replaceAll("\s+", "").replaceAll(""", "'");
// 将option字符串作为参数发送给echartsConvert服务器
Map params = new HashMap<>();
params.put("opt", option);
String response = HttpUtil.post(phantomjsUrl, 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;
}
}
9.模板opt.ftl
{
title: {
text:'${title}',
x:'middle',
textAlign:'center'
},
xAxis: {
type: 'category',
data: ${categories}
},
yAxis: {
type: 'value'
},
series: [{
data: ${values},
type: 'bar'
}]
}
10.测试
public class EchartTests {
private static String url = "http://localhost:7777";
@Test
public void test() throws TemplateException, IOException {
// 变量
String title = "销量";
String[] categories = new String[] { "2019", "2020", "2021" };
int[] values = new int[] { 100, 105, 200 };
// 模板参数
HashMap datas = new HashMap<>();
datas.put("categories", JSON.toJSONString(categories));
datas.put("values", JSON.toJSONString(values));
datas.put("title", title);
// 生成option字符串
// String option = FreemarkerUtils.generateString("option.ftl", "C:\ideaProjects\newframe\biz-base\src\test\java\com\iscas\base\biz\util\echarts", datas);
String option = FreemarkerUtils.generateString("option.ftl", "classpath:ftl", datas);
// 根据option参数
String base64 = EchartsUtils.generateEchartsbase64(url, option);
System.out.println("base64:" + base64);
File test = File.createTempFile("test", ".png");
test.deleteOnExit();
try (OutputStream os = new FileOutputStream(test)) {
ImageUtils.convertbase64ToImage(base64, os);
}
System.out.println("测试完成");
}
}
11.生成的图片
12.生成折线图
上面是一个生成生成简单柱状图的例子,下面我们自定义一个折线图模板,生成一个折线图
折线图模板line.ftl
{
"title": {
"text": "${title}",
"x": "left"
},
"tooltip": {
"trigger": "axis"
},
"legend": {
"data": ${legendData}
},
"xAxis": [
{
"boundaryGap": false,
"type": "category",
"data": ${xAxisData}
}
],
"yAxis": ${yAxis},
"series": ${data}
}
测试:
//测试折线图
@Test
public void testLine() throws TemplateException, IOException {
// 标题
String title = "资源增长情况";
//legendData
String[] legendData = new String[]{"ECS", "实例", "CPU", "MEM"};
//xAxisData
String[] xAxisData = new String[]{"2021-10-01", "2021-10-02", "2021-10-03", "2021-10-04", "2021-10-05"};
//yAxis
ArrayList
生成的图片:
除了上面的使用freemarker的方式生成option,还有一种方式是使用Echarts工具生成。
(1)首先引入Echarts依赖gradle:
compile group: 'com.github.abel533', name: 'ECharts', version: '3.0.0.6'
maven:
(2)生成optioncom.github.abel533 ECharts 3.0.0.6
生成时可以照着echarts官网的js来生成,基本是一一对应的
private String createPie() {
List> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Map map = new HashMap<>();
map.put("NAME", "张三" + i);
map.put("TOTAL", new Random().nextInt(50));
list.add(map);
}
//创建Option
Option option = new GsonOption();
option.title(new Title().text("测试饼图").x("middle"));
option.tooltip(Trigger.item);
option.legend(new Legend().orient(Orient.vertical).left("left"));
//饼图数据
Pie pie = new Pie("测试饼图");
//循环数据
for (Map objectMap : list) {
//饼图数据
pie.data(new PieData(objectMap.get("NAME").toString(), objectMap.get("TOTAL")));
}
//设置数据
option.series(pie);
String optionStr = option.toString().replace(" ", "");
return optionStr;
}
(3)生成图片
//测试饼状图
@Test
public void testPie() throws IOException {
String option = createPie();
String base64 = EchartsUtils.generateEchartsbase64(url, option);
System.out.println("base64:" + base64);
File test = File.createTempFile("test", ".png");
test.deleteOnExit();
try (OutputStream os = new FileOutputStream(test)) {
ImageUtils.convertbase64ToImage(base64, os);
}
System.out.println("测试完成");
}
(4) 生成的图片



