最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實現(xiàn)PDF批量處理之合并、拆分、加水印的技術(shù)方案與實踐

 更新時間:2026年02月11日 09:36:07   作者:用戶3891775626958  
在日常開發(fā)中,PDF文檔處理是一個高頻需求,無論是合同管理系統(tǒng)需要合并多份PDF,還是報表系統(tǒng)需要按頁拆分,亦或是給機密文檔添加水印,都需要一套可靠的PDF處理方案,本文將分享基于Java技術(shù)棧實現(xiàn)PDF批量處理的核心思路與代碼實踐,需要的朋友可以參考下

一、技術(shù)選型

Java生態(tài)中處理PDF的庫主要有以下幾個:

| 庫名 | 特點 | 適用場景 |

|------|------|----------|

| Apache PDFBox | 開源免費,功能全面 | 合并、拆分、水印、文本提取 |

| iText | 功能強大,商用需授權(quán) | 復(fù)雜PDF生成、表單處理 |

| OpenPDF | iText的開源分支 | 輕量級PDF生成 |

綜合考慮開源協(xié)議和功能覆蓋度,Apache PDFBox 是大多數(shù)項目的首選。

二、Maven依賴配置

<dependency>

<groupId>org.apache.pdfbox</groupId>

<artifactId>pdfbox</artifactId>

<version>2.0.27</version>

</dependency>

三、PDF合并實現(xiàn)

3.1 核心思路

PDF合并的本質(zhì)是將多個PDF文檔的頁面按順序追加到一個新文檔中。PDFBox提供了PDFMergerUtility工具類來簡化這個過程。

3.2 代碼實現(xiàn)

import org.apache.pdfbox.multipdf.PDFMergerUtility;

import java.io.*;

import java.util.List;

  


public class PdfMergeService {

  


/**

* 合并多個PDF文件

* @param inputStreams PDF文件輸入流列表

* @param outputPath 輸出文件路徑

*/

public void mergePdf(List<InputStream> inputStreams, String outputPath)

throws IOException {

PDFMergerUtility merger = new PDFMergerUtility();

merger.setDestinationFileName(outputPath);

  


for (InputStream is : inputStreams) {

merger.addSource(is);

}

  


// 執(zhí)行合并,MemoryUsageSetting可控制內(nèi)存使用

merger.mergeDocuments(

org.apache.pdfbox.io.MemoryUsageSetting.setupMainMemoryOnly()

);

}

}

3.3 注意事項

  • 內(nèi)存管理:處理大文件時建議使用setupTempFileOnly()將臨時數(shù)據(jù)寫入磁盤,避免OOM
  • 文件順序:合并順序取決于addSource的調(diào)用順序,前端可通過拖拽排序來控制
  • 書簽處理:合并后原有書簽可能丟失,如需保留需額外處理PDDocumentOutline

四、PDF拆分實現(xiàn)

4.1 按頁碼范圍拆分

import org.apache.pdfbox.multipdf.Splitter;

import org.apache.pdfbox.pdmodel.PDDocument;

  


public class PdfSplitService {

  


/**

* 按頁碼范圍拆分PDF

* @param inputStream 源PDF輸入流

* @param startPage 起始頁(從1開始)

* @param endPage 結(jié)束頁

*/

public byte[] splitByPageRange(InputStream inputStream,

int startPage, int endPage) throws IOException {

  


try (PDDocument document = PDDocument.load(inputStream);

PDDocument newDoc = new PDDocument()) {

  


int totalPages = document.getNumberOfPages();

// 參數(shù)校驗

startPage = Math.max(1, startPage);

endPage = Math.min(totalPages, endPage);

  


for (int i = startPage - 1; i < endPage; i++) {

newDoc.addPage(document.getPage(i));

}

  


ByteArrayOutputStream baos = new ByteArrayOutputStream();

newDoc.save(baos);

return baos.toByteArray();

}

}

}

4.2 性能優(yōu)化建議

對于頁數(shù)很多的PDF(如上千頁),逐頁操作可能較慢??梢钥紤]:

  • 使用Splitter類的setSplitAtPage()方法按固定頁數(shù)批量拆分
  • 對于僅需提取少量頁面的場景,直接操作頁面樹比使用Splitter更高效

五、PDF加水印實現(xiàn)

5.1 文字水印核心代碼

import org.apache.pdfbox.pdmodel.*;

import org.apache.pdfbox.pdmodel.font.PDType1Font;

import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;

import org.apache.pdfbox.util.Matrix;

  


public class PdfWatermarkService {

  


public byte[] addTextWatermark(InputStream input, String text,

float opacity, float rotation, float fontSize) throws IOException {

  


try (PDDocument document = PDDocument.load(input)) {

// 遍歷每一頁添加水印

for (PDPage page : document.getPages()) {

PDPageContentStream cs = new PDPageContentStream(

document, page,

PDPageContentStream.AppendMode.APPEND, true, true

);

  


// 設(shè)置透明度

PDExtendedGraphicsState gs = new PDExtendedGraphicsState();

gs.setNonStrokingAlphaConstant(opacity);

cs.setGraphicsStateParameters(gs);

  


// 設(shè)置字體和顏色

cs.setFont(PDType1Font.HELVETICA_BOLD, fontSize);

cs.setNonStrokingColor(200, 200, 200); // 淺灰色

  


// 計算頁面中心位置

float pageWidth = page.getMediaBox().getWidth();

float pageHeight = page.getMediaBox().getHeight();

float cx = pageWidth / 2;

float cy = pageHeight / 2;

  


// 旋轉(zhuǎn)變換

cs.beginText();

Matrix matrix = Matrix.getRotateInstance(

Math.toRadians(rotation), cx, cy

);

cs.setTextMatrix(matrix);

cs.showText(text);

cs.endText();

cs.close();

}

  


ByteArrayOutputStream baos = new ByteArrayOutputStream();

document.save(baos);

return baos.toByteArray();

}

}

}

5.2 中文水印的坑

PDFBox默認的PDType1Font不支持中文字符,直接使用會導(dǎo)致亂碼或報錯。解決方案:

// 加載系統(tǒng)中文字體

PDType0Font chineseFont = PDType0Font.load(document,

new FileInputStream("/usr/share/fonts/wqy-microhei/wqy-microhei.ttc"), 0);

cs.setFont(chineseFont, fontSize);

服務(wù)器部署時需確保安裝了中文字體

# CentOS/RHEL

sudo yum install -y wqy-microhei-fonts

# Ubuntu/Debian

sudo apt-get install -y fonts-wqy-microhei

六、封裝為REST API

在Spring Boot項目中,可以將上述功能封裝為統(tǒng)一的REST接口:

@RestController

@RequestMapping("/api/document/pdf")

public class PdfController {

  


@PostMapping("/merge")

public ResponseEntity<?> merge(

@RequestParam("files") MultipartFile[] files) {

// 調(diào)用合并服務(wù)

}

  


@PostMapping("/split")

public ResponseEntity<?> split(

@RequestParam("file") MultipartFile file,

@RequestParam("startPage") int startPage,

@RequestParam("endPage") int endPage) {

// 調(diào)用拆分服務(wù)

}

  


@PostMapping("/watermark")

public ResponseEntity<?> watermark(

@RequestParam("file") MultipartFile file,

@RequestParam("text") String text,

@RequestParam(defaultValue = "0.5") float opacity) {

// 調(diào)用水印服務(wù)

}

}

七、實際效果

如果你不想自己搭建服務(wù),也可以直接使用現(xiàn)成的在線工具來處理PDF。比如 輕語API開放平臺 提供了免費的 PDF在線處理工具,支持合并、拆分、加水印、轉(zhuǎn)Word、轉(zhuǎn)圖片等功能,底層就是基于上述技術(shù)方案實現(xiàn)的。

對于需要批量處理的場景,也可以通過API接口集成到自己的系統(tǒng)中,省去重復(fù)造輪子的成本。

八、總結(jié)

| 功能 | 核心類/方法 | 難點 |

|------|------------|------|

| PDF合并 | PDFMergerUtility | 大文件內(nèi)存管理 |

| PDF拆分 | PDDocument.getPage() | 頁碼邊界校驗 |

| PDF水印 | PDPageContentStream | 中文字體支持 |

PDF處理看似簡單,但在生產(chǎn)環(huán)境中需要關(guān)注內(nèi)存控制、字體兼容、并發(fā)處理等問題。希望本文的實踐經(jīng)驗?zāi)軒椭闵俨纫恍┛印?/p>

以上就是Java實現(xiàn)PDF批量處理之合并、拆分、加水印的技術(shù)方案與實踐的詳細內(nèi)容,更多關(guān)于Java批量處理PDF文檔的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Graceful Response 構(gòu)建 Spring Boot 響應(yīng)處理的方法

    Graceful Response 構(gòu)建 Spring Boot 響應(yīng)

    Graceful Response是一個Spring Boot技術(shù)棧下的優(yōu)雅響應(yīng)處理器,提供一站式統(tǒng)一返回值封裝、全局異常處理、自定義異常錯誤碼等功能,本文介紹Graceful Response 構(gòu)建 Spring Boot 下優(yōu)雅的響應(yīng)處理,感興趣的朋友一起看看吧
    2024-01-01
  • 詳解Java泛型中類型擦除問題的解決方法

    詳解Java泛型中類型擦除問題的解決方法

    Java泛型的實現(xiàn)是不完整的,有時會遇到一些Java泛型類型擦除的問題。本文將詳細為大家講解Java泛型中類型擦除問題的解決方法,需要的可以參考一下
    2022-05-05
  • IDEA 中創(chuàng)建SpringBoot 父子模塊的實現(xiàn)

    IDEA 中創(chuàng)建SpringBoot 父子模塊的實現(xiàn)

    這篇文章主要介紹了IDEA 中創(chuàng)建SpringBoot 父子模塊的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Java后臺開發(fā)之表單提交之前驗證

    Java后臺開發(fā)之表單提交之前驗證

    這篇文章主要介紹了Java后臺開發(fā)之表單提交之前驗證的實現(xiàn)代碼,非常不錯具有參考借鑒價值,需要的朋友參考下吧
    2017-02-02
  • Java日期格式化實現(xiàn)過程

    Java日期格式化實現(xiàn)過程

    本文介紹了在Java中處理日期格式y(tǒng)yyyMMddHHmmss的方法,包括使用java.time包(Java8+)和SimpleDateFormat(Java7及以下),詳細說明了格式化和解析時間的示例代碼,并強調(diào)了線程安全和異常處理的重要性,還討論了常見錯誤及其解決方法,以及如何生成唯一標(biāo)識符
    2025-11-11
  • Idea中g(shù)it的使用小結(jié)

    Idea中g(shù)it的使用小結(jié)

    這篇文章主要介紹了Idea中g(shù)it的使用小結(jié),本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-01-01
  • Java基礎(chǔ)知識之Java語言概述

    Java基礎(chǔ)知識之Java語言概述

    這篇文章主要介紹了Java基礎(chǔ)知識之Java語言概述,本文介紹了Java語言相關(guān)的基礎(chǔ)知識、歷史介紹、主要應(yīng)用方向等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • 詳解spring mvc4使用及json 日期轉(zhuǎn)換解決方案

    詳解spring mvc4使用及json 日期轉(zhuǎn)換解決方案

    本篇文章主要介紹了spring mvc4使用及json 日期轉(zhuǎn)換解決方案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • Java8中Map常用的遍歷方式

    Java8中Map常用的遍歷方式

    這篇文章主要給大家介紹了關(guān)于Java8中Map常用的遍歷方式,map屬于java中的頂級接口之一,區(qū)別于list,map是鍵值對的形式存在,需要的朋友可以參考下
    2023-07-07
  • Java編碼摘要算法實例解析

    Java編碼摘要算法實例解析

    這篇文章主要介紹了Java編碼摘要算法實例解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01

最新評論

淅川县| 康马县| 博湖县| 康乐县| 岳阳县| 凤凰县| 红河县| 静海县| 赞皇县| 平谷区| 汽车| 张北县| 忻州市| 乌拉特前旗| 铁岭县| 涿州市| 千阳县| 乌苏市| 凉城县| 南安市| 黄浦区| 建昌县| 雷波县| 金寨县| 绥棱县| 太仆寺旗| 临江市| 黔西县| 黑水县| 清水河县| 赤水市| 五河县| 南京市| 彩票| 柘城县| 读书| 遂平县| 耿马| 洛宁县| 青海省| 拜泉县|