java 富文本转pdf

前言:

本文的目的是将传入的富文本内容(html标签,图片)并且分页导出为pdf。

所用的核心依赖为iText7。

因为itextpdf-core的核心包在maven中央仓库中,阿里云华为云等拉不下来,中央仓库在外网,并且此包在中央仓库中未提供可下载的jar包文件,所以通过iText github上提供的core包的组成jar,实现core包所需方法的调用。

一、jar包导入

在子项目的resources下新建lib目录,下载文件所提供的压缩包,解压jar包文件到lib下,如图所示

二、maven依赖导入

bash 复制代码
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>barcodes</artifactId>
            <version>7.2.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/barcodes-7.2.3.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>commons</artifactId>
            <version>7.2.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/commons-7.2.3.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>font-asian</artifactId>
            <version>7.2.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/font-asian-7.2.3.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>forms</artifactId>
            <version>7.2.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/forms-7.2.3.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>hyph</artifactId>
            <version>7.2.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/hyph-7.2.3.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>io</artifactId>
            <version>7.2.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/io-7.2.3.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>kernel</artifactId>
            <version>7.2.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/kernel-7.2.3.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>layout</artifactId>
            <version>7.2.3</version> <!-- 如果需要布局功能 -->
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/layout-7.2.3.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>pdfa</artifactId>
            <version>7.2.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/pdfa-7.2.3.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>pdftest</artifactId>
            <version>7.2.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/pdftest-7.2.3.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>sign</artifactId>
            <version>7.2.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/sign-7.2.3.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>styled-xml-parser</artifactId>
            <version>7.2.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/styled-xml-parser-7.2.3.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>svg</artifactId>
            <version>7.2.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/svg-7.2.3.jar</systemPath>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.itextpdf/html2pdf -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>html2pdf</artifactId>
            <version>4.0.3</version>
        </dependency>

三、打包配置

因为从外部引入jar包,在本地测试没有问题,但是打包后发布,引用不了,所以需要配置打包引用外部jar包。所以可以根据以下链接,博主的另外一个文章提供了相关的方法。

java引用第三方jar包,打包全流程_java引入外部jar包-CSDN博客

四、工具类

bash 复制代码
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider;
import com.itextpdf.io.exceptions.IOException;
import com.itextpdf.layout.font.FontProvider;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

@Component
public class RichTextExporter {

    /**
     * HTML内容转PDF并输出到响应流
     * @param htmlContent HTML内容
     * @param response HttpServletResponse
     * @param request HttpServletRequest(用于获取基础路径)
     * @param fileName 生成的PDF文件名
     * @throws IOException 转换过程异常
     */
    public static void convertToPdf(
            String htmlContent,
            HttpServletResponse response,
            HttpServletRequest request,
            String fileName
    ) throws IOException, java.io.IOException {
        // 配置响应头
        configureResponseHeaders(response, fileName, request);

        try (OutputStream outputStream = response.getOutputStream()) {
            // 创建转换器配置
            ConverterProperties converterProperties = createConverterProperties(request);

            // 执行转换
            HtmlConverter.convertToPdf(htmlContent, outputStream, converterProperties);
        }
    }

    /**
     * 配置HTTP响应头
     */
    private static void configureResponseHeaders(
            HttpServletResponse response,
            String fileName,
            HttpServletRequest request) {
        response.setContentType("application/pdf");
        String attachment = String.format(
                "attachment; filename=\"%s\"",
                encodeFileName(fileName, request)
        );
        response.setHeader("Content-Disposition", attachment);
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
    }

    /**
     * 创建转换器配置(处理路径、字体、字符集等)
     */
    private static ConverterProperties createConverterProperties(
            HttpServletRequest request
    ) {
        ConverterProperties properties = new ConverterProperties();

        // 设置基础URI(解析相对路径,如图片/字体地址)
        properties.setBaseUri(getBaseHttpPath(request));

        // 配置字体(支持中文、非嵌入字体、符号)
        FontProvider fontProvider = new DefaultFontProvider(true, true, true);
        properties.setFontProvider(fontProvider);

        // 设置字符集
        properties.setCharset(StandardCharsets.UTF_8.name());

        return properties;
    }

    /**
     * 获取完整的基础HTTP路径(包含协议、域名、端口、上下文路径)
     */
    private static String getBaseHttpPath(HttpServletRequest request) {
        int port = request.getServerPort();
        String portStr = (port == 80 || port == 443) ? "" : ":" + port;
        return String.format(
                "%s://%s%s%s",
                request.getScheme(),
                request.getServerName(),
                portStr,
                request.getContextPath()
        );
    }

    /**
     * 处理文件名编码(兼容不同浏览器)
     */
    private static String encodeFileName(String fileName, HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
        try {
            if (userAgent.contains("MSIE") || userAgent.contains("Edge") || userAgent.contains("Chrome")) {
                return java.net.URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            } else {
                return new String(fileName.getBytes(StandardCharsets.UTF_8), "ISO-8859-1");
            }
        } catch (Exception e) {
            return fileName;
        }
    }

}

五、controller

bash 复制代码
    @PostMapping("/export")
    @Operation(summary = "导出pdf")
    @Parameter(name = "htmlContent", description = "富文本内容", required = true)
    public void exportPdf(@RequestParam("htmlContent") String htmlContent, HttpServletRequest request, HttpServletResponse response) throws IOException {
        RichTextExporter.convertToPdf(htmlContent, response, request, "pdf导出测试");
    }

六、yaml配置

因为富文本内容很大,所以如果必须用post请求,并且需要修改上传配置,在yaml文件中加入如下配置即可:

bash 复制代码
###设置缓冲区大小,方便上传大文件
server:
  tomcat:
    max-swallow-size: 15MB
    max-http-form-post-size: 16777216

七、测试

八、注意

经测试,富文本内容最好把ol标签给过滤掉,因为会导致富文本导出为pdf出错,并且如果还需要支持其余特殊的标签,请自行扩展工具类。

相关推荐
柯南二号4 分钟前
【Java后端】Spring Boot 集成 MyBatis-Plus 全攻略
java·spring boot·mybatis
桦说编程7 小时前
Java 中如何创建不可变类型
java·后端·函数式编程
lifallen7 小时前
Java Stream sort算子实现:SortedOps
java·开发语言
IT毕设实战小研7 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
没有bug.的程序员8 小时前
JVM 总览与运行原理:深入Java虚拟机的核心引擎
java·jvm·python·虚拟机
甄超锋8 小时前
Java ArrayList的介绍及用法
java·windows·spring boot·python·spring·spring cloud·tomcat
阿华的代码王国9 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
Zyy~9 小时前
《设计模式》装饰模式
java·设计模式
A尘埃9 小时前
企业级Java项目和大模型结合场景(智能客服系统:电商、金融、政务、企业)
java·金融·政务·智能客服系统
青云交9 小时前
Java 大视界 -- 基于 Java 的大数据可视化在城市交通拥堵治理与出行效率提升中的应用(398)
java·大数据·flink·大数据可视化·拥堵预测·城市交通治理·实时热力图