Freemarker和ItextPDF实际应用

1. FreeMarker模板文件路径

确保FreeMarker模板文件位于正确的路径,并通过Spring Boot自动加载。模板文件放在 src/main/resources/templates/ 目录下,FreeMarker会自动处理这些文件。

java 复制代码
@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/ 目录下:

ftl 复制代码
<!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文件,并灵活调整章的位置。

java 复制代码
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文件流。

java 复制代码
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模板的正确路径,配置如下:

properties 复制代码
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. 运行项目

  1. 启动项目:运行Spring Boot应用程序,可以使用命令:

    bash 复制代码
    mvn spring-boot:run
  2. 访问接口:打开浏览器或使用Postman访问:

    复制代码
    http://localhost:8080/generate-pdf

    这会触发PDF生成并返回下载链接。

10. 测试与调试

  1. 如果PDF文件生成成功,它会自动作为附件下载。
  2. 如果出现问题,检查控制台日志,确保:
    • 图片路径正确。
    • 模板路径正确。
    • PDF文件生成没有错误。

相关推荐
LUCIAZZZ9 分钟前
HikariCP数据库连接池原理解析
java·jvm·数据库·spring·springboot·线程池·连接池
sky_ph33 分钟前
JAVA-GC浅析(二)G1(Garbage First)回收器
java·后端
开发者工具分享36 分钟前
如何应对敏捷转型中的团队阻力
开发语言
gregmankiw43 分钟前
C#调用Rust动态链接库DLL的案例
开发语言·rust·c#
IDRSolutions_CN1 小时前
PDF 转 HTML5 —— HTML5 填充图形不支持 Even-Odd 奇偶规则?(第二部分)
java·经验分享·pdf·软件工程·团队开发
hello早上好1 小时前
Spring不同类型的ApplicationContext的创建方式
java·后端·架构
roman_日积跬步-终至千里1 小时前
【Go语言基础【20】】Go的包与工程
开发语言·后端·golang
秦少游在淮海1 小时前
C++ - string 的使用 #auto #范围for #访问及遍历操作 #容量操作 #修改操作 #其他操作 #非成员函数
开发语言·c++·stl·string·范围for·auto·string 的使用
const5441 小时前
cpp自学 day2(—>运算符)
开发语言·c++
心扬1 小时前
python生成器
开发语言·python