IO系列-- JAVA PDF合并

前言

本章主要讲解JAVA中怎么进行PDF合并 并响应给前端 前端进行预览操作

IO实战代码 主要是记录一些常用 但是很容易忘记的IO流操作

欢迎查看👉🏻👉🏻👉🏻JAVA IO 专栏 查漏补缺 指教一二

虽然你现在用不到 但是未来你一定用得到 🥸

POM依赖

引入下方依赖 后续代码都是在这个版本进行开发 不同版本可能会有些依赖报错

pom 复制代码
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext7-core</artifactId>
    <version>7.1.16</version>
    <type>pom</type>
</dependency>

java代码

文档合并

java 复制代码
/**
 * 将pdf文档转换成字节数组
 *
 * @return 返回对应PDF文档的字节数组
 */
private static byte[] getPdfBytes(InputStream inputStream) throws Exception {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    byte[] data = new byte[2048];
    int len;
    while ((len = inputStream.read(data)) != -1) {
        out.write(data, 0, len);
    }
    return out.toByteArray();
}

/**
 * 基于内存中的字节数组进行PDF文档的合并
 *
 * @param firstPdf  第一个PDF文档
 * @param secondPdf 第二个PDF文档
 */
private static byte[] mergePdfBytes(byte[] firstPdf, byte[] secondPdf) {
    try {
        if (firstPdf != null && secondPdf != null) {
            // 创建字节数组,基于内存进行合并
            ByteArrayOutputStream bass = new ByteArrayOutputStream();
            PdfDocument destDoc = new PdfDocument(new PdfWriter(bass));
            // 合并的pdf文件对象
            PdfDocument firstDoc = new PdfDocument(new PdfReader(new ByteArrayInputStream(firstPdf)));
            PdfDocument secondDoc = new PdfDocument(new PdfReader(new ByteArrayInputStream(secondPdf)));
            // 合并对象
            PdfMerger merger = new PdfMerger(destDoc);
            merger.merge(firstDoc, 1, firstDoc.getNumberOfPages());
            merger.merge(secondDoc, 1, secondDoc.getNumberOfPages());
            // 关闭文档流
            merger.close();
            firstDoc.close();
            secondDoc.close();
            destDoc.close();
            return bass.toByteArray();
        }
    } catch (IOException e) {
        e.printStackTrace();
        log.error("合并PDF文件失败 {}", e.getMessage());
    }
    return null;
}

调用

参数 List<InputStream> inputStreamList 自行将pdf转换 是需要合并的pdf流

例如: // xxx.pdf 填入pdf 路径路径 InputStream fileInputStream = new FileInputStream(new File("xxx.pdf"));

java 复制代码
/**
 * @param response        响应
 * @param inputStreamList 文件流列表
 * @throws Exception 异常处理
 */
private void handleResponse(HttpServletResponse response,
                            List<InputStream> inputStreamList) throws Exception {
    if (CollUtil.isNotEmpty(inputStreamList)) {
        // 处理响应
        int size = inputStreamList.size();
        byte[] pdfData = getPdfBytes(inputStreamList.get(0));
        for (int i = 1; i < size; i++) {
            pdfData = mergePdfBytes(pdfData, getPdfBytes(inputStreamList.get(i)));
        }
        if (pdfData != null) {
            response.setContentType("application/pdf");
            response.setHeader("Content-Disposition", "attachment; filename=merged.pdf");

            try (OutputStream outputStream = response.getOutputStream()) {
                outputStream.write(pdfData);
                outputStream.flush();
            }
        }
    }
}

代码直接复制后段合并逻辑就处理完成了

前端接收

因为请求方式不同所有自行修改 只是给一个例子

请求一定要带上 responseType: "blob"

js 复制代码
export function expressService(waybillNoList) {
  return request({
    url: 'xxx' ,
    method: 'get',
    responseType: "blob"
  })
}

预览打印

js 复制代码
   async expressServiceData() {
            try {
                this.buttonLoading = true;
                const response = await expressService(this.expressServicelist);
                this.buttonLoading = false;

                const pdfBlob = new Blob([response.data], {
                    type: "application/pdf",
                });
                const blobUrl = URL.createObjectURL(pdfBlob);

                const printWindow = window.open(blobUrl, "_blank");

                // 等待新窗口加载完成后触发打印
                printWindow.onload = function () {
                    printWindow.print();
                };
            } catch (error) {
                this.buttonLoading = false;
                console.error("Error calling expressService:", error);
            }
        },

效果

相关推荐
橙子家1 小时前
Serilog 日志库简单实践(二):控制台与调试 Sinks(.net8)
后端
扯蛋4381 小时前
LangChain的学习之路( 一 )
前端·langchain·mcp
Mr.Jessy1 小时前
Web APIs学习第一天:获取 DOM 对象
开发语言·前端·javascript·学习·html
想不明白的过度思考者1 小时前
Rust——异步递归深度指南:从问题到解决方案
开发语言·后端·rust
ConardLi2 小时前
Easy Dataset 已经突破 11.5K Star,这次又带来多项功能更新!
前端·javascript·后端
芒克芒克2 小时前
ssm框架之Spring(上)
java·后端·spring
冴羽2 小时前
10 个被严重低估的 JS 特性,直接少写 500 行代码
前端·javascript·性能优化
rising start2 小时前
四、CSS选择器(续)和三大特性
前端·css
冒泡的肥皂2 小时前
MVCC初学demo(二
数据库·后端·mysql
追逐时光者2 小时前
一款基于 .NET WinForm 开源、轻量且功能强大的节点编辑器,采用纯 GDI+ 绘制无任何依赖库仅仅100+Kb
后端·.net