由于最近项目需要在java后台生成echarts图片,花时间研究了下这个,顺便分享下;
1.首先需要先下载echarts本地服务器;
(1)网盘:链接:https://pan.baidu.com/s/1kTZ9JWsU48PTTG809HurRA 提取码:b69t
(2)
获取后放入本地解压到例如D:/TEST下
D:\TEST\phantomjs-2.1.1-windows\bin\phantomjs.exe D:\TEST\saintlee-echartsconvert-master\echartsconvert\echarts-convert.js -s -p 6666
解压之后可以使用cmd命令启动这个服务,输入以上命令出现 echarts-convert server start success. [pid]=10500 提示即启动成功;
2.此服务启动成功后就是代码了
以下是springboot项目整体结构了采用了Maven导包方式,需要utils下和pom文件需要导入相应的包
(1)导入pom.xml包
org.freemarker
freemarker
2.3.28
org.apache.httpcomponents
httpclient
4.5.7
com.alibaba
fastjson
1.2.68
org.apache.commons
commons-pool2
(2)3个工具类分别如下,根据需求可自行修改逻辑
package com.lxp.demo.utils;/**
* @projectName: ruoyi
* @packageName: com.rmis.common.utils.chart
* @className: HttpUtil
* @description: ${description}
* @author: hrs
* @date: 2020-07-16 15:25
*/
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;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
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 (Map.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;
}
}
package com.lxp.demo.utils;/**
* @projectName: ruoyi
* @packageName: com.rmis.common.utils.chart
* @className: FreemarkerUtil
* @description: ${description}
* @author: hrs
* @date: 2020-07-16 15:26
*/
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.Map;
/**
* @author msh
* @date2020/7/16
*/
public class FreemarkerUtil {
private static final String path = FreemarkerUtil.class.getClassLoader().getResource("").getPath();
public static String generateString(String templateFileName, String templateDirectory, Map datas)
throws IOException, TemplateException {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_0);
// 设置默认编码
configuration.setDefaultEncoding("UTF-8");
//获取模板地址
configuration.setClassForTemplateLoading(FreemarkerUtil.class,templateDirectory);
// 生成模板对象
Template template = configuration.getTemplate(templateFileName);
// 将datas写入模板并返回
try (StringWriter stringWriter = new StringWriter()) {
template.process(datas, stringWriter);
stringWriter.flush();
return stringWriter.getBuffer().toString();
}
}
}
package com.lxp.demo.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import freemarker.template.TemplateException;
import org.apache.http.client.ClientProtocolException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author msh
* @date2020/7/16
*/
public class EchartsUtil {
/**
* 临时文件夹路径
*/
public static final String TEMP_FILE_PATH = "D:/tempFile/";
private static final String SUCCESS_CODE = "1";
private static final Logger logger = LoggerFactory.getLogger(EchartsUtil.class);
public static String generateEchartsBase64(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("http://localhost:6666", 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;
}
public static void getImage(Map datas) throws IOException {
// 生成option字符串
String option = null;
try {
if (!datas.containsKey("ftl")){
logger.error("没有指定生成图表的模板!");
}
option = FreemarkerUtil.generateString((String) datas.get("ftl"), "/template", datas);
} catch (TemplateException e) {
logger.error(e.getMessage());
}
// 根据option参数
String base64 = generateEchartsBase64(option);
File file = new File(TEMP_FILE_PATH);
if(!file.exists()) {
// 如果不存在就创建文件
file.mkdir();
}
BASE64Decoder decoder = new BASE64Decoder();
try (OutputStream out = new FileOutputStream(TEMP_FILE_PATH+"test.jpg")){
// 解密
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();
}
}
}
以上是所有工具类的代码,解释基本都有,最后还需要一个echarts图模板 option.ftl 如下:
{
title: {
text: '功率调节计算'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['AO', 'AO*']
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ${aohour}
},
yAxis: {
type: 'value'
},
series: [
{
name: 'AO',
type: 'line',
stack: '总量',
data: ${aoList},
smooth : true
},
{
name: 'AO*',
type: 'line',
stack: '总量',
data: ${aoxList},
smooth : true
},
]
}
(3)最后一部是执行EchartUtils的测试方法
public static void main(String[] args) {
//制造数据
List aoxList = new ArrayList<>();
aoxList.add("2"); aoxList.add("4"); aoxList.add("7");aoxList.add("9"); aoxList.add("10"); aoxList.add("9");
aoxList.add("8"); aoxList.add("8"); aoxList.add("7");
List aoList = new ArrayList<>();
aoList.add("1"); aoList.add("4"); aoList.add("7");aoList.add("9"); aoList.add("10"); aoList.add("10");
aoList.add("10"); aoList.add("10"); aoList.add("10");
List aohour = new ArrayList<>();
aohour.add("1");aohour.add("2");aohour.add("3");aohour.add("4");aohour.add("5");aohour.add("6");aohour.add("7");
aohour.add("8");aohour.add("9");
// 模板参数
HashMap datas = new HashMap<>();
//aohour、aoList、aoxList对应模板/template/option.ftl中的x和y轴的名字,模板可自行修改,
//ftl 为设置模板的名字。路径在/templates下
datas.put("aoxList", JSON.toJSONString(aoxList));
datas.put("aoList", JSON.toJSONString(aoList));
datas.put("aohour", JSON.toJSONString(aohour));
datas.put("ftl", "option.ftl");
try {
EchartsUtil.getImage(datas);
} catch (IOException e) {
e.printStackTrace();
}
}
执行后在代码设置的路径下会生成这样的图片及完成功能,后续会继续如何将图片以及文字替换掉word模板文档中的字和图片