目录
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
- 官网地址:wkhtmltopdfhttps://wkhtmltopdf.org/
- 官网下载地址:wkhtmltopdfhttps://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代码改为较原始的版本.