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文件生成没有错误。

相关推荐
sinat_2622921142 分钟前
Java面试实战:音视频场景下的微服务架构与缓存技术剖析
java·spring boot·redis·微服务·kafka·分布式系统·面试技巧
ghost14344 分钟前
C#学习第18天:特性(Attributes)
开发语言·学习·c#
mask哥1 小时前
详解springcloudalibaba采用prometheus+grafana实现服务监控
java·nacos·springboot·grafana·prometheus·springcloud·微服务监控
振鹏Dong1 小时前
Java基础&集合 面试经典八股总结 [连载ing]
java
会讲英语的码农1 小时前
php基础
开发语言·后端·php
不当菜虚困5 小时前
JAVA设计模式——(二)组合模式
java·设计模式·组合模式
ptu小鹏5 小时前
类和对象(中)
开发语言·c++
jack_xu6 小时前
经典大厂面试题——缓存穿透、缓存击穿、缓存雪崩
java·redis·后端
CHQIUU7 小时前
Java 设计模式心法之第4篇 - 单例 (Singleton) 的正确打开方式与避坑指南
java·单例模式·设计模式
Bayi·7 小时前
前端面试场景题
开发语言·前端·javascript