springboot之HTML与图片生成

背景

后台需要根据字段动态生成HTML,并生成图片,发送邮件到给定邮箱

依赖

xml 复制代码
 <!-- freemarker模板引擎-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
    <version>2.7.17</version>
</dependency>
<!-- 图片生成 -->
<dependency>
    <groupId>org.xhtmlrenderer</groupId>
    <artifactId>core-renderer</artifactId>
    <version>R8</version>
</dependency>

HTML模版 (ftl格式模板)

xml 复制代码
<!-- demo.ftl -->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>demo Receipt</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f0f0f0;
            margin: 20px;
        }
        hr {
            border: none;
            border-bottom:1px dashed black;
        }
        .receipt {
            background-color: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            width: 320px;
            text-align: center;
            margin: 0 auto;
        }
        .fieldLabel, .fieldMiddle, .fieldValue {
            margin: 0 auto; /* 使子元素水平居中 */
        }
        .fieldLabel {
            font-size: 14px;
            /*font-weight: bold;*/
            text-align: left;
        }
        .fieldMiddle {
            font-size: 14px;
            /*font-weight: bold;*/
            text-align: left;
        }
        .fieldValue {
            font-size: 14px;
            text-align: right;
        }
    </style>
</head>
<body>
<!-- <div style="text-align: center; padding: 20px"> -->
<div class="receipt">
    <table>
<#--        content1-->
        <#if content1??>
            <tr>
                <!-- 水平实线 -->
                <td colspan="10">
                    <hr/>
                </td>
            </tr>
            <#list content1 as item>
                <tr>
                    <td colspan="4" class="fieldLabel">
                        ${item.fieldName}
                    </td>
                    <td colspan="1" class="fieldMiddle">
                        :
                    </td>
                    <td colspan="5" class="fieldValue">
                        ${item.fieldValue}
                    </td>
                </tr>
            </#list>
        </#if>
<#--        content2-->
        <#if content2??>
            <tr>
                <!-- 水平实线 -->
                <td colspan="10">
                    <hr/>
                </td>
            </tr>
            <#list content2 as item>
                <tr>
                    <td colspan="4" class="fieldLabel">
                        ${item.fieldName}
                    </td>
                    <td colspan="1" class="fieldMiddle">
                        :
                    </td>
                    <td colspan="5" class="fieldValue">
                        ${item.fieldValue}
                    </td>
                </tr>
            </#list>
        </#if>
    </table>
</div>
</body>
</html>

ftl相关类

xml 复制代码
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ReceiptFieldDto {
    private String fieldName;
    private String fieldValue;
}

函数

java 复制代码
/**
 * 获取ftl模板转为html
 */
public static String ftlToString(Map<String, Object> map, String templateName) throws IOException,
        TemplateException {
    String value = "";
    Configuration configuration = new Configuration(Configuration.VERSION_2_3_32);
    // 模板路径
    String ftlPath = System.getProperty("user.dir") + File.separator + "templates";
    String encoding = "UTF-8";
    configuration.setDefaultEncoding(encoding);
    StringWriter out = new StringWriter();
    configuration.setDirectoryForTemplateLoading(new File(ftlPath));
    Template template = configuration.getTemplate(templateName, Locale.US, encoding);
    template.process(map, out);
    out.flush();
    out.close();
    value = out.getBuffer().toString();
    return value;
}

/**
* html: html内容
* inputFileName: 输入文件名绝对路径
* outputFileName: 输出文件名绝对路径
* widthImage:图片宽
* heightImage:图片高
*/
public static String turnImage(String html, String inputFileName, String outputFileName, int widthImage, int heightImage) throws IOException {
    File inputFile = new File(inputFileName);
    File inputDir = inputFile.getParentFile();
    if (!inputFile.exists()) {
        if (inputDir != null) {
            inputDir.mkdirs();
        }
        inputFile.createNewFile();
    }

    try (BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(inputFile), StandardCharsets.UTF_8))) {
        String specialHtml = html.replace("&", "&amp;");
        bufferedWriter.write(specialHtml);
        bufferedWriter.newLine();
    }

    File outputFile = new File(outputFileName);
    File outputDir = outputFile.getParentFile();
    if (!outputFile.exists()) {
        if (outputDir != null) {
            outputDir.mkdirs();
        }
        outputFile.createNewFile();
    }

    Java2DRenderer renderer = new Java2DRenderer(inputFile, widthImage, heightImage);
    BufferedImage image = renderer.getImage();
    FSImageWriter imageWriter = new FSImageWriter();
    imageWriter.setWriteCompressionQuality(0.9f);

    try (FileOutputStream fout = new FileOutputStream(outputFile)) {
        imageWriter.write(image, fout);
    }

    return outputFileName;
}

public static void deleteTempFolder(String folderPath) {
    FileUtils.deleteQuietly(new File(folderPath));
}

private void initMap(Map<String, Object> map) {
	ArrayList<ReceiptFieldDto> content1List = new ArrayList<>();
	content1List.add(new ReceiptFieldDto("第一行标题", "第一行内容"));
	map.put("content1", content1List);
	ArrayList<ReceiptFieldDto> content2List = new ArrayList<>();
	content2List.add(new ReceiptFieldDto("第二行标题", "第二行内容"));
	map.put("content2", content2List);
}

测试

xml 复制代码
public String generateImage(){
	UUID uuid = UUID.randomUUID();
	String tempFolder = System.getProperty("user.dir") + File.separator + "tmp" + File.separator + uuid.toString().replace("-", "");
	try {
		Map<String, Object> map = new HashMap<>();
		initMap(map);
		String html = ftlToString(map, "demo.ftl");
		String htmlPath = tempFolder + File.separator + "demo.html";
		String imagePath = tempFolder + File.separator + "demo.jpg";
		int imageWidth = 400;
		int imageHeight = 600;
		try {
			turnImage(html, htmlPath, imagePath, imageWidth, imageHeight);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return imagePath;
	} catch (Exception e) {
		e.printStackTrace();
	}finally {
		deleteTempFolder(tempFolder);
	}
}
相关推荐
武子康1 小时前
Java-80 深入浅出 RPC Dubbo 动态服务降级:从雪崩防护到配置中心秒级生效
java·分布式·后端·spring·微服务·rpc·dubbo
舒一笑2 小时前
我的开源项目-PandaCoder迎来史诗级大更新啦
后端·程序员·intellij idea
@昵称不存在3 小时前
Flask input 和datalist结合
后端·python·flask
zhuyasen3 小时前
Go 分布式任务和定时任务太难?sasynq 让异步任务从未如此简单
后端·go
东林牧之3 小时前
Django+celery异步:拿来即用,可移植性高
后端·python·django
超浪的晨4 小时前
Java UDP 通信详解:从基础到实战,彻底掌握无连接网络编程
java·开发语言·后端·学习·个人开发
AntBlack4 小时前
从小不学好 ,影刀 + ddddocr 实现图片验证码认证自动化
后端·python·计算机视觉
Pomelo_刘金5 小时前
Clean Architecture 整洁架构:借一只闹钟讲明白「整洁架构」的来龙去脉
后端·架构·rust
双力臂4045 小时前
Spring Boot 单元测试进阶:JUnit5 + Mock测试与切片测试实战及覆盖率报告生成
java·spring boot·后端·单元测试
CodeCraft Studio6 小时前
借助Aspose.HTML控件,在 Python 中将 HTML 转换为 Markdown
开发语言·python·html·markdown·aspose·html转markdown·asposel.html