需求是导出word,里面有数据统计图表。

要从后端直接导出图表的话,思路是这样的:

  先通过echarts生成图片,通过phantomjs 截图,将图片暂存在本地,再将图片转换成base64,然后放入word。

 

phantomjs 是一个基于js的webkit内核无头浏览器 也就是没有显示界面的浏览器。

 

一、准备word模板,转换成xml,需要填入数据的地方用${字段},需要天出图片的地方可以先随便一张用图片替代,方便之后找到图片插入位置。这里就不多说了

 

二、准备环境、依赖

 1、准备js,需要用到的,放在同一个文件夹下面。自己更改echarts-convert.js的路径

  

java导图 java导出图表_数据

 

 

   echarts.min.js 和jquery.js 去官网下载

  echarts-convert.js的内容如下:

  

(function () {
    var system = require('system');
    var fs = require('fs');
    var config = {
        // define the location of js files
        //这样写要求这三个js在同一个文件夹下
        JQUERY: 'jquery-3.5.1.min.js',
        //ESL: 'esl.js',
        ECHARTS: 'echarts.min.js',
        // default container width and height
        DEFAULT_WIDTH: '400',
        DEFAULT_HEIGHT: '600'
    }, parseParams, render, pick, usage;

    usage = function () {
        console.log("\nUsage: phantomjs echarts-convert.js -options options -outfile filename -width width -height height"
            + "OR"
            + "Usage: phantomjs echarts-convert.js -infile URL -outfile filename -width width -height height\n");
    };

    pick = function () {
        var args = arguments, i, arg, length = args.length;
        for (i = 0; i < length; i += 1) {
            arg = args[i];
            if (arg !== undefined && arg !== null && arg !== 'null' && arg != '0') {
                return arg;
            }
        }
    };

    parseParams = function () {
        var map = {}, i, key;
        if (system.args.length < 2) {
            usage();
            phantom.exit();
        }
        for (i = 0; i < system.args.length; i += 1) {
            if (system.args[i].charAt(0) === '-') {
                key = system.args[i].substr(1, i.length);
                if (key === 'infile') {
                    // get string from file
                    // force translate the key from infile to options.
                    key = 'options';
                    try {
                        map[key] = fs.read(system.args[i + 1]).replace(/^\s+/, '');
                    } catch (e) {
                        console.log('Error: cannot find file, ' + system.args[i + 1]);
                        phantom.exit();
                    }
                } else {
                    map[key] = system.args[i + 1].replace(/^\s+/, '');
                }
            }
        }
        return map;
    };

    render = function (params) {
        var page = require('webpage').create(), createChart;

        var bodyMale = config.SVG_MALE;
        page.onConsoleMessage = function (msg) {
            console.log(msg);
        };

        page.onAlert = function (msg) {
            console.log(msg);
        };

        createChart = function (inputOption, width, height,config) {
            var counter = 0;
            function decrementImgCounter() {
                counter -= 1;
                if (counter < 1) {
                    console.log(messages.imagesLoaded);
                }
            }

            function loadScript(varStr, codeStr) {
                var script = $('<script>').attr('type', 'text/javascript');
                script.html('var ' + varStr + ' = ' + codeStr);
                document.getElementsByTagName("head")[0].appendChild(script[0]);
                if (window[varStr] !== undefined) {
                    console.log('Echarts.' + varStr + ' has been parsed');
                }
            }

            function loadImages() {
                var images = $('image'), i, img;
                if (images.length > 0) {
                    counter = images.length;
                    for (i = 0; i < images.length; i += 1) {
                        img = new Image();
                        img.onload = img.onerror = decrementImgCounter;
                        img.src = images[i].getAttribute('href');
                    }
                } else {
                    console.log('The images have been loaded');
                }
            }
            // load opitons
            if (inputOption != 'undefined') {
                // parse the options
                loadScript('options', inputOption);
                // disable the animation
                options.animation = false;
            }

            // we render the image, so we need set background to white.
            $(document.body).css('backgroundColor', 'white');
            var container = $("<div>").appendTo(document.body);
            container.attr('id', 'container');
            container.css({
                width: width,
                height: height
            });
            // render the chart
            var myChart = echarts.init(container[0]);
            myChart.setOption(options);
            // load images
            loadImages();
            return myChart.getDataURL();
        };

        // parse the params
        page.open("about:blank", function (status) {
            // inject the dependency js
            page.injectJs(config.ESL);
            page.injectJs(config.JQUERY);
            page.injectJs(config.ECHARTS);


            var width = pick(params.width, config.DEFAULT_WIDTH);
            var height = pick(params.height, config.DEFAULT_HEIGHT);

            // create the chart
            var base64 = page.evaluate(createChart, params.options, width, height,config);
            fs.write("base64.txt",base64);
            // define the clip-rectangle
            page.clipRect = {
                top: 0,
                left: 0,
                width: width,

                height: height
            };
            // render the image
            page.render(params.outfile);
            console.log('render complete:' + params.outfile);
            // exit
            phantom.exit();
        });
    };
// get the args
    var params = parseParams();

// validate the params
    if (params.options === undefined || params.options.length === 0) {
        console.log("ERROR: No options or infile found.");
        usage();
        phantom.exit();
    }
// set the default out file
    if (params.outfile === undefined) {
        var tmpDir = fs.workingDirectory + '/tmp';
        // exists tmpDir and is it writable?
        if (!fs.exists(tmpDir)) {
            try {
                fs.makeDirectory(tmpDir);
            } catch (e) {
                console.log('ERROR: Cannot make tmp directory');
            }
        }
        params.outfile = tmpDir + "/" + new Date().getTime() + ".png";
    }

// render the image
    render(params);
}());

 

  2、安装phantomjs

    网站:https://phantomjs.org/download.html

    选择合适的版本,我下载的是windows的,下载解压

    

java导图 java导出图表_数据_02

 

 

     配置环境变量:

 

 

 

 

     

java导图 java导出图表_java导图_03

 

 

   

    然后测试是否安装成功,在命令行 输入:phantomjs -- version

    

java导图 java导出图表_List_04

 

 

     出现版本就表示安装成功了。

  

  3、构建echarts数据,就是option


    

<dependency>
     <groupId>com.github.abel533</groupId>
     <artifactId>ECharts</artifactId>
     <version>3.0.0.6</version>
</dependency>

 

三、生成echarts图表

  1、构建echarts 的数据option

   

/**
     * 构建柱状图
     * @param cate x轴数据
     * @param enterpriseCnt 数据
     * @return
     */
    private static String getOption(List<String> cate, List<Integer> enterpriseCnt){
        GsonOption option = new GsonOption();
        option.title().setText("测试点位数图片"); // 标题
        // 设置图例
        option.legend().data("点位数").x("center");

        Bar bar = new Bar();
        // x轴
        CategoryAxis category = new CategoryAxis();
        category.data(cate.toArray());

        //y 轴
        ValueAxis valueAxis = new ValueAxis();

        bar.data().addAll(enterpriseCnt); // 数据

        option.xAxis(category);  //x轴
        option.yAxis(valueAxis);  //y轴

        option.series(bar);// 多条柱子放多个bar就行

        String optionStr = option.toString().replace(" ", "");
        log.info(optionStr);
        return optionStr;
    }

  2、生成echarts图片

  

public static String generateEChart(String option, String filepath, String fileName) {
        String dataPath = writeOptionToFile(option, filepath); // 将option 数据写磁盘上用文件保存
        String path = filepath + fileName+".png"; //生成图片路径
        try {
            String JSpath = "D:\\data\\tmp\\echarts-convert.js";
            String cmd = "phantomjs " + JSpath + " -infile " + dataPath + " -outfile " + path;
            log.info(cmd);
            Process process = Runtime.getRuntime().exec(cmd);
            BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            String line = "";
            while ((line = input.readLine()) != null) {
                log.info(line);
            }
            input.close();
            // 删除json数据
            File jsonFile = new File(dataPath);
            jsonFile.delete();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return path;
    }

  

public static String writeOptionToFile(String options, String filepath) {
        String dataPath = filepath +"echart.json";
        try {
            File writename = new File(dataPath);
            if (!writename.getParentFile().exists()) {   //文件目录不存在,则先创建,不然会报错
                writename.getParentFile().mkdirs();
            }
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(writename), "UTF-8"));
            out.write(options);
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return dataPath;
    }

 

  先测试一哈:

   

java导图 java导出图表_java导图_05

  这个时候在文件夹下可以看到图片啦:

  

java导图 java导出图表_数据_06

 

 

 

四、导出word

  准备好数据,图片需要base64编码的,将之前生成的echart图片读入转base64

  

public static String imageToBase64(String imgPath) {
        InputStream in = null;
        byte[] data = null;
        try {
            in = new FileInputStream(imgPath);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch(Exception ex) {
            ex.printStackTrace();
        }
        Base64Encoder encoder = new Base64Encoder();
        return encoder.encode(data);
    }

  

  然后就是正常word的导出了