You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Spring JdbcTemplate从Azure SQL读取BLOB并修改内容后存储为PDF

基于Spring JdbcTemplate处理Azure SQL中PDF BLOB的可修改操作流程

核心逻辑

网上常见的示例之所以不适用,是因为实现了「数据库BLOB流 -> FileOutputStream」的直连通道,没有预留中间内容修改的环节。你只需要把这个直连链路拆解,在中间插入内存级的内容处理步骤即可,全程不需要依赖磁盘临时文件。

1. 读取数据库varbinary列的BLOB到内存可操作载体

不要直接将ResultSet获取的二进制流对接文件输出流,优先把BLOB内容加载为内存中可读写的结构:

// 通过JdbcTemplate读取目标PDF的BLOB字节
byte[] originalPdfByteArray = jdbcTemplate.queryForObject(
    "SELECT pdf_blob FROM pdf_record WHERE id = ?",
    (rs, rowNum) -> rs.getBytes("pdf_blob"),
    targetRecordId
);
// 转为输入流供后续PDF解析使用
ByteArrayInputStream pdfInputSource = new ByteArrayInputStream(originalPdfByteArray);

如果PDF体积较大(超过内存可承载阈值),可以将上述读取方式替换为rs.getBinaryStream()做分页流式读取,避免一次性加载全量字节导致OOM。

2. 在内存中完成PDF内容修改

借助专业PDF处理库(如OpenPDF、合规版本的iText)对内存流中的PDF做解析、修改,全程在内存缓冲区完成操作,不生成磁盘临时文件:

// 示例内存修改逻辑
PdfReader pdfReader = new PdfReader(pdfInputSource);
ByteArrayOutputStream modifiedPdfBuffer = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(pdfReader, modifiedPdfBuffer);

// 在此处替换为你的自定义修改逻辑:如替换指定位置文本、添加电子签章、补充页眉页脚等
int pageCount = pdfReader.getNumberOfPages();
for (int pageIndex = 1; pageIndex <= pageCount; pageIndex++) {
    PdfContentByte pageContent = stamper.getOverContent(pageIndex);
    pageContent.beginText();
    pageContent.setFontAndSize(BaseFont.createFont(), 10);
    pageContent.showTextAligned(
        Element.ALIGN_RIGHT, 
        "内容已校验", 
        pdfReader.getPageSize(pageIndex).getWidth() - 36, 
        36, 
        0
    );
    pageContent.endText();
}
stamper.close();
pdfReader.close();

// 拿到修改完成的最终PDF字节数组
byte[] finalPdfContent = modifiedPdfBuffer.toByteArray();

3. 处理完成后的输出/回写

修改逻辑执行完成后,可根据需求选择两种处理方向:

  • 回写Azure SQL数据库:直接将修改后的字节数组通过JdbcTemplate更新到对应varbinary列,无需经过文件落地
    jdbcTemplate.update(
        "UPDATE pdf_record SET pdf_blob = ?, update_time = GETDATE() WHERE id = ?",
        finalPdfContent,
        targetRecordId
    );
    
  • 导出为本地PDF文件:此时再对接FileOutputStream完成文件写入即可,和常规示例的落盘逻辑一致
    try (FileOutputStream fileOut = new FileOutputStream("modified_result.pdf")) {
        fileOut.write(finalPdfContent);
    }
    

关键注意点

  • 不要手动直接修改PDF的原始字节数据,PDF有固定的二进制结构,手动篡改极易造成文件损坏无法打开
  • 全流程尽量用内存流处理,避免生成不必要的磁盘临时文件,减少IO开销和临时文件泄露的风险
  • 大体积PDF处理时要注意内存占用阈值,结合流式解析能力调整代码实现,避免内存溢出

内容的提问来源于stack exchange,提问作者Manoj kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.23 11:36:10