简单介绍
概述
FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件
适用场景
- **模板化文档生成:**FreeMarker 是一个模板引擎,适用于生成具有固定格式的文档,比如发票、报告或合同。这些文档的结构和格式是固定的,但内容可以动态变化。
- **内容动态填充:**使用 FreeMarker,你可以创建 Word 文档模板,并在运行时将数据填充到模板中,生成最终的 Word 文件。例如,生成个性化的信件或文档报告。
- **简单文档生成:**适用于文档结构较为简单的场景,比如只包含文本和基本格式的文档。
准备工作
开发环境
正式开始之前,依然给出本文所基于的环境,避免环境问题可能给大家带来的影响。
- JDK 17(理论上推荐不低于 1.8 版本)
- IDEA INTELLIJ
- SpringBoot 2.x
添加 FreeMarker 依赖
<!--freemarker模板依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>4.0.3</version>
</dependency>
添加 FreeMarker 相关配置
添加依赖后,我们需要在项目配置文件 application.yml 中添加 FreeMarker 的相关配置。
spring:
freemarker:
# 模板路径
template-loader-path: template-loader-path: classpath:/static/templates/
# 模板后缀名
suffix: .ftl
# 页面编码
charset: utf-8
# 页面缓存
cache: false
# 文档类型
content-type: text/html
代码实现
工具类和模板
工具类
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URLEncoder;
import java.util.Map;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.layout.font.FontProvider;
import lombok.extern.slf4j.Slf4j;
import freemarker.template.Template;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
@Slf4j
@Component
public class ExportWordUtil {
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
private String encoding="utf-8";
/**
* 获取模板
*
* @param name
* @return
* @throws Exception
*/
public Template getTemplate(String name) throws Exception {
return freeMarkerConfigurer.getConfiguration().getTemplate(name);
}
/**
* 导出pdf文档到客户端
*
* @param response
* @param content
* @param fileName
* @throws Exception
*/
public void exportPdfToClient(HttpServletResponse response, String content, String fileName)
throws Exception {
response.reset();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/octet-stream");
// response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
// 把本地文件发送给客户端
ServletOutputStream outputStream = response.getOutputStream();
ConverterProperties converterProperties = new ConverterProperties();
converterProperties.setCharset("utf-8");
FontProvider fontProvider = new FontProvider();
fontProvider.addSystemFonts();
converterProperties.setFontProvider(fontProvider);
HtmlConverter.convertToPdf(content,outputStream,converterProperties);
}
/**
* 导出pdf文档项目根目录下
*
* @param content
* @param fileName
* @throws Exception
*/
public void exportPdfToProjectRoot( String content, String fileName)
throws Exception {
File file = new File(fileName);
FileOutputStream outputStream = new FileOutputStream(file);
ConverterProperties converterProperties = new ConverterProperties();
converterProperties.setCharset("utf-8");
FontProvider fontProvider = new FontProvider();
fontProvider.addSystemFonts();
converterProperties.setFontProvider(fontProvider);
HtmlConverter.convertToPdf(content,outputStream,converterProperties);
}
}
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.layout.font.FontProvider;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Map;
import java.util.Objects;
@Slf4j
@Component
public class HtmlUtils {
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
/**
* @return
* @throws Exception
*/
public String getTemplateDirectory() {
ClassLoader classLoader = HtmlUtils.class.getClassLoader();
URL resource = classLoader.getResource("templates");
try {
return Objects.requireNonNull(resource).toURI().getPath();
} catch (URISyntaxException e) {
log.error("获取模板文件夹失败,{}", e);
}
return null;
}
/**
* 获取模板内容
*
* @param templateName 模板文件名
* @param paramMap 模板参数
* @return
* @throws Exception
*/
public String getTemplateContent(String templateName, Map<String, Object> paramMap) throws Exception {
Configuration config = freeMarkerConfigurer.getConfiguration();
Template template = config.getTemplate(templateName);
return FreeMarkerTemplateUtils.processTemplateIntoString(template, paramMap);
}
}
模板
hello,${name}!
功能实现
导出到项目根目录
controller代码
import com.example.freemarker.util.ExportWordUtil;
import com.example.freemarker.util.HtmlUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
/**
* FreeMarker测试案例
*
* @PACKAGE_NAME: com.example.freemarker.controller
* @author: zqy
* @DATE: 2024/8/30 15:47
*/
@RestController
@RequestMapping("/freemarker")
@Slf4j
public class HelloController {
@Autowired
private ExportWordUtil exportWordUtil;
@Autowired
private HtmlUtils htmlUtils;
@GetMapping("/pdf/export/to-project-root")
public void exportPdfToProjectRoot(HttpServletRequest request, HttpServletResponse response) throws Exception {
String fileName = "test.pdf"; // 文件名称
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("name", "freemarker导出pdf"); // 设置要导出的数据,这里的title要和word模板中保持一致
String content = htmlUtils.getTemplateContent("test.ftl", dataMap);
exportWordUtil.exportPdfToProjectRoot(content, fileName);
}
}
导出到客户端
controller代码
import com.example.freemarker.util.ExportWordUtil;
import com.example.freemarker.util.HtmlUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
/**
* FreeMarker测试案例
*
* @PACKAGE_NAME: com.example.freemarker.controller
* @author: zqy
* @DATE: 2024/8/30 15:47
*/
@RestController
@RequestMapping("/freemarker")
@Slf4j
public class HelloController {
@Autowired
private ExportWordUtil exportWordUtil;
@Autowired
private HtmlUtils htmlUtils;
@GetMapping("/pdf/export/to-client")
public void exportPdfToClient(HttpServletRequest request, HttpServletResponse response) throws Exception {
String fileName = "test.pdf"; // 文件名称
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("name", "freemarker导出pdf"); // 设置要导出的数据,这里的title要和word模板中保持一致
String content = htmlUtils.getTemplateContent("test.ftl", dataMap);
exportWordUtil.exportPdfToClient(response,content, fileName);
}
}