JAVA生成PDF(itextpdf)

java生成PDF有多种方式,比如itextpdf、 Apache PDFBox、Flying Saucer (XHTMLRenderer)、 OpenPDF等。今天要介绍的是itextpdf,及在开发过程中处理的问题。

  1. 引入POM
XML 复制代码
            <!--PDF导出POM-->
            <dependency>
                <groupId>com.itextpdf</groupId>
                <artifactId>itextpdf</artifactId>
                <version>5.5.9</version>
            </dependency>
            <dependency>
                <groupId>com.itextpdf.tool</groupId>
                <artifactId>xmlworker</artifactId>
                <version>5.5.9</version>
            </dependency>
            <dependency>
                <groupId>com.itextpdf</groupId>
                <artifactId>itext-asian</artifactId>
                <version>5.2.0</version>
            </dependency>
            <dependency>
                <groupId>org.xhtmlrenderer</groupId>
                <artifactId>flying-saucer-pdf</artifactId>
                <version>9.0.3</version>
            </dependency>

            <dependency>
                <groupId>org.freemarker</groupId>
                <artifactId>freemarker</artifactId>
                <version>2.3.28</version>
            </dependency>
  1. 导出工具类
java 复制代码
import cn.hutool.core.io.FileUtil;
import com.jxdj.framework.common.domain.exception.CustomException;
import com.lowagie.text.pdf.BaseFont;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.nio.file.Paths;
import java.util.Locale;

/**
 * 生成pdf文件工具类
 * @author *******
 * @create 2025/7/09
 */
@Slf4j
public class PdfUtils {

    public static String PDF_BASE_PATH = "com/file/export/";
    public static String TEMPLATE_VERIFY_APPLY = "verifyApply.ftl"; // PDF模板名称

    private final static String TEMPLATE_BASE_PATH = "template/";
    private final static String FONT_BASE_PATH = "fonts/";
    private final static String DEFAULT_FONT = "simkai.ttf"; // 字体资源文件
    private final static String ENCODING = "UTF-8";


    /**
     * 生成pdf
     * @param templateName  模板名称
     * @param data  数据
     * @param filePath 生成pdf文件路径
     * @return 生成的文件数量
     */
    public static void createPDF(String templateName, Object data, String filePath) throws Exception {
        // 如果不存在,则创建目录
        File file = new File(filePath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }

        OutputStream out = null;
        boolean isSuccess = false;
        try {
            out = new FileOutputStream(file);
            // 资源文件存放的根路径
            String resourcePath = Paths.get(PdfUtils.class.getResource("/").toURI()).toString();

            Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
            cfg.setDirectoryForTemplateLoading(Paths.get(resourcePath , TEMPLATE_BASE_PATH).toFile());
            ITextRenderer renderer = new ITextRenderer();
            // 设置 css中 的字体样式
            renderer.getFontResolver().addFont(Paths.get(resourcePath, FONT_BASE_PATH , DEFAULT_FONT).toString(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            cfg.setEncoding(Locale.CHINA, ENCODING);
            // 获取模板文件
            Template template = cfg.getTemplate(templateName, ENCODING);
            StringWriter writer = new StringWriter();
            template.process(data, writer);
            writer.flush();

            String html = writer.toString();
            renderer.setDocumentFromString(html);
            renderer.layout();
            renderer.createPDF(out, false);
            renderer.finishPDF();
            out.flush();
            isSuccess = true;

        } catch (Exception e) {
            throw e;
        } finally {
            if (out != null) {
                try {
                    out.close();
                    if (!isSuccess) {
                        deleteFile(filePath);
                    }
                } catch (Exception e) {
                    throw new CustomException("文件导出PDF异常,资源未正确释放", e);
                }
            }
        }

    }

    private static void deleteFile(String path) {
        try {
            File file = new File(path);
            if (file.exists()) {
                boolean isDel = FileUtil.del(file);
                if (!isDel) {
                    log.error("删除本地磁盘文件失败,请检查路径是否被占用或权限问题:{}", path);
                }
            }
        } catch (Exception e) {
            log.error("删除本地磁盘文件异常", e);
        }
    }

}
  1. 资源文件的存放路径,与代码相匹配。(你放在其他位置也行,java代码的写法要相对应)

字体文件可以根据实际需求引入其他不同的字体。

模板文件根据实际进行修改

  1. 模板文件(部分代码)

这实际就是一个html文件

html 复制代码
<body>
<div class="mybody">
    <div class="header"></div>
    <div class="content_class">
        <table border="1" width="100%" cellspacing="0" cellpadding="0"
               style="table-layout: fixed; border-collapse: collapse; min-width:600px">
            <thead>

            </thead>
            <tbody>
            <tr>
                <td style="text-align: center; width:100%" colspan="6">费用报销单</td>
            </tr>
            <tr>
                <td style="text-align: center; width:70%; border-right: none" colspan="4"></td>
                <td style="text-align: center; width:8%; border-left: none; border-right: none" >编号</td>
                <td style="text-align: center; border-left: none; width: 22%">${applyNo!""}</td>
            </tr>
            <tr>
                <td style="text-align: center; width:8%">公司</td>
                <td style="width:20%" class="td_content_show">${companyName!""}</td>
                <td style="text-align: center; width:8%">部门</td>
                <td style="width:15%" class="td_content_show">${deptProject!""}</td>
                <td style="text-align: center; width:8%">申请日期</td>
                <td style="width:40%" class="td_content_show">${(createTime?string("yyyy-MM-dd HH:mm:ss"))!""}</td>
            </tr>
            <tr>
                <td style="text-align: center">金额</td>
                <td class="td_content_show" colspan="5">${amountUpper!""}&nbsp;元(&nbsp;¥${amount!""}&nbsp;) </td>
            </tr>
            <tr>
                <td style="text-align: center">申请人</td>
                <td class="td_content_show" colspan="5">${creator!""}</td>
            </tr>
            <tr style="height:10px">
                <td style="text-align: center" colspan="6"> </td>
            </tr>
            </tbody>
        </table>
    </div>
</div>
</body>

5.PDF生成效果

相关推荐
看浪的路人10 分钟前
第9讲:大模型应用监控与可观测性——OpenTelemetry + Prometheus + Grafana 全链路追踪
java·前端·spring
临床数据科学和人工智能兴趣组21 分钟前
在R语言的生态系统中,字符串处理一直是一个重要且复杂的任务
开发语言·正则表达式·r语言·r语言-4.2.1
大侠归来21 分钟前
事务能回滚吗?Pipeline 算事务吗?
java·数据库·oracle
蜗牛互联网22 分钟前
Python调用Gemini Structured Outputs实现工单路由门禁
java·开发语言·人工智能·python
SEO_juper38 分钟前
给网页做可引用性评分:判断内容够不够让 AI 引用(GEO 工具,附代码)
开发语言·人工智能·爬虫·python·seo·独立站
Wang's Blog42 分钟前
Java 项目实战: 交友项目 - 产品定位、功能模块与客户端原型解读
java·开发语言·交友
Wang's Blog1 小时前
Java 项目实战:交友项目 —— 项目导读与整体架构
java·架构·交友
今年下半年1 小时前
【短信发送】Spring Boot整合多种短信接口的实现(附源码)
java·spring boot·后端·sms·qcloudsms
盛世宏博北京1 小时前
十二防档案库房总线架构设计:恒湿消毒净化一体机 RS485 组网实战笔记
开发语言·笔记·php·恒湿机·档案八防温湿度
wespaul1 小时前
VeapAI 自然语言操作实战|第 04 篇:系统数据加工——把系统自身的元数据吃成知识
java·大数据·运维·数据库·人工智能