手摸手系列之 Java 通过 PDF 模板生成 PDF 功能

集团 SaaS 平台目前需要实现导出 PDF 格式的电子委托协议功能。业务方已经提供了一个现成的 PDF 文件作为参考。针对这一需求,我们有两个可行的方案:

  1. 完全代码生成:根据 PDF 文件的外观,完全通过代码动态生成 PDF 文件。
  2. 模板填充:将现有的 PDF 文件作为模板,仅需在代码中填充真实数据即可生成最终的 PDF 文件。

从实现效率和开发速度的角度来看,方案二(模板填充)无疑是更优的选择。它不仅能够大幅减少开发工作量,还能确保生成的 PDF 文件与业务方提供的模板完全一致,避免样式偏差。接下来,我们将重点探讨如何通过模板填充的方式实现这一功能。

一、PDF 模板制作

首先通过 PDF 编辑器制作 PDF 模板,这里我选用 Adobe Acrobat Pro 编辑表单来实现,这里我主要用到了表单的文本域和复选框。
工具我放云盘,需要的自取:https://caiyun.139.com/m/i?105CqcMLSgEyR 提取码:6ais
在这里插入图片描述
文本域的 name 对应 Java 中 model 类的属性。

二、前端编码

// html
<a-button v-has="'dec:down'" type="primary" icon="printer" :loading="printBatchLoading" @click="handlePrintBatch">批量打印</a-button>

// JavaScript
/**
 * 批量打印
 */
handlePrintBatch(){
  if (this.selectedRowKeys.length == 0) {
   this.$message.error('请选择至少一票数据!')
   return
  }
  let params = {}
  params.ids = this.selectedRowKeys.join(',')
  this.printBatchLoading = true
  let fileName = ''
  if (this.selectedRowKeys.length > 1) {
   fileName = '电子委托协议批量导出.zip'
  } else {
   fileName = '电子委托协议导出' + (this.selectionRows[0].consignNo ? this.selectionRows[0].consignNo :
    this.selectionRows[0].id) + '.pdf'
  }
  downloadFile(this.url.exportElecProtocolBatch, fileName,
   params).then((res) => {
   if (res.success) {
   } else {
    this.$message.warn(`导出失败!${res.message}`)
   }
  }).finally(() => {
   this.printBatchLoading = false
  })
}

/**
 * 下载文件
 * @param url 文件路径
 * @param fileName 文件名
 * @param parameter
 * @returns {*}
 */
export function downloadFile(url, fileName, parameter) {
  return downFile(url, parameter).then((data) => {
    if (!data || data.size === 0) {
      Vue.prototype['$message'].warning('文件下载失败')
      return
    }
    if (typeof window.navigator.msSaveBlob !== 'undefined') {
      window.navigator.msSaveBlob(new Blob([data]), fileName)
    } else {
      let url = window.URL.createObjectURL(new Blob([data]))
      let link = document.createElement('a')
      link.style.display = 'none'
      link.href = url
      link.setAttribute('download', fileName)
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link) //下载完成移除元素
      window.URL.revokeObjectURL(url) //释放掉blob对象
    }
  })
}

三、后端编码

/**
 * 批量打印电子委托协议
 *
 * @param ids
 * @return org.jeecg.common.api.vo.Result<?>
 * @author ZHANGCHAO
 * @date 2025/1/16 08:54
 */
@Override
public void exportElecProtocolBatch(String ids, HttpServletResponse response) {
   
   
    try {
   
   
        // 获取协议列表
        List<ElecProtocol> elecProtocolList = fetchProtocolsByIds(ids);
        if (isEmpty(elecProtocolList)) {
   
   
            throw new RuntimeException("未获取到电子委托协议数据");
        }

        if (elecProtocolList.size() == 1) {
   
   
            // 单个文件导出
            ElecProtocol protocol = elecProtocolList.get(0);
            Map<String, Object> data = prepareDataMap(protocol);
            byte[] pdfBytes = generatePdf(data);

            // 设置响应头
            String pdfFileName = URLEncoder.encode(
                    "电子委托协议_" + (isNotBlank(protocol.getConsignNo()) ? protocol.getConsignNo() : protocol.getId()) + ".pdf",
                    "UTF-8");
            response.setContentType("application/pdf");
            response.setHeader("Content-Disposition", "attachment; filename=" + pdfFileName);

            try (ServletOutputStream outputStream = response.getOutputStream()) {
   
   
                outputStream.write(pdfBytes);
                outputStream.flush();
            }
        } else {
   
   
            // 多个文件压缩成 ZIP 导出
            response.setContentType("application/zip");
            String zipFileName = URLEncoder.encode("电子委托协议导出.zip", "UTF-8");
            response.setHeader("Content-Disposition", "attachment; filename=" + zipFileName);

            try (<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值