(最新)itext7 freemarker动态模板转pdf

1.引入依赖

复制代码
<!--PDF导出POM-->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext7-core</artifactId>
    <version>8.0.3</version>
    <type>pom</type>
</dependency>
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>html2pdf</artifactId>
    <version>5.0.3</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
</dependency>

2.编写FTL文件

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>

<style>
    .pic {
        width: 100%;
        height: 100%;
    }
</style>

<body>
<div id="app">
    <#--封面图-->
    <#if show>
        <img class="pic" src="${coverImageFile!''}"/>
    </#if>
</div>
</body>
</html>

3.后台代码

复制代码
@Resource
Configuration configuration;

/**
     * 导出
     */
    @Override
    public void export(HttpServletResponse response){
         //获取文件byte[]
        byte[] pdfBytes=getPdfBytes();
        try{
            //输出pdf文件
            String chineseName="中文文件名";
            response.setCharacterEncoding("utf-8");
            String fileName=URLEncoder.encode(chineseName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=" + fileName + ".pdf");
            //设置响应头(导出为pdf文件)
            response.setContentType("application/pdf");
            //设置响应头(返回流给前端预览使用)
            //response.setContentType("application/octet-stream;charset=UTF-8");
            // 获取HttpServletResponse的OutputStream
            OutputStream os=response.getOutputStream();
            // 写入字节流数组
            os.write(pdfBytes);
            os.flush();
            os.close();
        }catch(IOException e){
            throw new InvalidCmdException(e.getMessage());
        }
    }

private byte[] getPdfBytes(){
        //获取模板替换数据
        Map<String, Object> map=new HashMap<>();
        map.put("show", true);
        map.put("coverImageFile", "base64图片");
        try{
            //读取freemarker模板
            Template template=configuration.getTemplate("FTL文件路径");
            StringWriter out=new StringWriter();
            // 将数据模型合并到模板中生成HTML
            template.process(map, out);
            String htmlContent=out.toString();
            // 初始化字节输出流用于保存PDF
            ByteArrayOutputStream pdfOutput=new ByteArrayOutputStream();
            // 设置中文字体
            ConverterProperties converterProperties=new ConverterProperties();
            FontProvider fontProvider=new DefaultFontProvider(true, true, false);
            PdfDocument pdfDoc;
            FontProgram fontProgram=FontProgramFactory.createFont("static/simhei.ttf");
            // 添加中文字体到字体提供者
            fontProvider.addFont(fontProgram);
            converterProperties.setFontProvider(fontProvider);
            // 转换HTML到PDF
            try(ByteArrayOutputStream outputStream=pdfOutput){
                // 初始化文档
                PdfWriter writer=new PdfWriter(outputStream);
                pdfDoc=new PdfDocument(writer);
                //设置pdf纸张大小
                pdfDoc.setDefaultPageSize(PageSize.A4);
                // 将HTML转换为PDF
                HtmlConverter.convertToPdf(htmlContent, pdfDoc, converterProperties);
            }
            // 从字节输出流中获取PDF的字节数组
            byte[] pdfBytes=pdfOutput.toByteArray();
            // 关闭流
            pdfOutput.close();
            pdfDoc.close();
            out.close();
            return pdfBytes;
        }catch(IOException e){
            throw new InvalidCmdException("读取候选人freemarker模板错误");
        }catch(TemplateException e){
            throw new InvalidCmdException("替换模板值错误");
        }
    }

4.注意事项

itext7本身不支持中文 所以需要在项目中引入字体文件。

freemarker图片需要使用base64格式图片

byte[] 数组转base64

复制代码
 /**
     * 图片转base64
     */
    private String convertBase64(String ossFileId){
        if(String2Utils.isNotBlank(ossFileId)){
            //这里使用的是阿里的oss查询
            OssUrlDto ossUrlDto=ossFileService.findDfsById(ossFileId).orElse(null);
            try{
                byte[] adviserBytes=ossClientService.getContentByteByKey(ossUrlDto.getBucketName(), ossUrlDto.getPath());
                return "data:image/jpeg;base64," + Base64.getEncoder().encodeToString(adviserBytes);
            }catch(Exception e){
                throw new InvalidCmdException("图片转base64失败");
            }
        }
        return "";
    }

给导出的PDF设置页面边距,网上搜索了很多中办法,只有一种成功了

再FTL页面中添加

复制代码
<style>
    @page {
        size: A4;
        margin: 10mm;
    }
</style>
相关推荐
都叫我大帅哥42 分钟前
深入浅出 Resilience4j:Java 微服务的“免疫系统”实战指南
java·spring cloud
Cao_Shixin攻城狮3 小时前
Flutter运行Android项目时显示java版本不兼容(Unsupported class file major version 65)的处理
android·java·flutter
Dcs5 小时前
还在用 Arrays.hashCode?Java 自己也能写出更快的版本!
java
fouryears_234177 小时前
Spring,Spring Boot 和 Spring MVC 的关系以及区别
java·spring boot·spring·mvc
阿葱(聪)8 小时前
java 在k8s中的部署流程
java·开发语言·docker·kubernetes
浮生带你学Java8 小时前
2025Java面试题及答案整理( 2025年 7 月最新版,持续更新)
java·开发语言·数据库·面试·职场和发展
板板正8 小时前
SpringAI——提示词(Prompt)、提示词模板(PromptTemplate)
java·spring boot·ai·prompt
板板正8 小时前
SpringAI——对话记忆
java·spring boot·ai
期待のcode9 小时前
图片上传实现
java·前端·javascript·数据库·servlet·交互
李长渊哦9 小时前
深入理解Java中的Map.Entry接口
java·开发语言