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("&", "&");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);}
}
相关文章:
springboot之HTML与图片生成
背景 后台需要根据字段动态生成HTML,并生成图片,发送邮件到给定邮箱 依赖 <!-- freemarker模板引擎--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifa…...
数据结构(初阶)(三)----单链表
单链表 概念 概念:链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 结点 与顺序表不同的是,链表的结构类似于带车头的火车车厢,,链表的每个车厢都是独立…...
ChatGPT与DeepSeek:AI语言模型的巅峰对决
目录 引言 一、ChatGPT 与 DeepSeek 简介 (一)ChatGPT (二)DeepSeek 二、技术原理剖析 (一)ChatGPT 技术原理 (二)DeepSeek 技术原理 (三)技术原理对比…...
DaoCloud 亮相 2025 GDC丨开源赋能 AI 更多可能
2025 年 2 月 21 日至 23 日,上海徐汇西岸,2025 全球开发者先锋大会以 “模塑全球,无限可能” 的主题,围绕云计算、机器人、元宇宙等多元领域,探讨前沿技术创新、应用场景拓展和产业生态赋能,各类专业论坛、…...
人工智能之数学基础:线性代数中矩阵的运算
本文重点 矩阵的运算在解决线性方程组、描述线性变换等方面发挥着至关重要的作用。通过对矩阵进行各种运算,可以简化问题、揭示问题的本质特征。在实际应用中,我们可以利用矩阵运算来处理图像变换、数据分析、电路网络等问题。深入理解和掌握矩阵的运算,对于学习线性代数以…...
(上)基于机器学习的图像识别——遥感图像分类(LeNet-5;AlexNet;VGGNet;GoogLeNet;ResNet)
遥感图像识别: 专业词汇: kernel:卷积 目录 遥感图像分类 1.1 LeNet-5 视频来源: 任务:使用什么网络实现遥感图像的分类 LeNet-5结构: 遥感图像分类 1.2 AlexNet(冠军) 视频…...
数据集笔记:NUSMods API
1 介绍 NUSMods API 包含用于渲染 NUSMods 的数据。这些数据包括新加坡国立大学(NUS)提供的课程以及课程表的信息,还包括上课地点的详细信息。 可以使用并实验这些数据,它们是从教务处提供的官方 API 中提取的。 该 API 由静态的…...
HTML元素,标签到底指的哪块部分?单双标签何时使用?
1. 标签(Tag) vs 元素(Element) 标签(Tag) 标签是 HTML 中用于定义元素的符号,用尖括号 < > 包裹。例如 <img> 是标签。元素(Element) 元素是由 标签 内容…...
基于ai技术的视频生成工具
一、通用型AI视频生成工具 腾讯智影 特点:支持数字人播报、文字转视频,提供免费模板和素材库,登录即送5分钟免费时长,每日签到可兑换额外额度。 限制:免费版分辨率较低,部分高级功能需付费。 LunaAI.vid…...
【Java 后端】Restful API 接口
Restful API 接口 REST:Representational State Transfer,表现层(前端的视图页面和后端的控制层)资源状态转移。 一种软件架构的风格(格式) RESTful 是目前最流行的互联网软件架构,如果一个架…...
Matlab地图绘制教程第2期—水陆填充图
上一期分享了海岸线图的绘制方法: 本着由浅入深的理念,本期再来分享一下水陆填充图的绘制方法。 先来看一下成品效果: 特别提示:Matlab地图绘制教程系列,旨在降低大家使用Matlab进行地图类科研绘图的门槛,…...
企业知识库搭建:14款开源与免费系统选择
本文介绍了以下14 款知识库管理系统:1.Worktile;2.PingCode;3.石墨文档; 4. 语雀; 5. 有道云笔记; 6. Bitrix24; 7. Logseq等。 在如今的数字化时代,企业和团队面临着越来越多的信息…...
【Linux系统】—— 冯诺依曼体系结构与操作系统初理解
【Linux系统】—— 冯诺依曼体系结构与操作系统初理解 1 冯诺依曼体系结构1.1 基本概念理解1.2 CPU只和内存打交道1.3 为什么冯诺依曼是这种结构1.4 理解数据流动 2 操作系统2.1 什么是操作系统2.2 设计OS的目的2.3 操作系统小知识点2.4 如何理解"管理"2.5 系统调用和…...
Android内存优化指南:从数据结构到5R法则的全面策略
目录 一、APP 内存限制 二、内存的三大问题 2.1、内存抖动(Memory Churn) 2.1.1 频繁创建短生命周期对象 2.1.2 系统API或第三方库的不合理使用 2.1.3 Handler使用不当 2.2、内存泄漏(Memory Leak) 2.2.1 静态变量持有Activity或Context引用 2.2.2 未取消的回调或…...
机器学习:线性回归,梯度下降,多元线性回归
线性回归模型 (Linear Regression Model) 梯度下降算法 (Gradient Descent Algorithm) 的数学公式 多元线性回归(Multiple Linear Regression)...
Linux上用C++和GCC开发程序实现两个不同MySQL实例下单个Schema稳定高效的数据迁移到其它MySQL实例
设计一个在Linux上运行的GCC C程序,同时连接三个不同的MySQL实例,其中两个实例中分别有两个Schema的表结构分别与第三实例中两个Schema个结构完全相同,同时复制两个实例中两个Schema里的所有表的数据到第三个实例中两个Schema里,使…...
RabbitMQ系列(一)架构解析
RabbitMQ 架构解析 RabbitMQ 是一个基于 AMQP 协议的开源消息中间件,其核心架构通过多组件协作实现高效、可靠的消息传递。以下是其核心组件与协作流程的详细说明: 一、核心组件与功能 Broker(消息代理服务器) RabbitMQ 服务端核…...
XSL 语言:XML 样式表的语言基础与应用
XSL 语言:XML 样式表的语言基础与应用 引言 XSL(Extensible Stylesheet Language)是一种专门用于XML文档样式的语言,它允许用户定义XML文档的格式、布局和外观。XSL是XML技术家族中的重要组成部分,与XML和XPATH等语言共同构成了处理和格式化XML文档的强大工具集。本文将…...
【计算机网络】常见tcp/udp对应的应用层协议,端口
TCP 和 UDP 对应的常见应用层协议 📌 基于 TCP 的应用层协议 协议全称用途默认端口HTTPHyperText Transfer Protocol超文本传输协议80HTTPSHTTP Secure加密的超文本传输协议443FTPFile Transfer Protocol文件传输协议(20 传输数据,21 控制连…...
ExpMoveFreeHandles函数分析和备用空闲表的关系
第一部分:ExpMoveFreeHandles和备用空闲表的关系 ULONG ExpMoveFreeHandles ( IN PHANDLE_TABLE HandleTable ) { ULONG OldValue, NewValue; ULONG Index, OldIndex, NewIndex, FreeSize; PHANDLE_TABLE_ENTRY Entry, FirstEntry; EXHAND…...
如何在macOS上轻松运行Windows应用:Whisky终极使用指南
如何在macOS上轻松运行Windows应用:Whisky终极使用指南 【免费下载链接】Whisky A modern Wine wrapper for macOS built with SwiftUI 项目地址: https://gitcode.com/gh_mirrors/wh/Whisky 想在Apple Silicon Mac上运行Windows软件,又不想安装笨…...
《病隙碎笔》生病卧床的日子,才知道拥有健康身心的时刻是多么宝贵
《病隙碎笔》生病卧床的日子,才知道拥有健康身心的时刻是多么宝贵 史铁生(1951/1/4-2010/12/31),作家,散文家,代表作有《我与地坛》《命若琴弦》《奶奶的星星》等。 湖南文艺出版社 文章目录《病隙碎笔》生…...
Unity图表性能优化:从折线图到饼图的底层实现与避坑指南
1. 为什么Unity里做图表不是“加个UI控件”就完事了? 在Unity项目里,当策划甩来一句“这个数据面板加个折线图展示用户留存率”,或者美术提出“战斗结算页需要动态饼图显示伤害来源分布”,很多开发者第一反应是:去Asse…...
【2026年世界模型最全综述】:从开山之作到Sora与Genie 3
论文信息 标题:Understanding World or Predicting Future? A Comprehensive Surveyof World Models会议:ACM Computing Surveys 2026(计算机领域顶级综述期刊)单位:清华大学FIB-Lab代码:https://github.c…...
学网安压根不卡学历,在校生自学这样走少绕好几年弯路
学网安压根不卡学历,在校生自学这样走少绕好几年弯路 前言 “网络安全只有计算机高材生才能学?” “没有名校背景,根本进不了这个行业?” “普通专科生、本科生、非科班出身想要自学网络安全,难度太大了吧…...
告别拥塞:手把手优化Dragonfly网络性能,UGAL-LVC_H算法详解与配置
告别拥塞:手把手优化Dragonfly网络性能,UGAL-LVC_H算法详解与配置 在数据中心网络架构中,Dragonfly拓扑以其高度可扩展性和低直径特性脱颖而出,成为超大规模计算环境的理想选择。然而,当面对对抗性流量模式时ÿ…...
Beyond Compare 5授权密钥生成器:一键激活与完整技术解析
Beyond Compare 5授权密钥生成器:一键激活与完整技术解析 【免费下载链接】BCompare_Keygen Keygen for BCompare 5 项目地址: https://gitcode.com/gh_mirrors/bc/BCompare_Keygen 在软件开发和日常工作中,文件对比工具Beyond Compare 5无疑是开…...
潜变量扩散模型原理:用宝可梦类比讲透Stable Diffusion核心机制
1. 项目概述:用宝可梦讲清楚潜变量扩散模型到底在做什么你有没有试过让AI画一只“皮卡丘和喷火龙的混血宝宝”?不是简单拼接,而是长着皮卡丘的圆脸、喷火龙的尾巴尖带火焰、耳朵轮廓像皮卡丘但末端微微上翘——这种既熟悉又陌生、细节合理又充…...
脉冲相机与NeRF结合的高速场景三维重建技术
1. 高速场景重建的技术挑战与解决方案在计算机视觉领域,高速场景的三维重建一直是个棘手的问题。传统RGB相机受限于曝光时间和帧率,在拍摄快速运动物体时会产生严重的运动模糊。这种模糊不仅影响视觉效果,更会破坏三维重建所需的几何和纹理信…...
平衡小车PID调参新思路:用合宙ESP32-C3的BLE功能实现无线数据收发(附完整Arduino代码)
平衡小车无线PID调参实战:基于ESP32-C3 BLE的实时数据交互方案 调试平衡小车时,最令人头疼的莫过于反复插拔USB线修改PID参数。我曾经历过这样的场景:小车在桌面上左右摇摆,我蹲在地上盯着串口数据,每次修改参数都要暂…...
