(最新)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>
相关推荐
Haven-1 小时前
Java-面试八股文-JVM篇
java·jvm·面试
我真的是大笨蛋1 小时前
JVM调优总结
java·jvm·数据库·redis·缓存·性能优化·系统架构
wjs0401 小时前
Git常用的命令
java·git·gitlab
superlls2 小时前
(算法 哈希表)【LeetCode 349】两个数组的交集 思路笔记自留
java·数据结构·算法
田里的水稻2 小时前
C++_队列编码实例,从末端添加对象,同时把头部的对象剔除掉,中的队列长度为设置长度NUM_OBJ
java·c++·算法
ponnylv2 小时前
深入剖析Spring Boot启动流程
java·开发语言·spring boot·spring
前行的小黑炭2 小时前
Android 协程的使用:结合一个环境噪音检查功能的例子来玩玩
android·java·kotlin
李少兄3 小时前
解决IntelliJ IDEA 提交代码时无复选框问题
java·ide·intellij-idea
cyforkk3 小时前
Spring Boot @RestController 注解详解
java·spring boot·后端
叫我阿柒啊4 小时前
从Java全栈到前端框架:一次真实面试的深度复盘
java·spring boot·typescript·vue·database·testing·microservices