当前位置: 首页 > news >正文

springboot之HTML与图片生成

背景

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

依赖

 <!-- 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格式模板)

<!-- 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相关类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ReceiptFieldDto {
    private String fieldName;
    private String fieldValue;
}

函数

/**
 * 获取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);
}

测试

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);
	}
}

相关文章:

  • IP属地是通过卫星定位的吗?如何保护用户隐私
  • mysql-analyze table导致waiting for table flush
  • 【AI+智造】在阿里云Ubuntu 24.04上部署DeepSeek R1 14B的完整方案
  • Redis---缓存穿透,雪崩,击穿
  • GNN入门与实践——基于GraphSAGE在Cora数据集上的节点分类研究
  • 思维训练(算法+技巧)
  • 大白话TypeScript第八章TypeScript 项目的部署与监控
  • Kafka零拷贝
  • springcloud组件调用顺序
  • 游戏引擎学习第128天
  • 1-3压缩命令
  • 内存中的缓存区
  • 数据结构:二叉搜索树(排序树)
  • 介绍一款飞算JavaAI编程工具,集成到idea,图文并茂
  • AcWing 5933:爬楼梯 ← 递归 / 递推 / 高精度
  • Vue 安装 wangEditor 富文本编辑器
  • 【Redis】Mac系统一键安装redis
  • Python基于Django和人脸识别的在线票务系统设计与实现
  • Java进阶——注解一文全懂
  • MR-图解
  • 做网站签到挣钱吗/北京seo包年
  • 衡水专业做wap网站/长沙网站seo外包
  • 文明网站建设方案/怎样搭建网站
  • 网站建设7个基/自学seo大概需要多久
  • 广告电商怎么做/seo推广费用
  • 做网站的技术要求/网站seo优化步骤