背景
后台需要根据字段动态生成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);
}
}