Java使用IText7动态生成带审批文本框的PDF文档

Java使用IText7动态生成带审批文本框的PDF文档

文章目录

测试结果示例

实现思路

使用Canvas进行相对定位和绝对定位来确定文本框内文字位置,用Rectangle通过坐标转换来确定文本框的位置

xml 复制代码
   <itext.version>7.1.2</itext.version>
xml 复制代码
 <!--itext-->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>kernel</artifactId>
            <version>${itext.version}</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>io</artifactId>
            <version>${itext.version}</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>layout</artifactId>
            <version>${itext.version}</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>forms</artifactId>
            <version>${itext.version}</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>pdfa</artifactId>
            <version>${itext.version}</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>pdftest</artifactId>
            <version>${itext.version}</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>font-asian</artifactId>
            <version>${itext.version}</version>
        </dependency>

1.构建第一个框的起始坐标

注意:由于Rectangle构造的坐标为以文档的左下角为xy轴,为了支持计算分页顺序添加需要转换到左上角

java 复制代码
        //第一个文本框(非审批框,高度比较大有特殊自动换行需求)
        // 定义文本框坐标和矩形尺寸(左上点坐标)
        float xLeftTop = 80;    // 左上角x坐标
        float yLeftTop = 100;   // 左上角y坐标
        float width = 450;      // 矩形宽度
        float height = 300;      // 矩形高度

        //坐标转换:默认是左下角坐标轴
        PdfPage firstPage = pdfDoc.getPage(1);
        float yBottom = firstPage.getPageSize().getHeight() - yLeftTop - height;
        Rectangle rect = new Rectangle(xLeftTop, yBottom, width, height);

2.渲染第一个框

使用Canvas进行相对定位和绝对定位,来确保文本框内的文字内容位置

为了防止自动换行超出框内,建议Canvas布局的宽度小于文本框的布局

java 复制代码
    private void createIndexFieldText(Document doc, PdfFont font, String text, Rectangle rect) {

        // 创建Canvas进行绝对定位
        PdfCanvas pdfCanvas = new PdfCanvas(doc.getPdfDocument().getLastPage());
        //防止字体出框
        Rectangle textArea = new Rectangle(rect.getX(), rect.getY(), rect.getWidth()-20, rect.getHeight());
        Canvas canvas = new Canvas(pdfCanvas, doc.getPdfDocument(), textArea);
        // 绘制文本框边框
        pdfCanvas.setStrokeColor(ColorConstants.BLACK).rectangle(rect).stroke();
        //相对定位
        Paragraph approve = new Paragraph()
                .setFont(font)
                .setFontSize(12)
                .setRelativePosition(10, 10,0,0)
                .add("致______________:");
        canvas.add(approve);
        Paragraph approve1 = new Paragraph()
                .setFont(font)
                .setFontSize(12).setFirstLineIndent(25)
                .setRelativePosition(10,  10,0,0)
                .add("________________机构:");
        canvas.add(approve1);

        Paragraph approve2 = new Paragraph("我方承担的工程," +
                "已完成相关准备工作,申请开工,请予以审核,批准。")
                .setTextAlignment(TextAlignment.JUSTIFIED)
                .setFont(font).setFirstLineIndent(25)
                .setRelativePosition(10, 10, 0,0)
                .setFontSize(12);
        canvas.add(approve2);

        // 审批相关绝对定位
        Paragraph fieldText = new Paragraph()
                .setFont(font)
                .setFontSize(12).setTextAlignment(TextAlignment.RIGHT)
                .setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 40, 300)
                .add(text);
        canvas.add(fieldText);
        // 在文本框内添加
        Paragraph dateText = new Paragraph()
                .setFont(font)
                .setFontSize(12).setTextAlignment(TextAlignment.RIGHT)
                .setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 20, 300)
                .add("日期:                        ");
        canvas.add(dateText);
        canvas.close();
    }

3.渲染其他的审批框

原理同大框,需计算是否需要分页,如分页需要重置新页面的起始坐标,且由于大框高度大于其他框,需要重置高度,多个框添加时需计算y轴坐标。

java 复制代码
   /**
     * 添加审批文本框
     */
    private static void addTextField(Document doc, PdfFont font, String text, Rectangle rect,boolean page) {
        // 创建Canvas进行绝对定位
        PdfCanvas pdfCanvas = new PdfCanvas(doc.getPdfDocument().getLastPage());
        //防止字体出框
        Rectangle textArea = new Rectangle(rect.getX(), rect.getY(), rect.getWidth()-20, rect.getHeight());
        if(page){
            pdfCanvas = new PdfCanvas(doc.getPdfDocument().addNewPage());
        }
        Canvas canvas = new Canvas(pdfCanvas, doc.getPdfDocument(), textArea);
        // 绘制文本框边框
        pdfCanvas.setStrokeColor(ColorConstants.BLACK).rectangle(rect).stroke();
        //审核意见定位
        Paragraph approve = new Paragraph()
                .setFont(font)
                .setFontSize(12)
                .setFixedPosition(rect.getX() + 10,  rect.getY()+rect.getHeight()-25,200)
                .add("审核意见:");
        canvas.add(approve);
        // 在文本框内添加
        Paragraph fieldText = new Paragraph()
                .setFont(font)
                .setFontSize(12).setTextAlignment(TextAlignment.RIGHT)
                .setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 40, 300)
                .add(text);
        canvas.add(fieldText);
        // 在文本框内添加
        Paragraph dateText = new Paragraph()
                .setFont(font)
                .setFontSize(12).setTextAlignment(TextAlignment.RIGHT)
                .setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 20, 300)
                .add("日期:                        ");
        canvas.add(dateText);
        canvas.close();

    }

4.完整代码

java 复制代码
package com.moshangshang.pdf.controller;

import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.property.TextAlignment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;


@RestController
@RequestMapping("")
public class PDFController {


    /**
     * 带文本框的审批表生成
     */
    @GetMapping(value = "/pdf")
    public void test( HttpServletResponse response) throws Exception {
        response.setContentType("application/pdf");
        OutputStream os = response.getOutputStream();
        // 创建 PDF 文档
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(os));
        Document document = new Document(pdfDoc,PageSize.A4);
        PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H", true);
        // 设置页面尺寸和边距
        document.setMargins(50, 50, 50, 50);

        Paragraph title = new Paragraph("审批测试表")
                .setTextAlignment(TextAlignment.CENTER)
                .setFont(font).setBold().setFontSize(22);
        document.add(title);

        List<String> unitList = Arrays.asList("测试1","测试2","测试3","测试4","测试5","测试6","测试7","测试8","测试9");

        //文本框绘制索引
        int fieldTextIndex = 1;

        //第一个文本框(非审批框,高度比较大有特殊自动换行需求)
        // 定义文本框坐标和矩形尺寸(左上点坐标)
        float xLeftTop = 80;    // 左上角x坐标
        float yLeftTop = 100;   // 左上角y坐标
        float width = 450;      // 矩形宽度
        float height = 300;      // 矩形高度

        //坐标转换:默认是左下角坐标轴
        PdfPage firstPage = pdfDoc.getPage(1);
        float yBottom = firstPage.getPageSize().getHeight() - yLeftTop - height;
        Rectangle rect = new Rectangle(xLeftTop, yBottom, width, height);

        for (String name : unitList) {
            //定位
            if(fieldTextIndex == 1){
                //开工报告第一个大框添加
                createIndexFieldText(document, font, name+"(签字、印章):", rect,false);
            }else {
                //其他全为同等审批框,修改高度
                height = 150;
                //默认第一页三个框,其他页默认四个
                if(fieldTextIndex%4==0){
                    //如果大于单页数量,创建新页,并重置坐标
                    float yBottom1 = firstPage.getPageSize().getHeight() - yLeftTop - height;
                    rect = new Rectangle(xLeftTop, yBottom1, width, height);
                    addTextField(document, font, name+" (签字、印章):", rect,true);
                    fieldTextIndex++;
                    continue;
                }
                rect = new Rectangle(xLeftTop, rect.getY()-height, width, height);
                // 绘制文本框边框
                addTextField(document, font, name+"(签字、印章):", rect,false);
            }
            fieldTextIndex++;
        }

        document.close();
    }

    /**
     *
     */
    private void createIndexFieldText(Document doc, PdfFont font, String text, Rectangle rect,boolean page) {

        // 创建Canvas进行绝对定位
        PdfCanvas pdfCanvas = new PdfCanvas(doc.getPdfDocument().getLastPage());
        //防止字体出框
        Rectangle textArea = new Rectangle(rect.getX(), rect.getY(), rect.getWidth()-20, rect.getHeight());
        if(page){
             pdfCanvas = new PdfCanvas(doc.getPdfDocument().addNewPage());
        }
        Canvas canvas = new Canvas(pdfCanvas, doc.getPdfDocument(), textArea);
        // 绘制文本框边框
        pdfCanvas.setStrokeColor(ColorConstants.BLACK).rectangle(rect).stroke();
        //相对定位
        Paragraph approve = new Paragraph()
                .setFont(font)
                .setFontSize(12)
                .setRelativePosition(10,  10,0,0)
                .add("致______________(单位):");
        canvas.add(approve);
        Paragraph approve1 = new Paragraph()
                .setFont(font)
                .setFontSize(12).setFirstLineIndent(25)
                .setRelativePosition(10,  10,0,0)
                .add("________________机构:");
        canvas.add(approve1);

        Paragraph approve2 = new Paragraph("我方," +
                "已完成相关准备工作,具备开工条件,申请于2025年开工,请予以审核,批准。")
                .setTextAlignment(TextAlignment.JUSTIFIED)
                .setFont(font).setFirstLineIndent(25)
                .setRelativePosition(10, 10, 0,0)
                .setFontSize(12);
        canvas.add(approve2);

        // 审批相关绝对定位
        Paragraph fieldText = new Paragraph()
                .setFont(font)
                .setFontSize(12).setTextAlignment(TextAlignment.RIGHT)
                .setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 40, 300)
                .add(text);
        canvas.add(fieldText);
        // 在文本框内添加
        Paragraph dateText = new Paragraph()
                .setFont(font)
                .setFontSize(12).setTextAlignment(TextAlignment.RIGHT)
                .setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 20, 300)
                .add("日期:                        ");
        canvas.add(dateText);
        canvas.close();
    }



    /**
     * 添加审批文本框
     */
    private static void addTextField(Document doc, PdfFont font, String text, Rectangle rect,boolean page) {
        // 创建Canvas进行绝对定位
        PdfCanvas pdfCanvas = new PdfCanvas(doc.getPdfDocument().getLastPage());
        //防止字体出框
        Rectangle textArea = new Rectangle(rect.getX(), rect.getY(), rect.getWidth()-20, rect.getHeight());
        if(page){
            pdfCanvas = new PdfCanvas(doc.getPdfDocument().addNewPage());
        }
        Canvas canvas = new Canvas(pdfCanvas, doc.getPdfDocument(), textArea);
        // 绘制文本框边框
        pdfCanvas.setStrokeColor(ColorConstants.BLACK).rectangle(rect).stroke();
        //审核意见定位
        Paragraph approve = new Paragraph()
                .setFont(font)
                .setFontSize(12)
                .setFixedPosition(rect.getX() + 10,  rect.getY()+rect.getHeight()-25,200)
                .add("审核意见:");
        canvas.add(approve);
        // 在文本框内添加
        Paragraph fieldText = new Paragraph()
                .setFont(font)
                .setFontSize(12).setTextAlignment(TextAlignment.RIGHT)
                .setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 40, 300)
                .add(text);
        canvas.add(fieldText);
        // 在文本框内添加
        Paragraph dateText = new Paragraph()
                .setFont(font)
                .setFontSize(12).setTextAlignment(TextAlignment.RIGHT)
                .setFixedPosition(rect.getX() + rect.getWidth()-400, rect.getY() + 20, 300)
                .add("日期:                        ");
        canvas.add(dateText);
        canvas.close();

    }

}
相关推荐
Lxinccode1 小时前
Java查询数据库表信息导出Word-获取数据库实现[1]:KingbaseES
java·数据库·word·获取数据库信息·获取kingbasees信息
元亓亓亓2 小时前
Java后端开发day36--源码解析:HashMap
java·开发语言·数据结构
sd21315122 小时前
RabbitMQ 复习总结
java·rabbitmq
码银4 小时前
Java 集合:泛型、Set 集合及其实现类详解
java·开发语言
东阳马生架构4 小时前
Nacos简介—4.Nacos架构和原理
java
一只叫煤球的猫5 小时前
你真的会用 return 吗?—— 11个值得借鉴的 return 写法
java·后端·代码规范
颇有几分姿色5 小时前
Spring Boot 读取配置文件的几种方式
java·spring boot·后端
爱编程的鱼5 小时前
C# 枚举(Enum)声明与使用详解
java·windows·c#
人生导师yxc5 小时前
Spring MVC
java·spring·mvc
曹牧5 小时前
Java 调用webservice接口输出xml自动转义
java·开发语言·javascript