【已解决】java如何在后台生成echarts图表并将图片插入到word文档中,完整demo

  • 作者: 凯哥Java(公众号:凯哥Java)
  • echarts
  • 时间:2023-05-24 17:37
  • 2547人已阅读
简介 需求:数据进行统计后,需要将统计好的数据生成对应的echarts图,并将echarts图插入到word文档中导出使用。不需要在页面(浏览器)上展示。这就导致了,无法通过浏览器对echarts数据进行渲染后,在提供对应的base64的字符串给后端进行下载。原理:通过无头浏览器调用js方法,使用服务端查出来的数据生成echars图片,此处使用了phantomjs作为无头浏览器(此开源项目目前处于终止状

🔔🔔好消息!好消息!🔔🔔

 如果您需要注册ChatGPT,想要升级ChatGPT4。凯哥可以代注册ChatGPT账号代升级ChatGPT4

有需要的朋友👉:微信号 kaigejava2022

需求:

数据进行统计后,需要将统计好的数据生成对应的echarts图,并将echarts图插入到word文档中导出使用。不需要在页面(浏览器)上展示。这就导致了,无法通过浏览器对echarts数据进行渲染后,在提供对应的base64的字符串给后端进行下载。

原理:

通过无头浏览器调用js方法,使用服务端查出来的数据生成echars图片,此处使用了phantomjs作为无头浏览器(此开源项目目前处于终止状态,谷歌浏览器等都开发出类似功能,源码贡献者成员之一终止继续更新版本)。下附详细代码。

所需要的软件包:

链接: https://pan.baidu.com/s/1guTP-9RsZtSDFj1XFLzXqA?pwd=vgay 提取码: vgay 

详细代码如下;

①:常量对象

package com.kaigejava.demo4;
public class EChartWord {

    // ============== 这里要改成自己电脑对应的文件位置,服务器部署时可以通过环境变量等方式来动态改变它们的值 =================
    /**
     * echart-convert包的路径
     */
    public static String eChartJSPath = "D:\\BaiduNetdiskDownload\\服务器生成echart图片工具包\\echarts-convert\\echarts-convert1.js";
    /**
     * echart临时文件存储路径
     */
    public static  String eChartTempPath = "D:\\files\\test\\";
    /**
     * phantomjs命令路径
     */
    //private String phantomjsPath = "/Users/helios_fz/IdeaProjects/rbac/rbac-admin/src/main/resources/phantomjs/phantomjs-2.1.1-macosx/bin/phantomjs";
    public static  String phantomjsPath = "D:\\BaiduNetdiskDownload\\服务器生成echart图片工具包\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe";

}

②:工具类

package com.kaigejava;

/**
 * @author 凯哥Java
 * @since 2023/5/24 14:42
 */

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.UUID;

import static com.kaigejava.demo4.EChartWord.phantomjsPath;

public class EChartsUtil {

    /**
     * 生成EChart图
     *
     * @param options      EChart初始化json
     * @param tmpPath      临时文件存放处
     * @param echartJsPath 第三方工具路径--也就是js的路径
     * @return
     */
    public static  String generateEChartConvertFilePath(String options, String tmpPath, String echartJsPath)  {
        return  generateEChart(options, tmpPath,echartJsPath);
    }
    /**
     * 生成EChart图
     *
     * @param options      EChart初始化json
     * @param tmpPath      临时文件存放处
     * @param echartJsPath 第三方工具路径--也就是js的路径
     * @return
     */
    public static  InputStream generateEChartConvert(String options, String tmpPath, String echartJsPath) throws IOException {
        String dataPath = generateEChart(options, tmpPath,echartJsPath);
        return new FileInputStream(new File(dataPath));
    }

        /**
         * 生成EChart图
         *
         * @param options      EChart初始化json
         * @param tmpPath      临时文件存放处
         * @param echartJsPath 第三方工具路径--也就是js的路径
         * @return
         */
    public  static BufferedImage  generateEChartConvertFileToImage(String options, String tmpPath, String echartJsPath) throws IOException {
        // 生成Echart的初始化json文件
        String dataPath = generateEChart(options, tmpPath,echartJsPath);
        BufferedImage image = ImageIO.read(new File(dataPath));
        return image;
    }
    /**
     * 生成EChart图
     *
     * @param options      EChart初始化json
     * @param tmpPath      临时文件存放处
     * @param echartJsPath 第三方工具路径--也就是js的路径
     * @return
     */
    private static String generateEChart(String options, String tmpPath, String echartJsPath) {
        // 生成Echart的初始化json文件
        String dataPath = writeFile(options, tmpPath);
        // 生成随机文件名
        String fileName = UUID.randomUUID().toString().substring(0, 8) + ".png";
        String path = tmpPath + fileName;
        try {
            // 文件路径(路径+文件名)
            File file = new File(path);
            // 文件不存在则创建文件,先创建目录
            if (!file.exists()) {
                File dir = new File(file.getParent());
                dir.mkdirs();
                file.createNewFile();
            }

            // 这里只能写绝对路径,因为要执行系统命令行
            String cmd = phantomjsPath + " " +
                    echartJsPath +
                    " -infile " + dataPath +
                    " -outfile " + path;
            Process process = Runtime.getRuntime().exec(cmd);

            BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line = "";
            while ((line = input.readLine()) != null) {
                System.out.println(line);
            }
            input.close();

            // 删除生成的临时json文件
            File jsonFile = new File(dataPath);
            jsonFile.delete();
            return path;
        } catch (IOException e) {
            e.printStackTrace();
            return path;
        }
    }


    /**
     * 保存EChart临时json
     *
     * @param options echart初始化js
     * @param tmpPath 临时文件保存路径
     * @return 文件完整路径
     */
    private static String writeFile(String options, String tmpPath) {
        String dataPath = tmpPath + UUID.randomUUID().toString().substring(0, 8) + ".json";
        try {
            /* 写入Txt文件 */
            // 相对路径,如果没有则要建立一个新的output.txt文件
            File writeName = new File(dataPath);
            // 文件不存在则创建文件,先创建目录
            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;
    }
}

③:测试类

package com.kaigejava.demo5;

import cn.hutool.json.JSONUtil;
import com.github.abel533.echarts.Option;
import com.github.abel533.echarts.axis.CategoryAxis;
import com.github.abel533.echarts.code.Trigger;
import com.github.abel533.echarts.json.GsonOption;
import com.github.abel533.echarts.series.Line;
import com.kaigejava.EChartsUtil;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import static com.kaigejava.demo4.EChartWord.eChartJSPath;
import static com.kaigejava.demo4.EChartWord.eChartTempPath;

/**
 * @author 凯哥Java
 * @since 2023/5/24 17:07
 */
public class Demo5 {
    public static void main(String[] args) throws Exception {
        XWPFDocument doc = new XWPFDocument();
        XWPFParagraph p = doc.createParagraph();
        XWPFRun r = p.createRun();
        r.setText("图表展示");
        r.setColor("000000");
        r.setFontFamily("微软雅黑");
        r.setFontSize(18);

        String[] categories = {"周一", "周二", "周三", "周四", "周五", "周六", "周日"};
        Option option = createEchartsOption(categories);
        insertImageToWord(doc,option);
    }
    // 生成Echarts Option
    private static Option createEchartsOption(String[] categories) {
        GsonOption option = new GsonOption();
        option.title().text("某商场销售情况").subtext("纯属虚构");
        option.tooltip().trigger(Trigger.axis);
        option.legend().data("最高气温", "最低气温").left("center");
        option.xAxis(new CategoryAxis().data(categories));
        option.yAxis(new com.github.abel533.echarts.axis.ValueAxis());
        option.series(new Line().name("最高气温").data(11, 11, 15, 13, 12, 13, 10),
                new Line().name("最低气温").data(1, -2, 2, 5, 3, 2, 0));
        return option;
    }

    public static void insertImageToWord(XWPFDocument doc,Option dataOption) throws Exception {
        FileOutputStream out = new FileOutputStream(eChartTempPath+"output.docx");
        XWPFParagraph p = doc.createParagraph();
        XWPFRun r = p.createRun();
        String optionDataJson = JSONUtil.toJsonStr(dataOption);
        String imagePath = EChartsUtil.generateEChartConvertFilePath(optionDataJson, eChartTempPath,eChartJSPath);
        int format;
        switch (imagePath.substring(imagePath.lastIndexOf(".") + 1).toLowerCase()) {
            case "png":
                format = XWPFDocument.PICTURE_TYPE_PNG;
                break;
            case "jpg":
            case "jpeg":
                format = XWPFDocument.PICTURE_TYPE_JPEG;
                break;
            case "bmp":
                format = XWPFDocument.PICTURE_TYPE_BMP;
                break;
            default:
                throw new Exception("不支持该图片格式");
        }
        r.addPicture(new FileInputStream(new File(imagePath)), format, imagePath, Units.toEMU(450), Units.toEMU(250));
        doc.write(out);
        out.close();
    }
}

注意:需要生成Word之后,需要把生成的图片也删除掉。这里未处理

④:生成效果

28acd1809ae49660beb99bd377a9d1b8.png

2ee65259d0641c5070739fd6d9438395.png

TopTop