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