跳转到内容

Java 生成「交付收货回执」PDF 示例(Template)

JQuick-Pdf场景 Demo

Template1 页 A4 · 34 KB

表格跨页的交付收货回执,底部带签收栏。

下载 PDF 文件查看模板原始文件返回全部示例

交付收货回执 — Template
渲染效果

输出规格

PDF 页数
1
图表类型
Template
模板行数
125
源码行数
101

Java 源码 · JQuickBiz79DeliveryReceipt.java

以下代码即生成上方 PDF 的完整测试类,可直接复制运行;Maven 依赖见快速开始章节。

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright (c) [2025-2099] Martin ([email protected])
 */
package com.github.paohaijiao.biz.scenario;

import com.github.paohaijiao.config.JPdfConfig;
import com.github.paohaijiao.executor.JQuickPdfFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class JQuickBiz79DeliveryReceipt {

    private static final String PDF_DIR = "D:/test/pdf/";
    private static final String IMG_DIR = "D:/test/image/";
    private static final String OUT_FILE = PDF_DIR + "79_delivery_receipt.pdf";
    private static final String TEMPLATE = "report/biz/79_delivery_receipt.txt";

    public static void main(String[] args) throws Exception {
        new File(PDF_DIR).mkdirs();
        new File(IMG_DIR).mkdirs();

        // ---------- 1. 生成签名图片(模板 image src 按字面量引用固定路径) ----------
        generateSignature(IMG_DIR + "79_sign.png", "赵一鸣");

        // ---------- 2. 组织数据(普通 Map,无实体类)----------
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("receiptNo", "HZ-2026-1019-0043");
        data.put("receiverUnit", "××城市商业银行 信息科技部");
        data.put("contact", "赵一鸣 021-6123-4567");
        data.put("address", "××市浦东新区××路 88 号 JQ 大厦 12 层");
        data.put("deliveryDate", "2026年10月19日");

        List<String[]> items = new ArrayList<String[]>();
        items.add(new String[]{"PDF 报表引擎安装介质(U 盘)", "V4.2.0", "个", "1", "含许可文件"});
        items.add(new String[]{"企业版许可证书", "5 节点", "份", "1", "已激活"});
        items.add(new String[]{"部署手册", "V4.2", "册", "2", ""});
        items.add(new String[]{"运维手册", "V4.2", "册", "2", ""});
        items.add(new String[]{"接口开发文档", "V4.2", "册", "2", "含示例代码"});
        items.add(new String[]{"报表模板包(58 套)", "STD-2026", "套", "1", "压缩包"});
        data.put("itemCount", items.size() + " 项");
        String[] keys = {"name", "spec", "unit", "qty", "remark"};
        for (int i = 0; i < items.size(); i++) {
            for (int j = 0; j < keys.length; j++) {
                data.put("it" + (i + 1) + "_" + keys[j], items.get(i)[j]);
            }
        }

        // ---------- 3. 渲染 ----------
        JPdfConfig config = new JPdfConfig();
        config.getLayoutConfig().setFlexLayout(true);
        config.getDoc().setMargins(Arrays.asList(48, 48, 55, 48));
        config.getFooterConfig().setEnabled(true);
        config.getFooterConfig().setFontSize(8);
        config.getFooterConfig().setPageNumberFormat("第 %d 页");

        JQuickPdfFactory factory = new JQuickPdfFactory(config);
        factory.bindAll(data);
        byte[] pdf = factory.executeResource(TEMPLATE);

        FileOutputStream out = new FileOutputStream(OUT_FILE);
        out.write(pdf);
        out.close();
        System.out.println("已生成:" + OUT_FILE);
    }

    /** 生成手写签名图片(楷体 + 轻微旋转),与 93 样板同一套绘图逻辑。 */
    private static void generateSignature(String path, String name) throws IOException {
        BufferedImage image = new BufferedImage(180, 88, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = image.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.rotate(Math.toRadians(-3), 90, 44);
        g.setColor(new Color(0x1B, 0x2A, 0x3A));
        g.setFont(new Font("KaiTi", Font.PLAIN, 40));
        g.drawString(name, 26, 60);
        g.dispose();
        ImageIO.write(image, "png", new File(path));
    }
}

最小调用(3 行)

不想读完整测试类?核心就是这三行:绑定图表 SVG,执行模板,拿到 PDF 字节流。可直接复制到你的项目里。

// config 可省略;svg 来自 JChartRendererFactory.renderChart(...),见下方完整源码
byte[] pdf = new JQuickPdfFactory(config).executeResource("report/biz/79_delivery_receipt.txt");

模板文件 · 79_delivery_receipt.txt

类 HTML + 内联 CSS 的模板语法,绑定数据后渲染为 PDF。下方为完整模板,可直接复制,也可下载原始文件。

<pdf>
<body>

  // ---------- 页头 ----------
  <div style="display:flex; justifyContent:space-between; borderBottom:2px solid #1F4E79; paddingBottom:6px; marginBottom:8px">
    <div style="width:320px">
      <h1 style="fontSize:18pt; bold:true; color:#1F4E79; characterSpacing:3pt">'交付收货回执'</h1>
    </div>
    <div style="width:180px; textAlignment:right">
      <p style="fontSize:8.5pt; color:#5A6B7C">'回执单号'</p>
      <p style="fontSize:10pt; bold:true; color:#1A2733">${receiptNo}</p>
    </div>
  </div>

  // ---------- 收货信息 ----------
  <table style="width:100%; fontSize:9pt">
    <tr>
      <td style="width:78px; padding:5px; backgroundColor:#E8EDF2; bold:true; border:1px solid #C3CDD8">'收货单位'</td>
      <td style="width:170px; padding:5px; border:1px solid #C3CDD8">${receiverUnit}</td>
      <td style="width:78px; padding:5px; backgroundColor:#E8EDF2; bold:true; border:1px solid #C3CDD8">'联系人'</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${contact}</td>
    </tr>
    <tr>
      <td style="width:78px; padding:5px; backgroundColor:#E8EDF2; bold:true; border:1px solid #C3CDD8">'收货地址'</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${address}</td>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8; color:#C3CDD8">'—'</td>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8; color:#C3CDD8">'—'</td>
    </tr>
    <tr>
      <td style="width:78px; padding:5px; backgroundColor:#E8EDF2; bold:true; border:1px solid #C3CDD8">'交付日期'</td>
      <td style="width:170px; padding:5px; border:1px solid #C3CDD8">${deliveryDate}</td>
      <td style="width:78px; padding:5px; backgroundColor:#E8EDF2; bold:true; border:1px solid #C3CDD8">'明细项数'</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${itemCount}</td>
    </tr>
  </table>

  // ---------- 交付明细 ----------
  <table style="width:100%; fontSize:8.5pt; marginTop:6px">
    <tr>
      <th style="width:34px; padding:5px; backgroundColor:#1F4E79; color:white; textAlign:center; border:1px solid #1F4E79">'序号'</th>
      <th style="width:190px; padding:5px; backgroundColor:#1F4E79; color:white; textAlign:center; border:1px solid #1F4E79">'交付物名称'</th>
      <th style="width:110px; padding:5px; backgroundColor:#1F4E79; color:white; textAlign:center; border:1px solid #1F4E79">'规格型号'</th>
      <th style="width:40px; padding:5px; backgroundColor:#1F4E79; color:white; textAlign:center; border:1px solid #1F4E79">'单位'</th>
      <th style="width:45px; padding:5px; backgroundColor:#1F4E79; color:white; textAlign:center; border:1px solid #1F4E79">'数量'</th>
      <th style="padding:5px; backgroundColor:#1F4E79; color:white; textAlign:center; border:1px solid #1F4E79">'备注'</th>
    </tr>
    <tr>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8">'1'</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it1_name}</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it1_spec}</td>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8">${it1_unit}</td>
      <td style="padding:5px; textAlign:right; border:1px solid #C3CDD8">${it1_qty}</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it1_remark}</td>
    </tr>
    <tr>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8">'2'</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it2_name}</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it2_spec}</td>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8">${it2_unit}</td>
      <td style="padding:5px; textAlign:right; border:1px solid #C3CDD8">${it2_qty}</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it2_remark}</td>
    </tr>
    <tr>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8">'3'</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it3_name}</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it3_spec}</td>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8">${it3_unit}</td>
      <td style="padding:5px; textAlign:right; border:1px solid #C3CDD8">${it3_qty}</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it3_remark}</td>
    </tr>
    <tr>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8">'4'</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it4_name}</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it4_spec}</td>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8">${it4_unit}</td>
      <td style="padding:5px; textAlign:right; border:1px solid #C3CDD8">${it4_qty}</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it4_remark}</td>
    </tr>
    <tr>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8">'5'</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it5_name}</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it5_spec}</td>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8">${it5_unit}</td>
      <td style="padding:5px; textAlign:right; border:1px solid #C3CDD8">${it5_qty}</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it5_remark}</td>
    </tr>
    <tr>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8">'6'</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it6_name}</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it6_spec}</td>
      <td style="padding:5px; textAlign:center; border:1px solid #C3CDD8">${it6_unit}</td>
      <td style="padding:5px; textAlign:right; border:1px solid #C3CDD8">${it6_qty}</td>
      <td style="padding:5px; border:1px solid #C3CDD8">${it6_remark}</td>
    </tr>
  </table>

  // ---------- 交付说明 ----------
  <div style="borderLeft:4px solid #2F5597; background:#F7F9FC; padding:7px 9px; marginTop:8px">
    <p style="fontSize:8.5pt; color:#333333">'1. 请收货人当面清点数量、检查外观与包装,确认无误后在下方签收栏签字。'</p>
    <p style="fontSize:8.5pt; color:#333333">'2. 如发现短缺、破损或型号不符,请在备注栏注明,并于 24 小时内书面通知交付方。'</p>
    <p style="fontSize:8.5pt; color:#333333">'3. 本回执一式两联,交付方与收货单位各执一联,签字盖章后生效。'</p>
  </div>

  // ---------- 签收栏(签名图片由 Java 生成到固定路径) ----------
  <div style="display:flex; justifyContent:space-between; marginTop:16px">
    <div style="width:155px; border:1px solid #C3CDD8; padding:7px">
      <p style="fontSize:9pt; bold:true; color:#1F4E79">'交付人'</p>
      <p style="fontSize:9pt; color:#5A6B7C; marginTop:16px">'签字:'</p>
      <p style="fontSize:9pt; color:#5A6B7C; marginTop:8px">'日期:'</p>
    </div>
    <div style="width:155px; border:1px solid #C3CDD8; padding:7px">
      <p style="fontSize:9pt; bold:true; color:#1F4E79">'收货人'</p>
      <image src='D:/test/image/79_sign.png' style="width:90px; height:44px"></image>
      <p style="fontSize:9pt; color:#5A6B7C; marginTop:4px">'日期:'</p>
    </div>
    <div style="width:155px; border:1px solid #C3CDD8; padding:7px">
      <p style="fontSize:9pt; bold:true; color:#1F4E79">'收货单位(盖章)'</p>
      <p style="fontSize:9pt; color:#5A6B7C; marginTop:16px">'       '</p>
      <p style="fontSize:9pt; color:#5A6B7C; marginTop:8px">'日期:'</p>
    </div>
  </div>

</body>
</pdf>

同分组示例

本页 PDF、预览图、模板与源码均由 JQuick-Pdf 真实运行产出,可自由复制到你的项目中使用。