Java后台生成echarts图表图片并发送html页面邮件
文章目录
- Java后台生成echarts图表图片并发送html页面邮件
- 前言
- 一、如何后台生成图表图片
- 二、使用步骤
- 1.安装部署Phantomjs
- 2.运行EChartsConvert
- 3.调用接口生成图片
- 三、官方使用nodejs转svg图片方案
前言
项目需求,生成报表并发送邮件给指定邮箱,报表中包含echarts图表,由于无法在邮件中渲染图表,所以需要后台生成图表图片再嵌入到邮件中。
一、如何后台生成图表图片
如何不依赖前端在JAVA后台生成echarts图表图片呢,这里需要借助Phantomjs和EChartsConvert工具,可以自行了解。
二、使用步骤
1.安装部署Phantomjs
在https://phantomjs.org/download.html下载对应环境的安装包,我这边用的是linux环境。
- 将phantomjs-2.1.1-linux-x86_64.tar包放到/usr/local下,解压
- 修改环境变量
vi /etc/profile 添加以下配置到最后一行 export PATH=$PATH:/usr/local/phantomjs-2.1.1-linux-x86_64/bin 保存环境变量 source /etc/profile
- 安装依赖
yum install -y fontconfig freetype2 安装成功后判断是否成功 phantomjs -v 正常会输出版本号 再安装好字体,不安装的话,图表中的中文会乱码 可以先去windows下C:\Windows\Fonts复制字体文件,可以使用Microsoft YaHei UI这个字体,复制到linux下的/usr/share/fonts/chinese目录下。没有这个目录就自己创建一个,再执行以下命令 mkfontscale mkfontdir fc-cache -fv ps:如果以上找不到命令,执行yum install -y fontconfig mkfontscale ps:字体更新后要重启phantomjs服务才会生效
2.运行EChartsConvert
将下载好的EChartsConvert放在任意位置,找到echarts-convert.js文件,在同级目录下执行
nohup phantomjs echarts-convert.js -s -p 50130 > echarts.log 2>&1 &
以上命令可以在后台执行echarts-convert.js脚本,指定端口50130
3.调用接口生成图片
三、官方使用nodejs转svg图片方案
1、以下是官方转svg图片方案,链接: 服务端渲染 ECharts 图表
var http = require("http");
var echarts = require("echarts");
function renderChart(data) {
const chart = echarts.init(null, null, {
renderer: "svg",
ssr: true,
width: data.width,
height: data.height
});
if(data.type == "bar"){
chart.setOption({
xAxis: {
type: "category",
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
interval: 0
},
data: data.xAxis
},
yAxis: {
type: "value",
boundaryGap: true,
axisLine: {
show: false,
color: "#BDEDF8"
},
axisTick: {
show: false
},
axisLabel: {
rich: {
valueStyle: {
color: "#d9001b99"
}
}
}
},
title: {
show: false
},
tooltip: {
axisPointer: {
type: "shadow"
},
trigger: "axis",
backgroundColor: "#fff",
borderColor: "rgba(0,0,0,0.10)",
borderWidth: 1,
textStyle: {
color: "#333"
}
},
legend: {
data: []
},
grid: {
top: 30,
left: 30,
right: 50,
bottom: 15,
containLabel: true
},
color: [
"#0066FF",
"#8378EA",
"#0092FF",
"#00BDFF",
"#FFA254",
"#00BD7E",
"#AD9DF3",
"#FFCB00",
"#4AD3A4",
"#00FFCD"
],
series: [
{
data: data.series,
type: "bar",
stack: "",
name: "",
barMaxWidth: 24,
emphasis: {
label: {
fontWeight: "bold"
},
itemStyle: {
opacity: 1
}
},
itemStyle: {
color: "#AD9DF3"
},
animationDelay: (idx) => {
return idx * 100;
},
}
]
});
}else if(data.type == "line"){
chart.setOption(
{
title: {
show: false
},
tooltip: {
trigger: "axis",
backgroundColor: "#fff",
borderColor: "rgba(0,0,0,0.10)",
borderWidth: 1,
textStyle: {
color: "#333"
}
},
color: [
"#1890ff",
"#19c2c6",
"#dc122b",
"#4E9AFE",
"#4AD3A4 ",
"#AD9DF3",
"#F6C827",
"#F9A46E",
"#1890ff",
"#b31212",
"#faad14"
],
legend: {
type: "scroll",
right: 50,
top: 10,
height: 20,
data: data.legend,
itemWidth: 12,
itemHeight: 8,
padding: 10
},
grid: {
top: 50,
left: 30,
right: 50,
bottom: 30,
containLabel: true
},
xAxis: {
type: "category",
boundaryGap: false,
axisLabel: {
textStyle: {
fontSize: "12",
color: "#666"
}
},
axisLine: {
lineStyle: {
color: "#ccc"
}
},
axisTick: {
inside: true,
alignWithLabel: true
},
data: data.xAxis
},
yAxis: {
type: "value",
axisLine: {
show: false
},
splitLine: {
lineStyle: {
color: "rgba(153,153,153,.2)"
}
},
axisTick: {
show: false
},
lineStyle: {
width: 1
},
axisLabel: {
rich: {
valueStyle: {
color: "#d9001b99"
}
}
},
nameLocation: "end",
nameTextStyle: {
verticalAlign: "middle"
}
},
series: data.series
}
);
}else if(data.type == "pie"){
chart.setOption(
{
title: {
show: false
},
tooltip: {
trigger: "item",
borderWidth: 0,
axisPointer: {
type: "cross"
}
},
legend: {
type: "plain",
orient: "vertical",
left: "50%",
top: "center",
align: "left",
itemGap: 6,
itemWidth: 8,
itemHeight: 8,
icon: "circle",
symbolKeepAspect: false,
itemStyle: {
opacity: 1
},
textStyle: {
lineHeight: 18,
fontSize: 12,
color: "#333333",
rich: {
a: {
width: 250
},
b: {
width: 70
},
c: {
color: "#666666"
}
}
},
tooltip: {
show: true
}
},
color: [
"#4E9AFE",
"#4AD3A4",
"#AD9DF3",
"#FBDB6A",
"#F9A46E",
"#9d96f5",
"#8378EA",
"#96BFFF",
"#C5E545",
"#E9967A",
"#C8C8CB"
],
series: [
{
name: "",
type: "pie",
right: "50%",
radius: [
"50%",
"70%"
],
center: [
"50%",
"50%"
],
minAngle: 1,
data: data.series,
label: {
show: false
},
itemStyle: {
opacity: 0.8
},
emphasis: {
itemStyle: {
opacity: 1,
shadowColor: "none"
}
}
}
]
}
);
}
return chart.renderToSVGString();
}
http
.createServer(function (req, res) {
res.writeHead(200, {
"Content-Type": "application/xml"
});
var post = "";
req.on("data",function(chunk){
post+=chunk;
})
req.on("end",function(){
post = JSON.parse(post)
console.log(post);
var chart = renderChart(post)
console.log(chart)
res.write(chart);
res.end();
})
})
.listen(8877);
接口传参
{
"series": [
1,
2,
3,
4,
5,
6,
7
],
"xAxis": [
"星期一",
"星期二",
"星期三",
"星期四",
"星期五",
"星期六",
"星期天"
],
"type": "bar",
"width": 450,
"height": 200
}
安装好node.js服务,将转换代码复制到app.js文件中,将文件复制到node.js可执行的任意目录下,执行node app.js,然后通过http调用即可
创建精简node.js容器
docker pull alpine:latest
docker run -dit -p 8877:8877 --name alpine alpine:latest
docker exec -it alpine /bin/sh
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
apk update
apk add npm
cd /root
npm install echarts
apk del npm
exit
docker cp app.js alpine:/root/app.js
docker exec -it alpine /bin/sh
nohup node app.js > echarts.log 2>&1 &
使用docker镜像
docker pull node
docker run -dit -p 8877:8877 --name node node
docker cp app.js node:/root/app.js
docker exec -it node bash
cd /root
npm install echarts
apt -y install xfonts-utils fontconfig//安装字体
复制字体文件到/usr/share/fonts/和/usr/share/fonts/chinese
cd /usr/share/fonts/chinese
mkfontscale # 生产字体索引
mkfontdir #
fc-cache -frv # 更新字体缓存
nohup node app.js > echarts.log 2>&1 &
打包镜像文件命令
docker commit ffaa3859d2b9(容器id)node_echarts:2.0.0
docker save -o node_echarts node_echarts:2.0.0//保存为node_echarts文件
加载镜像文件
docker load -i node_echarts
docker run -dit -p 8877:8877 --name node_echarts node_echarts:2.0.0
svg字符串转base64图片字符串,利用batik包转png再转base64
implementation 'org.apache.xmlgraphics:batik-all:1.14'
package top.xxx.module.abac.util.echarts;
import cn.hutool.http.HttpUtil;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Map;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import top.xxx.module.abac.util.JackJsonUtil;
public class EchartsUtil {
private static String url = "http://abac.ensbrain.ztrust.top:8877";
/**
* @description: 根据echarts配置项生成echarts图片并返回base64编码
* @param: opt
* @return: java.lang.String
**/
public static String generateEchartsImg2Base64(Map opt) throws IOException {
String jsonData = JackJsonUtil.obj2String(opt);
String svg = HttpUtil.post(url, jsonData);
try {
ByteArrayInputStream bin=new ByteArrayInputStream(svg.getBytes());
PNGTranscoder transcoder = new PNGTranscoder();
TranscoderInput input = new TranscoderInput(bin);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
TranscoderOutput output = new TranscoderOutput(outputStream);
transcoder.transcode(input, output);
byte[] pngData = outputStream.toByteArray();
return Base64.getEncoder().encodeToString(pngData);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}