Skip to content

Safety responsibility pledge — generate this PDF with Java (Template)

JQuick-PdfScenario Demos

Template2 页 A4 · 117 KB

Multi-page work-safety responsibility pledge with clauses, a seal strip and dual signatures.

Download the PDFView raw template fileBack to all demos

Safety responsibility pledge — Template
Rendered output

Output specs

PDF pages
2
Chart type
Template
Template lines
143
Source lines
227

Java source · JQuickBiz93SafetyResponsibility.java

This is the complete test class that produced the PDF above — copy it and run as-is; see the quick-start section for the Maven dependency.

/*
 * 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 JQuickBiz93SafetyResponsibility {

    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 + "93_safety_responsibility.pdf";
    private static final String TEMPLATE = "report/biz/93_safety_responsibility.txt";

    public static void main(String[] args) throws IOException {
        mkdirs();

        // ---------- 1. 生成图片(印章 / 签名 / 骑缝章条),输出到 D:/test/image/ ----------
        // 模板中 image src 按字面量引用这些固定路径(当前引擎 image src 不解析 ${var})
        String seal = IMG_DIR + "93_seal.png";
        String sign = IMG_DIR + "93_sign.png";
        generateSeal(seal, "××建工集团");
        generateSignature(sign, "郑守义");
        splitSealForRidge(seal, 4, IMG_DIR + "93_ridge_");

        // ---------- 2. 组织数据(普通 Map,无实体类)----------
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("docNo", "AQ-2026-0138");
        data.put("unit", "××建工集团有限公司 第三工程分公司");
        data.put("responsiblePerson", "郑守义");
        data.put("personId", "3201**********2317");
        data.put("personPost", "项目经理");
        // 模板单元格只放单个变量,组合文案在 Java 侧拼好
        data.put("personLine", "郑守义 (岗位:项目经理)");
        data.put("idLine", "3201**********2317 (签署日期:2026年1月8日)");
        data.put("period", "2026年1月1日 至 2026年12月31日");
        data.put("signDate", "2026年1月8日");
        // 条款:逐条 bind 为 clauseTitle1~8 / clauseText1~8(模板逐条引用)
        String[] clauseArr = buildClauses();
        for (int i = 0; i < clauseArr.length / 2; i++) {
            data.put("clauseTitle" + (i + 1), clauseArr[i * 2]);
            data.put("clauseText" + (i + 1), clauseArr[i * 2 + 1]);
        }

        // ---------- 3. 渲染 ----------
        JPdfConfig config = new JPdfConfig();
        config.getLayoutConfig().setFlexLayout(true);
        // 右边距留 74pt 给骑缝章条
        config.getDoc().setMargins(Arrays.asList(58, 74, 56, 62));
        config.getHeaderConfig().setEnabled(true);
        config.getHeaderConfig().setText("安全生产责任书 " + data.get("docNo"));
        config.getHeaderConfig().setFontSize(8);
        config.getHeaderConfig().setHeight(34);
        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);
    }

    private static void mkdirs() {
        new File(PDF_DIR).mkdirs();
        new File(IMG_DIR).mkdirs();
    }

    /**
     * 返回条款数组:偶数下标为条标题(含「第 N 条」前缀),奇数下标为正文。
     */
    private static String[] buildClauses() {
        List<String> clauses = new ArrayList<String>();
        clauses.add("组织保障\n"
                + "责任人作为本单位安全生产第一责任人,对本单位安全生产工作全面负责,须健全安全生产责任制,"
                + "逐级签订责任书并落实到班组、岗位;每月至少主持召开一次安全生产专题会议,研究解决重大安全问题。");
        clauses.add("制度建设与执行\n"
                + "组织制定并落实安全生产规章制度和安全操作规程,建立健全风险分级管控与隐患排查治理双重预防机制;"
                + "对危大工程须编制专项施工方案,组织专家论证并按方案施工,严禁擅自变更。");
        clauses.add("安全生产投入\n"
                + "按不低于产值 1.5% 的比例提取安全生产费用,专款专用于安全防护设施、劳动保护用品、教育培训、"
                + "应急物资及安全技术改造,不得挪作他用;安全费用使用情况须按季度公示。");
        clauses.add("教育培训\n"
                + "组织全员安全生产教育培训,新入场人员须完成三级安全教育并考核合格后方可上岗;"
                + "特种作业人员必须持有效证件上岗,建立培训档案并保留不少于三年的记录。");
        clauses.add("隐患排查与治理\n"
                + "组织开展日常巡查、专项检查与季节性检查,对发现的隐患实行清单化管理,做到整改措施、责任、资金、"
                + "时限、预案五落实;重大隐患须立即停止作业并向上级主管部门报告。");
        clauses.add("应急管理\n"
                + "制定生产安全事故应急救援预案并每年至少组织两次演练,配备必要的应急救援器材与装备;"
                + "发生事故后须在规定时间内上报,严禁迟报、漏报、谎报或瞒报。");
        clauses.add("职业健康\n"
                + "落实职业病危害因素检测与告知制度,为从业人员提供符合标准的劳动防护用品并监督正确佩戴使用;"
                + "组织接触职业病危害岗位人员定期体检,建立职业健康监护档案。");
        clauses.add("事故报告与处理\n"
                + "坚持事故原因未查清不放过、责任人员未处理不放过、整改措施未落实不放过、有关人员未受到教育不放过的原则,"
                + "按四不放过要求组织调查处理,并召开现场分析会举一反三。");

        String[] result = new String[clauses.size() * 2];
        for (int i = 0; i < clauses.size(); i++) {
            // 按 \n 切成段:首段是条标题,其余是正文
            String[] lines = clauses.get(i).split("\n");
            result[i * 2] = "第 " + (i + 1) + " 条 " + lines[0];
            StringBuilder text = new StringBuilder();
            for (int j = 1; j < lines.length; j++) {
                text.append(lines[j]);
            }
            result[i * 2 + 1] = text.toString();
        }
        return result;
    }

    /**
     * 把整枚印章横向切成 strips 条窄图,用于骑缝章输出。
     *
     * @param sealPath 完整印章图片路径
     * @param strips   切分条数(建议 3~5)
     * @param prefix   输出文件前缀,结果形如 prefix0.png
     * @return 各细条路径,按从左到右顺序
     */
    public static List<String> splitSealForRidge(String sealPath, int strips, String prefix) throws IOException {
        BufferedImage source = ImageIO.read(new File(sealPath));
        int stripWidth = Math.max(1, source.getWidth() / strips);
        List<String> paths = new ArrayList<String>();
        for (int i = 0; i < strips; i++) {
            int x = i * stripWidth;
            int w = Math.min(stripWidth, source.getWidth() - x);
            BufferedImage part = source.getSubimage(x, 0, w, source.getHeight());
            String path = prefix + i + ".png";
            ImageIO.write(part, "png", new File(path));
            paths.add(path);
        }
        return paths;
    }

    /** 生成手写签名图片(楷体 + 轻微旋转)。 */
    private static void generateSignature(String path, String name) throws IOException {
        BufferedImage image = new BufferedImage(220, 104, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = image.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.rotate(Math.toRadians(-3), 110, 52);
        g.setColor(new Color(0x1B, 0x2A, 0x3A));
        g.setFont(new Font("KaiTi", Font.PLAIN, 44));
        g.drawString(name, 26, 72);
        g.dispose();
        ImageIO.write(image, "png", new File(path));
    }

    /** 生成单位公章(双圈 + 五角星 + 名称)。 */
    private static void generateSeal(String path, String orgName) throws IOException {
        int size = 220;
        BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = image.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        Color red = new Color(0xC6, 0x28, 0x28);
        g.setColor(red);
        g.setStroke(new BasicStroke(7f));
        g.drawOval(7, 7, size - 14, size - 14);
        g.setStroke(new BasicStroke(2f));
        g.drawOval(19, 19, size - 38, size - 38);
        g.fill(star(size / 2, size / 2 - 8, 22));
        double startAngle = -160;
        double step = 200.0 / Math.max(1, orgName.length());
        for (int i = 0; i < orgName.length(); i++) {
            double angle = Math.toRadians(startAngle + step * i);
            int r = 76;
            int x = (int) (size / 2 + r * Math.cos(angle));
            int y = (int) (size / 2 + r * Math.sin(angle));
            Graphics2D g2 = (Graphics2D) g.create();
            g2.rotate(angle + Math.PI / 2, x, y);
            g2.setFont(new Font("Microsoft YaHei", Font.BOLD, 13));
            g2.drawString(String.valueOf(orgName.charAt(i)), x - 7, y + 6);
            g2.dispose();
        }
        g.setFont(new Font("Microsoft YaHei", Font.BOLD, 15));
        g.drawString("公章", size / 2 - 16, size - 34);
        g.dispose();
        ImageIO.write(image, "png", new File(path));
    }

    private static Shape star(int cx, int cy, int radius) {
        java.awt.geom.Path2D.Double path = new java.awt.geom.Path2D.Double();
        for (int i = 0; i < 10; i++) {
            double r = (i % 2 == 0) ? radius : radius * 0.4;
            double angle = Math.toRadians(-90 + i * 36);
            double x = cx + r * Math.cos(angle);
            double y = cy + r * Math.sin(angle);
            if (i == 0) {
                path.moveTo(x, y);
            } else {
                path.lineTo(x, y);
            }
        }
        path.closePath();
        return path;
    }
}

Minimal invocation (3 lines)

Skip the full test class — the core is these three lines: bind the chart SVG, execute the template, get the PDF bytes. Copy them straight into your project.

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

Template file · 93_safety_responsibility.txt

An HTML-like template with inline CSS that renders to PDF once bound to data. The full template is below — copy it or download the raw file.

<pdf>
<body>

  <!-- 标题 -->
  <h1 style="fontSize:20pt; bold:true; color:#7A1F1F; textAlignment:center; characterSpacing:6pt">'安 全 生 产 责 任 书'</h1>
  <p style="fontSize:9pt; color:#5A6B7C; textAlignment:center; marginBottom:10px">'编号:'${docNo}</p>

  <!-- 责任主体信息(两列布局:标签 + 内容,铺满版心) -->
  <table style="width:100%; fontSize:9.5pt; marginBottom:9px">
    <tr>
      <td style="width:90px; padding:5px; backgroundColor:#F4E6E6; bold:true; border:1px solid #D8C3C3">'责任单位'</td>
      <td style="padding:5px; border:1px solid #D8C3C3">${unit}</td>
    </tr>
    <tr>
      <td style="padding:5px; backgroundColor:#F4E6E6; bold:true; border:1px solid #D8C3C3">'责任人'</td>
      <td style="padding:5px; border:1px solid #D8C3C3">${personLine}</td>
    </tr>
    <tr>
      <td style="padding:5px; backgroundColor:#F4E6E6; bold:true; border:1px solid #D8C3C3">'身份证号'</td>
      <td style="padding:5px; border:1px solid #D8C3C3">${idLine}</td>
    </tr>
    <tr>
      <td style="padding:5px; backgroundColor:#F4E6E6; bold:true; border:1px solid #D8C3C3">'责任期限'</td>
      <td style="padding:5px; border:1px solid #D8C3C3">${period}</td>
    </tr>
  </table>

  <!-- 前言 -->
  <p style="fontSize:10.5pt; color:#333333; textIndent:21pt; marginBottom:5px">'为全面落实安全生产主体责任,防范和减少生产安全事故,保障从业人员的生命安全与身体健康,根据《中华人民共和国安全生产法》《生产安全事故报告和调查处理条例》等法律法规,本单位与责任人签订本责任书,明确双方安全生产职责与考核要求。'</p>

  <!-- 一、责任目标 -->
  <h2 style="fontSize:11pt; bold:true; color:#7A1F1F; borderLeft:3px solid #7A1F1F; paddingLeft:6px; marginTop:10px; marginBottom:5px">'一、安全生产责任目标'</h2>
  <table style="width:100%; fontSize:9pt; marginBottom:6px">
    <tr>
      <th style="width:38%; padding:5px; backgroundColor:#7A1F1F; color:white; textAlign:center; border:1px solid #7A1F1F">'考核指标'</th>
      <th style="width:22%; padding:5px; backgroundColor:#7A1F1F; color:white; textAlign:center; border:1px solid #7A1F1F">'目标值'</th>
      <th style="padding:5px; backgroundColor:#7A1F1F; color:white; textAlign:center; border:1px solid #7A1F1F">'考核方式'</th>
    </tr>
    <tr>
      <td style="padding:5px; border:1px solid #D8C3C3">'生产安全事故死亡人数'</td>
      <td style="padding:5px; textAlign:center; border:1px solid #D8C3C3">'0 人'</td>
      <td style="padding:5px; border:1px solid #D8C3C3">'事故台账 + 政府通报'</td>
    </tr>
    <tr>
      <td style="padding:5px; border:1px solid #D8C3C3">'较大及以上事故'</td>
      <td style="padding:5px; textAlign:center; border:1px solid #D8C3C3">'0 起'</td>
      <td style="padding:5px; border:1px solid #D8C3C3">'事故调查报告'</td>
    </tr>
    <tr>
      <td style="padding:5px; border:1px solid #D8C3C3">'重伤事故率'</td>
      <td style="padding:5px; textAlign:center; border:1px solid #D8C3C3">'≤0.3‰'</td>
      <td style="padding:5px; border:1px solid #D8C3C3">'工伤认定数据'</td>
    </tr>
    <tr>
      <td style="padding:5px; border:1px solid #D8C3C3">'隐患整改闭环率'</td>
      <td style="padding:5px; textAlign:center; border:1px solid #D8C3C3">'100%'</td>
      <td style="padding:5px; border:1px solid #D8C3C3">'隐患排查系统记录'</td>
    </tr>
    <tr>
      <td style="padding:5px; border:1px solid #D8C3C3">'安全教育培训覆盖率'</td>
      <td style="padding:5px; textAlign:center; border:1px solid #D8C3C3">'100%'</td>
      <td style="padding:5px; border:1px solid #D8C3C3">'培训签到与考核成绩'</td>
    </tr>
    <tr>
      <td style="padding:5px; border:1px solid #D8C3C3">'特种作业持证上岗率'</td>
      <td style="padding:5px; textAlign:center; border:1px solid #D8C3C3">'100%'</td>
      <td style="padding:5px; border:1px solid #D8C3C3">'证件台账抽查'</td>
    </tr>
    <tr>
      <td style="padding:5px; border:1px solid #D8C3C3">'安全投入占产值比例'</td>
      <td style="padding:5px; textAlign:center; border:1px solid #D8C3C3">'≥1.5%'</td>
      <td style="padding:5px; border:1px solid #D8C3C3">'财务专项账目'</td>
    </tr>
  </table>

  <!-- 二、责任条款(每条两个变量:条标题 + 正文,均为 Java 侧 bind 注入) -->
  <h2 style="fontSize:11pt; bold:true; color:#7A1F1F; borderLeft:3px solid #7A1F1F; paddingLeft:6px; marginTop:10px; marginBottom:5px">'二、安全生产责任条款'</h2>

  <p style="fontSize:10.5pt; bold:true; color:#7A1F1F; textIndent:21pt; marginTop:6px; marginBottom:2px">${clauseTitle1}</p>
  <p style="fontSize:10pt; color:#333333; textIndent:21pt; marginBottom:3px">${clauseText1}</p>

  <p style="fontSize:10.5pt; bold:true; color:#7A1F1F; textIndent:21pt; marginTop:6px; marginBottom:2px">${clauseTitle2}</p>
  <p style="fontSize:10pt; color:#333333; textIndent:21pt; marginBottom:3px">${clauseText2}</p>

  <p style="fontSize:10.5pt; bold:true; color:#7A1F1F; textIndent:21pt; marginTop:6px; marginBottom:2px">${clauseTitle3}</p>
  <p style="fontSize:10pt; color:#333333; textIndent:21pt; marginBottom:3px">${clauseText3}</p>

  <p style="fontSize:10.5pt; bold:true; color:#7A1F1F; textIndent:21pt; marginTop:6px; marginBottom:2px">${clauseTitle4}</p>
  <p style="fontSize:10pt; color:#333333; textIndent:21pt; marginBottom:3px">${clauseText4}</p>

  <p style="fontSize:10.5pt; bold:true; color:#7A1F1F; textIndent:21pt; marginTop:6px; marginBottom:2px">${clauseTitle5}</p>
  <p style="fontSize:10pt; color:#333333; textIndent:21pt; marginBottom:3px">${clauseText5}</p>

  <p style="fontSize:10.5pt; bold:true; color:#7A1F1F; textIndent:21pt; marginTop:6px; marginBottom:2px">${clauseTitle6}</p>
  <p style="fontSize:10pt; color:#333333; textIndent:21pt; marginBottom:3px">${clauseText6}</p>

  <p style="fontSize:10.5pt; bold:true; color:#7A1F1F; textIndent:21pt; marginTop:6px; marginBottom:2px">${clauseTitle7}</p>
  <p style="fontSize:10pt; color:#333333; textIndent:21pt; marginBottom:3px">${clauseText7}</p>

  <p style="fontSize:10.5pt; bold:true; color:#7A1F1F; textIndent:21pt; marginTop:6px; marginBottom:2px">${clauseTitle8}</p>
  <p style="fontSize:10pt; color:#333333; textIndent:21pt; marginBottom:3px">${clauseText8}</p>

  <!-- 三、考核与追责 -->
  <h2 style="fontSize:11pt; bold:true; color:#7A1F1F; borderLeft:3px solid #7A1F1F; paddingLeft:6px; marginTop:10px; marginBottom:5px">'三、考核与责任追究'</h2>
  <list style="fontSize:10pt; color:#333333; listStyleType:decimal; marginLeft:20px">
    <li>'考核周期为每季度一次,由单位安全生产管理委员会组织,考核结果纳入年度绩效评价。'</li>
    <li>'完成全部责任目标且全年无事故的,给予安全生产专项奖励;连续两个季度考核优秀的,优先推荐评优。'</li>
    <li>'未完成责任目标或发生责任事故的,视情节轻重给予通报批评、扣减绩效、调整岗位等处理。'</li>
    <li>'因失职渎职造成重大事故的,依法承担行政责任与民事责任;构成犯罪的,移交司法机关处理。'</li>
  </list>

  <p style="fontSize:10.5pt; color:#333333; textIndent:21pt; marginTop:8px">'本责任书一式两份,责任单位与责任人各持一份,自双方签字盖章之日起生效,有效期与责任期限一致。未尽事宜由双方协商解决。'</p>

  <!-- 骑缝章条 -->
  <!-- 骑缝章条(图片由 Demo 生成到固定路径 D:/test/image/,此处按字面量引用;
       注:当前渲染引擎的 image src 仅支持字面量路径,不解析 ${var} 变量) -->
  <p style="fontSize:8pt; color:#8a939b; marginTop:10px">'骑缝章:本页右侧竖排为骑缝章条,打印后沿装订线裁切,与各页边缘切口叠合可还原为完整印章。'</p>
  <div style="display:flex; justifyContent:flex-start; marginTop:2px">
    <image src='D:/test/image/93_ridge_0.png' style="width:15px; height:96px"></image>
    <image src='D:/test/image/93_ridge_1.png' style="width:15px; height:96px"></image>
    <image src='D:/test/image/93_ridge_2.png' style="width:15px; height:96px"></image>
    <image src='D:/test/image/93_ridge_3.png' style="width:15px; height:96px"></image>
  </div>

  <!-- 双方签字盖章 -->
  <div style="display:flex; justifyContent:space-between; marginTop:20px">
    <div style="width:49%; border:1px dashed #C3A0A0; padding:8px">
      <p style="fontSize:9.5pt; bold:true; color:#7A1F1F">'责任单位(盖章)'</p>
      <p style="fontSize:9pt; color:#5A6B7C">${unit}</p>
      <image src='D:/test/image/93_seal.png' style="width:96px; height:96px"></image>
      <p style="fontSize:9pt; color:#5A6B7C">'日期:'${signDate}</p>
    </div>
    <div style="width:49%; border:1px dashed #C3A0A0; padding:8px">
      <p style="fontSize:9.5pt; bold:true; color:#7A1F1F">'责任人(签字)'</p>
      <p style="fontSize:9pt; color:#5A6B7C">${responsiblePerson}' '${personPost}</p>
      <image src='D:/test/image/93_sign.png' style="width:116px; height:56px"></image>
      <p style="fontSize:9pt; color:#5A6B7C">'日期:'${signDate}</p>
    </div>
  </div>

</body>
</pdf>

More demos in this group

The PDF, preview image, template and source code on this page were all produced by a real JQuick-Pdf run and are free to copy into your own project.