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);
	}
}
相关推荐
customer0819 分钟前
【开源免费】基于SpringBoot+Vue.JS酒店管理系统(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·开源
m0_7482347138 分钟前
Spring Boot 集成 Kafka
spring boot·kafka·linq
Code额1 小时前
SpringBoot 中的 Redis 序列化
spring boot·redis
武昌库里写JAVA1 小时前
【Redis学习】Redis Docker安装,自定义config文件(包括RDB\AOF setup)以及与Spring Boot项目集成
java·开发语言·spring boot·学习·课程设计
是一只派大鑫1 小时前
从头开始学SpringMVC—02获取请求参数&向域对象共享数据
java·后端·springmvc
咖啡の猫2 小时前
http 模块
后端·node.js
uhakadotcom2 小时前
Zip Slip漏洞:任意文件覆盖与远程代码执行
后端·面试·架构
一ge科研小菜鸡3 小时前
DeepSeek 与云原生后端:AI 赋能现代应用架构
后端
mengweijin4 小时前
华为 Open Gauss 数据库在 Spring Boot 中使用 Flyway
数据库·spring boot·华为·flyway·gauss
老大白菜4 小时前
基于Flask实现的多语言Hello World
后端·python·flask