Springboot纯后端将ECharts统计图转为图片
简介:项目中要求是不经过前端,纯后端将ECharts统计图生成图片并转成base64码,以接口的形式提供调用,统计图所需参数接口预留。
此文章有三处工具记录
1.将jar包通过项目引入maven,无需将jar包打入maven库;
2.将ECharts图表生成图片保存至本地文件夹;
3.本地图片转为base64码。
直奔主题,程序所需文件已放至网盘
链接:https://pan.baidu.com/s/1R1A6LJndtojBleTG_qXngw
提取码:z5u2
1.将程序所需jar包放入项目里,使用Pom引入的方法
在项目里新建一个lib包,将jar包放进去,然后pom指定路径,更新maven
<!--本地包引入-->
<dependency>
<groupId>ECharts-2.2.7</groupId>
<artifactId>ECharts</artifactId>
<version>2.2.7</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/ECharts-2.2.7.jar</systemPath>
</dependency>
2.将phantomjs配置为环境变量
3.在本地新建两个文件夹,程序要用到,一个存储ECharts生成的json文件,一个存储图片
4.代码块
图片生成方法,注意封装的所需参数去调用
optiona里为原生ECharts,可在ECharts官网实例选择所需要的图表,将其代码放入optiona变量里
所需参数示例在下文接口封装调用处
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class EChartLines {
private static final String JSpath = "D:\\temp\\phantomjs-2.1.1-windows64\\echarts-convert\\echarts-convert1.js";
public static String eChartsImage(String xData,String thisCount,String lastCount,String title,String thisName,String lastName) {
String imgName = "D:/temp/Echart/tes" + UUID.randomUUID().toString().substring(0, 4) + ".png ";
String optiona ="{title: {\r\n" +
" text:"+"'"+title+"'}," +
" tooltip: {\r\n" +
" trigger: 'axis'\r\n" +
" },\r\n" +
" legend: {\r\n" +
" data:"+"['"+thisName+"','"+lastName+"']" +
" },\r\n" +
" grid: {\r\n" +
" left: '3%',\r\n" +
" right: '4%',\r\n" +
" bottom: '3%',\r\n" +
" containLabel: true\r\n" +
" },\r\n" +
" xAxis: {\r\n" +
"axisLabel:{interval:0,rotate:45},"+
" type: 'category',\r\n" +
" boundaryGap: false,data: " +
xData+
" },\r\n" +
" yAxis: {\r\n" +
" type: 'value'\r\n" +
" },\r\n" +
" series: [\r\n" +
" {\r\n" +
" name:"+"'"+thisName+"'," +
" type: 'line',\r\n" +
" stack: '总量',data: " +
thisCount +","+
" stack:\"stack\",label: {normal:{show:true,position:'top'}}" +
" },\r\n" +
" {\r\n" +
" name:"+"'"+lastName+"'," +
" type: 'line',\r\n" +
" stack: '总量',label: {normal:{show:true,position:'button'}},data: " +
lastCount +
" }\r\n" +
" ]}";
Map<String,Object> resultMap=new HashMap<>();
String imagePathName = generateEChart(optiona, resultMap);
return imagePathName;
}
public static String generateEChart(String options, Map<String,Object> resultMap) {
String dataPath = writeFile(options);
String fileName= UUID.randomUUID().toString().substring(0, 8) + ".png";
String path = "D:/temp/Echart/" +fileName;
try {
File file = new File(path); //文件路径(路径+文件名)
if (!file.exists()) { //文件不存在则创建文件,先创建目录
File dir = new File(file.getParent());
dir.mkdirs();
file.createNewFile();
}
String cmd = "phantomjs " + JSpath + " -infile " + dataPath + " -outfile " + path;
System.out.println(cmd);
Process process = Runtime.getRuntime().exec(cmd);
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = input.readLine()) != null) {
}
input.close();
} catch (IOException e) {
e.printStackTrace();
}finally{
return path;
}
}
public static String writeFile(String options) {
String dataPath="D:\\chartData\\data"+ 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);
out.flush(); // 把缓存区内容压入文件
out.close(); // 最后记得关闭文件
} catch (IOException e) {
e.printStackTrace();
}
return dataPath;
}
}
参数实体类
import lombok.Data;
/**
* 双折线,柱状图共用参数类
*/
@Data
public class EChartsDoubleParamVo {
private String title; // 图标题
private String thisName; // 本期图例及统计柱线名称(必填)
private String lastName; // 上期图例及统计柱线名称(必填)
private String name; // ['0点~1点'] 参数样例 x轴
private String thisCount; // 当期
private String lastCount; // 上期
}
base64转换工具类
import sun.misc.BASE64Encoder;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Objects;
public class ImageToBase64Util {
private static String strNetImageToBase64;
/**
* 网络图片转换Base64的方法
*
* @param netImagePath
*/
private static void NetImageToBase64(String netImagePath) {
final ByteArrayOutputStream data = new ByteArrayOutputStream();
try {
// 创建URL
URL url = new URL(netImagePath);
final byte[] by = new byte[1024];
// 创建链接
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
new Thread(new Runnable() {
@Override
public void run() {
try {
InputStream is = conn.getInputStream();
// 将内容读取内存中
int len = -1;
while ((len = is.read(by)) != -1) {
data.write(by, 0, len);
}
// 对字节数组Base64编码
BASE64Encoder encoder = new BASE64Encoder();
strNetImageToBase64 = encoder.encode(data.toByteArray());
System.out.println("网络图片转换Base64:" + strNetImageToBase64);
// 关闭流
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 本地图片转换Base64的方法
*
* @param imgPath
*/
public static String ImageToBase64(String imgPath) {
byte[] data = null;
// 读取图片字节数组
try {
InputStream in = new FileInputStream(imgPath);
data = new byte[in.available()];
in.read(data);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
// 对字节数组Base64编码
BASE64Encoder encoder = new BASE64Encoder();
// 返回Base64编码过的字节数组字符串
String base64Image = "data:image/png;base64,"+encoder.encode(Objects.requireNonNull(data));
return base64Image;
}
}
接口调用类
/**
* ECharts图表转图片
*/
@RestController
@RequestMapping("/eCharts")
public class EChartsImageController {
/**
* 双折线图表
* @param eChartsDoubleParamVo
* @return
*/
@PostMapping("/eChartLinesBase64")
public ActionResult EChartLinesBase64(@RequestBody EChartsDoubleParamVo eChartsDoubleParamVo){
ActionResult actionResult = null;
try {
String title = eChartsDoubleParamVo.getTitle();
String xData = eChartsDoubleParamVo.getName();
String thisCount = eChartsDoubleParamVo.getThisCount();
String lastCount = eChartsDoubleParamVo.getLastCount();
String thisName = eChartsDoubleParamVo.getThisName();
String lastName = eChartsDoubleParamVo.getLastName();
String imagePath = EChartLines.eChartsImage(xData,thisCount,lastCount,title,thisName,lastName); // 图片路径
String base64Image = ImageToBase64Util.ImageToBase64(imagePath);
base64Image = base64Image.replaceAll("\r|\n", "");
return actionResult = new ActionResult(200,"获取成功",base64Image);
} catch (Exception e){
e.printStackTrace();
actionResult = new ActionResult(500,"操作失败",null);
}
return actionResult;
}
}
Controller接口返回规范类
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serializable;
/**
* rest返回数对象
*/
@Data
@AllArgsConstructor
public class ActionResult<T> implements Serializable {
private static final long serialVersionUID = 6116515098874945764L;
private int code;
private String message;
private T content;
public ActionResult() {
}
}
接口调用参数示例
{
"title":"警情时段图",
"name":"['0点~1点', '1点~2点', '2点~3点', '3点~4点', '4点~5点', '5点~6点', '6点~7点','7点~8点','8点~9点','9点~10点','10点~11点','11点~12点']",
"thisCount":"[156, 111, 73, 71, 53, 89, 206, 533, 570, 559, 506, 448]",
"lastCount":"[161, 105, 80, 49, 54, 90, 205, 503, 536, 486, 464, 401]",
"thisName":"今年同期数量",
"lastName":"去年同期数量"
}
因为是Springboot项目,在打成jar包发布的时候,调用接口生成ECharts图表会有中文乱码情况,故采用utf-8编码启动
java -jar -Dfile.encoding=utf-8 web.jar
文章至此结束,一个开发笔记,也希望能帮助到有类似需求的朋友!