Freemarker和ItextPDF实际应用
1. FreeMarker模板文件路径
确保FreeMarker模板文件位于正确的路径,并通过Spring Boot自动加载。模板文件放在 src/main/resources/templates/
目录下,FreeMarker会自动处理这些文件。
@Configuration
public class FreeMarkerConfig {
@Value("${spring.freemarker.prefix:classpath:/templates/}")
private String freemarkerTemplatePrefix;
@Bean
public Configuration freemarkerConfiguration() {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_31);
try {
configuration.setDirectoryForTemplateLoading(new File(freemarkerTemplatePrefix));
} catch (IOException e) {
e.printStackTrace();
}
configuration.setDefaultEncoding("UTF-8");
return configuration;
}
}
2. 模板文件(template.ftl)
模板文件内容,放在 src/main/resources/templates/
目录下:
<!DOCTYPE html>
<html>
<head>
<title>${title}</title>
</head>
<body>
<h1>${title}</h1>
<p>${content}</p>
</body>
</html>
3. 图片路径(seal.png)
将章图片 seal.png
放在 src/main/resources/static/images/
目录下。Spring Boot会自动处理这些资源,你可以通过类加载器获取并加载它。
4. PDF生成逻辑(PDFGenerator.java)
改进后的 PDFGenerator.java
,支持动态加载模板和图片,生成带章的PDF文件,并灵活调整章的位置。
package com.example.demo;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.Image;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
@Service
public class PDFGenerator {
public void generatePdfWithSeal(String outputPdfPath, String sealImagePath) {
try {
// 模板数据
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("title", "带章的PDF文件");
dataModel.put("content", "这是一份动态生成的带章PDF文件。");
// FreeMarker模板文件路径
String templateFile = "template.ftl";
// 创建FreeMarker配置
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
cfg.setClassForTemplateLoading(PDFGenerator.class, "/templates"); // 设置模板目录
Template template = cfg.getTemplate(templateFile);
// 使用FreeMarker处理模板
StringWriter stringWriter = new StringWriter();
template.process(dataModel, stringWriter);
String generatedText = stringWriter.toString();
// 创建PDF文件
createPdfWithSeal(outputPdfPath, generatedText, sealImagePath); // 图片路径
} catch (Exception e) {
e.printStackTrace();
}
}
private void createPdfWithSeal(String outputPdfPath, String text, String sealImagePath) throws Exception {
// 创建一个空的PDF文件
OutputStream outputStream = new FileOutputStream(outputPdfPath);
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
// 添加内容
document.add(new Paragraph(text));
// 通过类加载器加载章图片(解决WAR包内路径问题)
InputStream sealInputStream = getClass().getClassLoader().getResourceAsStream(sealImagePath);
if (sealInputStream != null) {
Image sealImage = Image.getInstance(sealInputStream);
// 获取PDF页面的大小,并动态调整章位置
Rectangle pageSize = writer.getPageSize();
float x = pageSize.getWidth() - 150; // 章离右边缘150px
float y = pageSize.getHeight() - 150; // 章离下边缘150px
sealImage.setAbsolutePosition(x, y);
sealImage.scaleToFit(100, 100); // 调整章的大小
document.add(sealImage);
} else {
System.err.println("章文件未找到:" + sealImagePath);
}
document.close();
outputStream.close();
}
}
5. Spring Boot Controller(PDFController.java)
为了便于测试并下载生成的PDF文件,创建一个REST接口,返回PDF文件流。
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
@RestController
public class PDFController {
@Autowired
private PDFGenerator pdfGenerator;
@GetMapping("/generate-pdf")
public ResponseEntity<byte[]> generatePdf() throws IOException {
String outputPdfPath = "output.pdf";
String sealImagePath = "images/seal.png"; // 章图片路径
// 调用PDF生成方法
pdfGenerator.generatePdfWithSeal(outputPdfPath, sealImagePath);
File generatedFile = new File(outputPdfPath);
if (generatedFile.exists()) {
byte[] fileContent = Files.readAllBytes(generatedFile.toPath());
// 返回PDF文件作为下载
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"output.pdf\"")
.contentType(MediaType.APPLICATION_PDF)
.body(fileContent);
} else {
return ResponseEntity.status(500).body(null);
}
}
}
6. Spring Boot配置(application.properties)
确保配置了FreeMarker模板的正确路径,配置如下:
spring.freemarker.prefix=classpath:/templates/
spring.freemarker.suffix=.ftl
spring.freemarker.charset=UTF-8
7. 静态资源存放路径
将seal.png
放在src/main/resources/static/images/
目录下,这样Spring Boot会自动处理和提供访问。
8. 目录结构
确保项目目录结构如下:
src/
main/
java/
com/
example/
demo/
PDFGenerator.java // PDF生成逻辑
PDFController.java // REST控制器
DemoApplication.java // Spring Boot启动类
resources/
static/
images/
seal.png // 章图片
templates/
template.ftl // FreeMarker模板
application.properties // Spring Boot配置文件
9. 运行项目
-
启动项目:运行Spring Boot应用程序,可以使用命令:
mvn spring-boot:run
-
访问接口:打开浏览器或使用Postman访问:
http://localhost:8080/generate-pdf
这会触发PDF生成并返回下载链接。
10. 测试与调试
- 如果PDF文件生成成功,它会自动作为附件下载。
- 如果出现问题,检查控制台日志,确保:
- 图片路径正确。
- 模板路径正确。
- PDF文件生成没有错误。