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);
            }
        },

效果

相关推荐
ljt272496066140 分钟前
Flutter笔记--envied
前端·笔记·flutter
Flynt1 小时前
React Router v8 升了之后,我花了两天才把项目跑起来
前端·typescript·preact
卷无止境2 小时前
Python能做嵌入式开发吗?一份写给动手派的生态与硬件全景图
后端·python
泯泷7 小时前
手搓JSVMM第 8 篇:函数调用:参数、返回值与调用帧
前端·javascript·前端框架
Sherotree8 小时前
Google Antigravity——Agent 被提到主界面
前端·ide·后端·edge浏览器
2601_962056238 小时前
Spring Boot 入门 与 无法解析符号 springframework 的解决
java·spring boot·后端
里欧跑得慢8 小时前
Flutter 像素级还原:设计稿到代码的视觉无损转换技巧
前端·css·flutter·web
里欧跑得慢9 小时前
Flutter 三方库 function_tree — 鸿蒙应用开发中的动态数学公式解析与计算神器,实现鸿蒙深度适配下的复杂函数逻辑运行时求值实战(适配鸿蒙 HarmonyOS Next ohos)
android·前端·安全·flutter·华为·harmonyos
你驴我9 小时前
WhatsApp 多账号场景下的会话归档与历史消息检索优化实践
后端·python
苏灿烤鱼9 小时前
没有机密文件,也没有付费数据,在浏览器里造一颗"间谍卫星"
前端·javascript·github