java后台生成echarts图表图片

7 篇文章 1 订阅

Java后台生成echarts图表图片并发送html页面邮件



前言

项目需求,生成报表并发送邮件给指定邮箱,报表中包含echarts图表,由于无法在邮件中渲染图表,所以需要后台生成图表图片再嵌入到邮件中。


一、如何后台生成图表图片

如何不依赖前端在JAVA后台生成echarts图表图片呢,这里需要借助PhantomjsEChartsConvert工具,可以自行了解。

二、使用步骤

1.安装部署Phantomjs

https://phantomjs.org/download.html下载对应环境的安装包,我这边用的是linux环境。

  1. 将phantomjs-2.1.1-linux-x86_64.tar包放到/usr/local下,解压
  2. 修改环境变量
    vi /etc/profile
    添加以下配置到最后一行
    export PATH=$PATH:/usr/local/phantomjs-2.1.1-linux-x86_64/bin
    保存环境变量
    source /etc/profile
    
  3. 安装依赖
    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);
		}
    }
}

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图表图片的步骤是什么? 回答: 生成echarts图表图片的步骤如下: 1. 首先,需要安装部署Phantomjs,可以将下载好的Phantomjs放在任意位置。 2. 找到echarts-convert.js文件,并将其放在与Phantomjs相同的目录下。 3. 在命令行中执行命令,例如在Linux系统中可以执行nohup phantomjs echarts-convert.js -s -p 50130 > echarts.log 2>&1 &,而在Windows系统中可以执行C:\Users\Administrator\Desktop\phantomjs-2.1.1-windows\bin>phantomjs C:\Users\Administrator\Desktop\echartsconvert\echarts-convert.js -s -p 9090。\[2\]\[3\] 4. 调用接口生成图片,可以通过发送请求来调用接口生成echarts图表图片。 #### 引用[.reference_title] - *1* *2* [java后台生成echarts图表图片](https://blog.csdn.net/zixuanyankai/article/details/130702369)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [java 实现后台生成echarts 图片](https://blog.csdn.net/weixin_43831289/article/details/119645323)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值