java+thymeleaf+echartys实现图表导入到word

网上找过很多方法,但一直没有特别合适的直接导入方式,所以借鉴一篇博客的方法:先将echarts图表保存到本地临时文件,然后将文件添加到word摸板的对应位置,虽然比较繁琐,但摸板可调,操作更灵活。

参考博客连接:https://blinkfox.github.io/2018/10/01/hou-duan/java/shi-yong-java-diao-yong-phantomjs-dong-tai-dao-chu-echarts-tu-pian-dao-word-wen-jian-zhong/

首先测试将对应的数据新导入word摸板

新建word文档 test.docx,写好模板样式,可根据自己的需要自行添加,{{}}为你要填充的内容,固定不变文字可以提前写道模板里面

JAVA部分前期测试准备

开始写后台java代码部分,首先导入需要的依赖,因为后边会用到网页,和其他依赖这里一并导入

        <!--thymeleaf  web页面模板引擎 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!--lombok  类注释,省略getter setter方法-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--poi导出  导出word文档所需要的依赖-->
        <dependency>
            <groupId>com.deepoove</groupId>
            <artifactId>poi-tl</artifactId>
            <version>1.0.0</version>
        </dependency>

需要的java导出工具类 PoitlTest  这里是将本地存在的图片和自己构造的数据填充到模板中

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.PictureRenderData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * poi-tl库的使用示例.
 */
public class PoitlTest {
    private static final Logger log = LoggerFactory.getLogger(PoitlTest.class);

    /** word模板路径,这里为了方便直接采用真实路径 */
    private static final String DOC_PATH = "D:\\test\\test.docx";

    /** 要插入word的图片路径.  同上*/
    private static final String PIC_PATH = "D:\\test\\demo1.jpg";
    private static final String PIC_PATH1 = "D:\\test\\demo2.jpg";

    /** 输出文件及路径. */
    private static final String OUTPUT_PATH = "D:\\test\\poitl_out_word.docx";

    /**
     * 构造要填充的数据
     * Map或者是对象都可以(map的key为模板里面的填充标签,对象的属性名为模板里面的填充标签
     * @return map
     */
    private static Map<String,Object> buildBeanData() {
        Map<String,Object> map= new HashMap<>();
        map.put("title","导出word文档");
        map.put("smallTitle","数据图表信息");
        map.put("content1","图1");
        map.put("pic1",new PictureRenderData(600, 400, PIC_PATH));
        map.put("content2","图2");
        map.put("pic2",new PictureRenderData(600, 400, PIC_PATH1));
        return map;
    }

    /**
     *
     *   导出方法
     */
    public static void export() throws IOException {
        XWPFTemplate template = XWPFTemplate.compile(DOC_PATH).render(buildBeanData());
        FileOutputStream out = new FileOutputStream(OUTPUT_PATH);
        template.write(out);
        out.flush();
        out.close();
        template.close();
        log.info("通过'poi-tl'导出word成功!");
    }
}

直接运行 export 方法测试输出word文档成功,效果展示如下

 

接下来使用echarts生成图表,并将生成的图表保存到word

我们思路是echarts图片再页面显示,点击导出后先将图片存到本地,然后放入模板,因为我用到是thymeleaf引擎,需要在配置文件添加thymeleaf配置内容

spring.thymeleaf.prefix= classpath:/templates/  #页面所在位置
spring.thymeleaf.suffix= .html    #后缀

index.html页面内容为

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>测试的ECharts数据统计图</title>
</head>
<body>
<!-- 导出按钮 -->
<button id="button">button</button><br/><br/>
<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM 因为我们是两张图,所以准备了两个DOM-->
<div id="main1" style="width:560px; height:270px;"></div><br/>
<div id="main2" style="width:560px; height:270px;"></div><br/>
<!-- 引入用到的js文件  两文件存放在resources/static目录下 -->
<script type="text/javascript" src="jquery-3.4.1.min.js"></script>
<script type="text/javascript" src="echarts.js"></script>
<script type="text/javascript">
    //暂时使用的静态数据
    // 基于准备好的dom,初始化echarts实例
    var myChart1 = echarts.init(document.getElementById('main1'));
    // 指定图表的配置项和数据
    var option1 = {
        title: {
            text: 'ECharts 入门示例1'
        },
        animation: false, // 关闭动画效果
        tooltip: {},
        legend: {
            data:['销量']
        },
        xAxis: {
            data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
        },
        yAxis: {},
        series: [{
            name: '销量',
            type: 'bar',
            data: [5, 20, 36, 10, 10, 20]
        }]
    };
    // 使用刚指定的配置项和数据显示图表。
    myChart1.setOption(option1);


    var myChart2 = echarts.init(document.getElementById('main2'));
    var option2 = {
        title: {
            text: 'ECharts 入门示例2'
        },
        animation: false, // 关闭动画效果
        tooltip: {},
        legend: {
            data:['销量']
        },
        xAxis: {
            data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
        },
        yAxis: {},
        series: [{
            name: '销量',
            type: 'bar',
            data: [5, 20, 36, 10, 10, 20]
        }]
    };
    myChart2.setOption(option2);

    //点击按钮方法触发请求
    $("#button").click(postImage());
    /**
     * ajax传输图片信息到后台保存
     */
    function postImage() {
        // 向后台发起请求保存图片到指定目录.
        $.ajax({
            type: 'POST',
            url: '/saveImage',
            data: {picInfo1: myChart1.getDataURL(),picInfo2:myChart2.getDataURL()},
            success: function() {
                console.log('通过post请求传输数据成功!');
            }
        });
    }
</script>
</body>
</html>

后台请求的controller方法内容为,在方法中导出word文档时应该动态传入你设置保存图片的路径,此处只为演示所以没改,各位看客可以根据自己的需要更改一下,未修改记得将导出类的图片路径修改为你导出图片的路径

import com.example.practice.word.PoitlTest;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

@CrossOrigin
@RestController
public class AdminController {

    private static final Logger log = LoggerFactory.getLogger(AdminController.class);

    @PostMapping("saveImage")
    public void getAdmin(HttpServletRequest request) {
        // 获取图片信息.其实是图片解析为base64的编码
        String picInfo1 = request.getParameter("picInfo1");
        String picInfo2 = request.getParameter("picInfo2");
        if (StringUtils.isBlank(picInfo1) || StringUtils.isBlank(picInfo2)) {
            log.error("picInfo为空,未从前台获取到base64图片信息!");
            return;
        }
        //存放图片的位置
        getAndsaveImage(picInfo1, "D:\\test\\image1.png");
        getAndsaveImage(picInfo2, "D:\\test\\image2.png");
        //生成word文档
        try {
            //此处应该改为将图片地址动态的传入,博主未改,各位看客见谅
            PoitlTest.export();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("导出成功");
    }
    
    /**
     * 获取并保存图片到本地.
     *
     * @param picInfo   图片信息
     * @param imagePath 图片保存的路径
     */
    private void getAndsaveImage(String picInfo, String imagePath) {
        // 传递过程中  "+" 变为了 " ".
        String newPicInfo = picInfo.replaceAll(" ", "+");
        String picPath = decodeBase64(newPicInfo, imagePath);
        log.warn("从echarts中生成图片的的路径为:{}", picPath);
    }

    /**
     * 解析Base64位信息并输出到某个目录下面.
     *
     * @param base64Info base64串
     * @param picPath    生成的文件路径
     * @return 文件地址
     */
    private String decodeBase64(String base64Info, String picPath) {
        if (StringUtils.isEmpty(base64Info)) {
            return null;
        }

        // 数据中:data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABI4AAAEsCAYAAAClh/jbAAA ...  在"base64,"之后的才是图片信息
        String[] arr = base64Info.split("base64,");

        // 将图片输出到系统某目录.
        OutputStream out = null;
        try {
            // 使用了Apache commons codec的包来解析Base64
            byte[] buffer = Base64.decodeBase64(arr[1]);
            out = new FileOutputStream(picPath);
            out.write(buffer);
        } catch (IOException e) {
            log.error("解析Base64图片信息并保存到某目录下出错!", e);
        } finally {
            IOUtils.closeQuietly(out);
        }
        return picPath;
    }
}

验证效果:在浏览器输入localhost:8080

点击button,导出到word,查看word内容

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值