Java服务端使用freemarker+wkhtmltoimage生成Echart图片

目录

1.通过 freemarker 将ftl转成html

1.1 freemarker 手册: 

1.2 添加freemarker maven依赖

1.3 添加 echart-test.ftl 模版文件

1.4 添加 FreemarkerTool 工具类

1.5 添加测试main方法

1.6 运行,生成echart-test-时间戳.html 文件

2. 通过wkhtmltoimage将html 转为png图片

2.1 下载 wkhtmltoimage

 2.2 下载后安装(略)

 2.3 添加 WkhtmltopdfTool 工具类

2.4 添加 HtmlToPdfThread 工具类

 2.5 添加main方法测试

2.6 运行,生成 echart-test-时间戳.png 图片

2.7 注意


1.通过 freemarker 将ftl转成html

1.1 freemarker 手册: 

FreeMarker 中文官方参考手册​​​​​​​

Echart官网 Examples - Apache ECharts

1.2 添加freemarker maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
    <version>2.5.1</version>
</dependency>

1.3 添加 echart-test.ftl 模版文件

文件内容:

<html>

<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <title>ECharts Demo</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.2.2/echarts.min.js"
            integrity="sha512-ivdGNkeO+FTZH5ZoVC4gS4ovGSiWc+6v60/hvHkccaMN2BXchfKdvEZtviy5L4xSpF8NPsfS0EVNSGf+EsUdxA=="
            crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <style>
        body {
            margin: 0;
            display: flex;
            flex-direction: row;
            justify-content: center;
        }
        #display-container {
            width: 600px;
            height: 600px;
            border: 2px solid black;
        }
    </style>
</head>

<body>
<div id="container">

    <div id="display-container">
    </div>
</div>

<script type="text/javascript">

    var chart = echarts.init(document.getElementById("display-container"));
    var option = {
        "animation": false,

        "xAxis": {
            "type": "category",
            "axisTick": {
                "alignWithLabel": true
            },
            "data": ${xAxisData!'[]'}
        },
        "yAxis": {
            "type": "value"
        },
        "tooltip": {
            "axisPointer": {
                "type": "shadow"
            },
            "trigger": "axis"
        },
        "series": [
            {
                "type": "bar",
                "name": "Direct",
                "data": ${yAxisData!'[]'},
                "barWidth": "60%"
            }
        ]
    }
    chart.setOption(option);
</script>
</body>

</html>

1.4 添加 FreemarkerTool 工具类

package com.hanyc.demo.util;

import cn.hutool.core.collection.ListUtil;
import com.alibaba.fastjson.JSON;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author :hanyc
 * @date :2024/1/25 11:15
 * @description:
 */
@Slf4j
public class FreemarkerTool {

    /**
     * 根据模板,利用提供的数据,生成文件
     *
     * @param sourceFile 模板文件名
     * @param data       模版数据
     * @param destFile   最终生成的文件,需要携带路径
     */
    public static void data2html(String sourceFile, Map<String, Object> data, String destFile) throws IOException, TemplateException {

        // 如果文件夹不存在 则创建
        FileUtil.createFile(new File(destFile));
        Writer out = null;
        try {
            out = new FileWriter(new File(destFile));
            Configuration cfg = new Configuration(Configuration.VERSION_2_3_29);
            // 文件所在位置目录
            cfg.setDirectoryForTemplateLoading(new File("D:/code/springbootdemo2/src/main/resources/template/"));
            Template template = cfg.getTemplate(sourceFile);
            template.process(data, out);
        } catch (Exception e) {
            log.error("模板生成报告html文件异常", e);
            throw e;
        } finally {
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

1.5 添加测试main方法

public static void main(String[] args) throws IOException, InterruptedException, TemplateException {
	// 文件名
	String sourceFile = "echart-test.ftl";
	// 渲染存储数据
	Map<String, Object> datas = new HashMap<String, Object>();
	List<String> xAxisData = ListUtil.of("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun");
	datas.put("xAxisData", JSON.toJSONString(xAxisData));
	List<Integer> yAxisData = ListUtil.of(10, 52, 200, 334, 390, 330, 220);
	datas.put("yAxisData", JSON.toJSONString(yAxisData));
	//最终生成的文件路径
	String destFile = "D:\\code\\springbootdemo2\\src\\main\\resources\\template\\echart-test-" + System.currentTimeMillis() + ".html";

	data2html(sourceFile, datas, destFile);

}

1.6 运行,生成echart-test-时间戳.html 文件

2. 通过wkhtmltoimage将html 转为png图片

2.1 下载 wkhtmltoimage

  • 官网地址:wkhtmltopdficon-default.png?t=N7T8https://wkhtmltopdf.org/
  • 官网下载地址:wkhtmltopdficon-default.png?t=N7T8https://wkhtmltopdf.org/downloads.html

 2.2 下载后安装(略)

 2.3 添加 WkhtmltopdfTool 工具类

package com.hanyc.demo.util;

import cn.hutool.core.collection.ListUtil;
import com.alibaba.fastjson.JSON;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author :hanyc
 * @date :2024/1/25 9:33
 * @description: wkhtmltopdf 工具类
 */
@Slf4j
public class WkhtmltopdfTool {
    private static final String WKHTMLTOPDF_PATH = "D:\\ruanjian\\wkhtmltopdf\\bin\\wkhtmltoimage.exe"; // 替换为实际路径

    /**
     * html转pdf
     *
     * @param srcPath  html路径,可以是硬盘上的路径,也可以是网络路径
     * @param destPath 图片保存路径
     * @param width    宽度
     */
    public static void convert(String srcPath, String destPath, Integer width) throws IOException, InterruptedException {
        File file = new File(destPath);
        File parent = file.getParentFile();
        //如果pdf保存路径不存在,则创建路径
        if (!parent.exists()) {
            parent.mkdirs();
        }

        StringBuilder cmd = new StringBuilder();
        cmd.append(WKHTMLTOPDF_PATH);
        cmd.append(" ");
        // 去掉左右 边距
//        cmd.append(" --margin-left 0mm --margin-right 0mm  --margin-top 0mm  --margin-bottom 5mm ");
//        cmd.append("   --enable-local-file-access ");
        //设置页面上边距 (default 10mm)
//        cmd.append("  --margin-top 0mm ");
        //设置页面下边距 (default 10mm)
//        cmd.append("  --margin-bottom 0mm ");
        // (设置页眉和内容的距离,默认0)
//        cmd.append(" --header-spacing 0 ");
        // 添加页码
//        cmd.append("  --footer-center [page]/[topage] ");

//        1.--format.\<格式》:指定输出图像的格式。可以是PNG、JPEG、BMP等,默认为PNG。
        cmd.append(" --format png ");
        // 2 . –quality 75:就表示生成图片的质量为原来的 75%!
        cmd.append(" --quality 75 ");
//        3  --width \<宽度\>:设置输出图像的宽度。可以使用像素(如800px)或其他单位(如cm、mm等)指定,默认为 1024像素。
        if (width != null) {
            cmd.append(" --width ");
            cmd.append(width);
            cmd.append(" ");
        }
//        4 --height \<高度\>:设置输出图像的高度。同样可以使用像素或其他单位指定,默认为0,表示自适应高度。
//        cmd.append(" --height 600");
//        5 --crop-w \<宽度\>:将输入HI文档裁剪为指定宽度的图像。宽度单位与--width相同,默认为0,表示不进行裁剪。
//        6 --crop-h \高度\>:将输入HI文档裁剪为指定高度的图像。高度单位与--height相同,默认为0,表示不进行裁剪。
//        7 --crop-x\<x坐标\>:设置裁剪的左上角x坐标。默认为0。
//        8 --crop-y \<y坐标\>:设置裁剪的左上角y坐标。默认为0。
//        9. --no-outline:禁用轮廓线,即去掉输出图像中的边框线
//        10 .--no-background:禁用背景,即去掉输出图像中的背景色。
//        11 --disable-smart-width:禁用智能调整宽度,即不根据内容自适应调整宽度。
//        12 --transparent:将输出图像的背景色设置为透明。
//         13.--encoding<编码》>:设置HTML文档的字符编码
//        14.--quiet:静默模式,不输出任何日志信息。
//        15 --version:显示wkhtmltoimage的版本信息
        cmd.append(srcPath);
        cmd.append(" ");
        cmd.append(destPath);

        boolean result = true;
        try {
            log.info("执行命令:  {}", cmd.toString());
            Process proc = Runtime.getRuntime().exec(cmd.toString());
            HtmlToPdfThread error = new HtmlToPdfThread(proc.getErrorStream());
            HtmlToPdfThread output = new HtmlToPdfThread(proc.getInputStream());
            error.start();
            output.start();
            proc.waitFor();
        } catch (Exception e) {
            result = false;
            log.error("html转pdf fail:{}", e.getMessage(), e);
            throw e;
        }
    }
    }
}

2.4 添加 HtmlToPdfThread 工具类

package com.hanyc.demo.util;

import cn.hutool.core.io.IoUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

/**
 * @author :hanyc
 * @date :2023/4/26 14:44
 * @description: 流处理日志输出工具类
 */
@Slf4j
public class HtmlToPdfThread extends Thread {
    private InputStream is;

    public HtmlToPdfThread(InputStream is) {
        this.is = is;
    }

    @Override
    public void run() {
        BufferedReader br = null;
        try {
            InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
            br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null) {
                //输出内容
                log.info(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
            log.error("HtmlToPdfThread: ", e);
        } finally {
            IoUtil.close(is);
            IoUtil.close(br);
        }
    }
}

 2.5 添加main方法测试

    public static void main(String[] args) throws IOException, InterruptedException, TemplateException {
        String sourceFile = "D:\\code\\springbootdemo2\\src\\main\\resources\\template\\echart-test-1706154543908.html";
        String destFile = "D:\\code\\springbootdemo2\\src\\main\\resources\\template\\echart-test-1706154543908.png";
        WkhtmltopdfTool.convert(sourceFile, destFile,550);
    }

2.6 运行,生成 echart-test-时间戳.png 图片

2.7 注意

wkhtmltopdf / wkhtmltoimage 官网已经不再维护,如果生成的图片和原html不一样,或转化错误,可以尝试将js或css代码改为较原始的版本.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/349293.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【复现】JieLink+智能终端操作平台弱口令漏洞_28

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 JeLink智能终端操作平台 (JSOTC2016 fJeLink)是捷顺历经多年行业经验积累&#xff0c;集智能硬件技术视频分析技术、互联网技术等…

【HarmonyOS应用开发】ArkTS基础知识(三)

一、浅析ArkTS的起源和演进 1、引言 Mozilla创造了JS&#xff0c;Microsoft创建了TS&#xff0c;Huawei进一步推出了ArkTS。 从最初的基础的逻辑交互能力&#xff0c;到具备类型系统的高效工程开发能力&#xff0c;再到融合声明式UI、多维状态管理等丰富的应用开发能力&#xf…

如何解决服务器端口被占用的问题,减少带来的影响

在现代网络环境中&#xff0c;服务器扮演着至关重要的角色&#xff0c;其稳定性和安全性对企业的正常运营具有重要意义。然而&#xff0c;服务器端口被占用的问题却时常困扰着企业网络管理员。本文将深入探讨服务器端口被占用的影响&#xff0c;并提出相应的解决方案。 一、服务…

大数据学习之Redis、从零基础到入门(二)

二、Redis安装配置 1. VMWare本地虚拟机 VMWare准备的为64位 查看自己的VMWare是32位还是64位 getconf LONG_BIT 2. Redis的安装 2.1 系统选择 选择Linux系统 2.2 Linux版安装 2.2.1 Linux环境安装Redis必须先具备gcc编译环境 ①什么是gcc gcc是linux下的一个编译程序&…

Python模块与包:扩展功能、提高效率的利器

文章目录 一、引言1.1 模块与包对于Python开发的重要性1.2 Python作为拥有丰富生态系统的编程语言 二、为什么学习模块与包2.1 复用代码&#xff1a;利用现有模块与包加速开发过程2.2 扩展功能&#xff1a;通过模块与包提供的功能增强应用的能力 三、模块的使用3.1 导入模块&am…

网站域名一定要部署SSL证书吗?

随着互联网的发展&#xff0c;网络安全问题越来越受到重视。为网站域名部署SSL证书更是成为站长们维护网站安全的基础措施之一&#xff0c;但是这并非是强制性的&#xff0c;因此有不少人对部署SSL证书的必要性产生疑惑&#xff0c;网站域名一定要部署SSL证书吗&#xff1f;在本…

part1. jdk8新特性详解

1.Lambda //1.匿名内部类new Thread(new Runnable() {Overridepublic void run() {System.out.println("新线程中执行的代码&#xff1a;"Thread.currentThread().getName());}}).start();System.out.println("主线程中的代码:"Thread.currentThread().ge…

CI/CD

介绍一下CI/CD CI/CD的出现改变了开发人员和测试人员发布软件的方式,从最初的瀑布模型,到最后的敏捷开发(Agile Development),再到今天的DevOps,这是现代开发人员构建出色产品的技术路线 随着DevOps的兴起,出现了持续集成,持续交付和持续部署的新方法,传统的软件开发和交付方…

Maven(上):Maven介绍、安装配置及工程构建

1. Maven介绍 Maven 是一款为 Java 项目管理构建、依赖管理的工具&#xff08;软件&#xff09;&#xff0c;使用 Maven 可以自动化构建、测试、打包和发布项目&#xff0c;大大提高了开发效率和质量。 Maven就是一个软件&#xff0c;掌握安装、配置、以及基本功能 &#xff…

19 python快速上手

面向对象高级和应用 1. 继承【补充】1.1 mro和c3算法1.2 py2和py3区别&#xff08;了解&#xff09; 2. 内置函数补充3.异常处理3.1 异常细分3.2 自定义异常&抛出异常3.4 特殊的finally 4.反射4.1 一些皆对象4.2 import_module 反射 总结 各位小伙伴想要博客相关资料的话关…

vue3---inputRef.value.focus()报错Cannot read properties of null (reading ‘focus‘)

问题描述&#xff1a;点击编辑按钮&#xff0c;出现el-input框&#xff08;el-input显示隐藏通过v-if控制&#xff09; <el-input ref"inputRef" v-if"isEdit" v-model"modelName" blur"isEdit false" /> <el-button text …

python-自动化篇-办公-excel-实例应用(一维转二维)

文章目录 准备代码效果 准备 放根目录 代码 import openpyxl wbopenpyxl.load_workbook(业绩表.xlsx) if not 二维表 in wb.sheetnames:nwswb.create_sheet(二维表)wswb.worksheets[0]rngslist(ws.values)[1:]mmlist({m.value: for m in ws[b][1:]})namelist({m.value: for …

(2)(2.8) Holybro 900Mhz XBP9X无线电遥测设备

文章目录 前言 1 特点 2 规格 3 电源 4 引脚输出 5 下载 前言 Holybro XBP9X 无线电设备可使用 Digi 免费的 XCTU 软件或通过 Digi 简化的 AT 或 API 命令集轻松进行配置。无线电台采用 256 位 AES 加密技术&#xff0c;可在设备之间安全可靠地传输关键数据。无线电的射…

基于Kubernetes(K8s)构建企业容器云基础运行环境

cncfstack 新 文章上线&#xff1a; 书名&#xff1a;《云原生解决方案》 地址&#xff1a;https://zhaowenyu.com/cncf-solution 访问&#xff1a;文章底部“阅读原文”或访问域名 云原生计算是云计算发展新的里程碑阶段&#xff0c;是当今与未来很长一段时间中 IT 发展的技…

代码随想录 Leetcode111. 二叉树的最小深度

题目&#xff1a; 代码(首刷自解 2024年1月24日&#xff09;&#xff1a; class Solution { public:int minDepth(TreeNode* root) {if(root nullptr) return 0;queue<TreeNode*> que;TreeNode* cur root;que.push(cur);int size 0;int depth 0;while (!que.empty()…

Tomcat session复制及session共享技术

目录 1、环境 2、配置测试页面 3、配置session共享 前言&#xff1a; 为什么要做session复制或共享 实现Session复制或Session共享的目的是为了在多个Tomcat实例之间实现Session的无缝转移和共享&#xff0c;以提供更高的可伸缩性、负载均衡和容错性。以下是一些原因&#x…

C语言基本概念

目录 2.1 编写一个简单的C程序 2.1.1 编译和链接 2.1.2 集成开发环境 2.2 简单程序的一般形式 2.2.1 指令 2.2.2 函数 2.2.3 语句 2.3 注释 2.4 变量和赋值 2.4.1 类型 2.4.2 声明 2.4.3 赋值 2.4.4 显示变量的值 2.4.5 初始化 2.4.6 显示表达式的值 2.5 读入…

7款值得去尝试的前端动画特效(附效果图及在线演示)

分享7款好玩的前端动画特效 其中有CSS动画、canvas动画、js小游戏等等 下方效果图可能不是特别的生动 那么你可以点击在线预览进行查看相应的动画特效 同时也是可以下载该资源的 橙汁粒子特效 一款基于canvas实现的粒子动画特效 点击杯子 杯子上方会有橙子掉落至杯中并变为橙…

如何做标准化?| 京东云技术团队

在现代信息化的市场环境和社会中&#xff0c;标准化已经成为了各种行业的一个重要的标志。标准化不仅可以提升生产效率&#xff0c;减轻质量问题&#xff0c;还可以增加产品的可靠性和互通性。在这篇文章中&#xff0c;我们将探讨如何做标准化&#xff0c;为您提供详细的指导和…

深入理解Java类和对象的关系

如果要说清楚对象和类的关系&#xff0c;不可避免的要提到C&#xff0c;因为Java从时间线上来说&#xff0c;是C和C之后的一门语言&#xff0c;很多Java Coder 也是因为厌烦了C的一些特性&#xff0c;进而从事于Java开发的&#xff0c;所以以下内容会利用C的一部分知识来对比&a…