JAVA-创建PDF文档

目录

一、前期准备

1、中文字体文件

2、maven依赖

二、创建PDF文档方法

三、通过可填充PDF模板将业务参数进行填充

1、 设置可填充的PDF表单

2、代码开干,代码填充可编辑PDF并另存文件



一、前期准备

1、中文字体文件

本演示使用的是iText 7版本,如果没有中文字体,那生成的PDF文档涉及中文的区域都无法显示。

现有查找到的PDF免费下载网址如下:

  • 阿里巴巴矢量图标库:除了图标库,该网站还提供了一些免费的字体库供下载和使用。
  • 字由:字由是一个专注于中文字体的网站,提供了一些优质的免费字体供下载。
  • 字体中国:字体中国是一个提供中文字体下载的网站,包含了许多中文设计师的作品。
  • 站长之家字体库:站长之家提供了大量的免费字体库,包含了各种中文字体和英文字体。

2、maven依赖

    <dependencies>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext7-core</artifactId>
            <version>7.2.5</version>
            <type>pom</type>
        </dependency>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>kernel</artifactId>
            <version>7.2.5</version>
        </dependency>

    </dependencies>

二、创建PDF文档方法

import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
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.Cell;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.HorizontalAlignment;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

public class CreatePdf {

    //文件根目录
    public static String RootPath = "D:/files-pdf/";
    // 设置字体文件路径
    //注意:如果没有中文字体,那PDF内容涉及中文的区域都不显示
    public static String fontPath = RootPath + "ZiTiQuanWeiJunHei-W1-2.ttf";

    public static void main(String[] args) {

        String pdfName = "testContent.pdf";

        // 创建 PdfWriter 和 PdfDocument
        PdfWriter writer = null;
        try {
            writer = new PdfWriter(pdfName + ".pdf");
        } catch (FileNotFoundException e) {
            System.out.println("创建PdfWriter失败。。。。。");
            e.printStackTrace();
            return;
        }

        PdfDocument pdfDocument = new PdfDocument(writer);

        // 创建 Document
        Document document = new Document(pdfDocument);

        // 设置页面的边距
        documentMargins(document);

        // 设置页眉和页脚
        headerAndFooter(pdfDocument);

        //编写PDF主体的文档内容 , 这一块是主要编写位置
        setContent(document);

        //添加水印
        addWatermark(pdfDocument);

        // 关闭对象
        document.close();   //document文档要在输出前关闭,不然会提示“java.nio.file.NoSuchFileException: editable.pdf”
        pdfDocument.close();

        // 将生成的 PDF 文件移动到指定目录下
        downloadPdf(RootPath, pdfName);
    }

    /**
     * 获取设置的字体
     *
     * @return PdfFont 字体
     */
    private static PdfFont getFont() {
        // 设置中文字体
        PdfFont font = null;
        try {
            font = PdfFontFactory.createFont(fontPath);
        } catch (IOException e) {
            System.out.println("字体获取失败。。。。。。。。。。。");
            e.printStackTrace();
            return null;
        }
        return font;
    }

    /**
     * 设置页面的边距
     *
     * @param document 内容文档
     */
    private static void documentMargins(Document document) {
        // 上、右、下、左
        int margins = 80;
        document.setMargins(margins, margins, margins, margins);
    }

    /**
     * 设置页眉页脚
     *
     * @param pdfDocument PDF文档
     */
    private static void headerAndFooter(PdfDocument pdfDocument) {

        pdfDocument.addEventHandler(PdfDocumentEvent.START_PAGE, new IEventHandler() {

            @Override
            public void handleEvent(Event event) {
                PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
                PdfPage page = docEvent.getPage();
                PdfCanvas canvas = new PdfCanvas(page);

                // 创建页眉
                Rectangle pageSize = page.getPageSize();

                canvas.beginText()
                        .setFontAndSize(getFont(), 10)
                        .moveText(pageSize.getWidth() / 2, pageSize.getTop() - 20)
                        .showText("这是页眉")
                        .endText();

                // 创建页脚
                canvas.beginText()
                        .setFontAndSize(getFont(), 10)
                        .moveText(pageSize.getWidth() / 2, pageSize.getBottom() + 20)
                        .showText("这是页脚")
                        .endText();

                canvas.release();
            }
        });
    }


    /**
     * 添加水印
     *
     * @param pdfDocument PDF文档
     * @throws MalformedURLException
     */
    private static void addWatermark(PdfDocument pdfDocument) {

        // 加载水印图片
        String watermarkImage = RootPath + "zm5.jpg";
        Image image = null;
        try {
            image = new Image(ImageDataFactory.create(watermarkImage));
        } catch (MalformedURLException e) {
            System.out.println("获取水印图片失败 , e : " + e);
            e.printStackTrace();
            return;
        }

        // 获取 PDF 页面的大小,此处是要以页面区域做参考,后续好设置对应的坐标填充水印
        Rectangle rectanglePageSize = pdfDocument.getDefaultPageSize();

        // 遍历每个页面,添加水印
        for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
            //创建PDF画布
            PdfCanvas pdfCanvas = new PdfCanvas(pdfDocument.getPage(i));

            // 创建 Canvas 画布对象,设置位置和大小
            Canvas canvas = new Canvas(pdfCanvas, rectanglePageSize, true);

            // 在水印画布上添加图片,并设置透明度和位置
            // 上、右、下、左
            image.setOpacity(0.8f).setMargins(600, 200, 0, 300);
            canvas.add(image);

            // 关闭水印画布
            canvas.close();
        }
    }

    /**
     * 生成的 PDF 文件移动到指定目录下
     *
     * @param rootPath 存储目录
     * @param pdfName  PDF文件名
     * @return
     */
    private static String downloadPdf(String rootPath, String pdfName) {

        // 假设生成的 PDF 文件路径为 sourcePath
        Path sourcePath = Paths.get(pdfName + ".pdf");
        // 假设目标目录路径为 targetDirectoryPath
        Path targetDirectoryPath = Paths.get(rootPath);
        // 移动文件到目标目录
        Path targetPath = null;
        try {
            targetPath = Files.move(sourcePath, targetDirectoryPath.resolve(sourcePath.getFileName()), StandardCopyOption.REPLACE_EXISTING);
            // 输出成功信息
            System.out.println("文件移动成功,目标路径:" + targetPath);
            return targetPath.toString();
        } catch (IOException e) {
            // 输出失败信息
            System.out.println("文件移动失败,目标路径:" + targetPath);
            e.printStackTrace();
            return null;
        }
    }

    /**
     * PDF主体内容
     *
     * @param document 文档
     */
    private static void setContent(Document document) {

        // 设置中文字体
        PdfFont font = getFont();

        /********************************  段落内容由 Paragraph 区域编写 ******************************************/
        // 创建段落标题
        Paragraph paragraphTitle = new Paragraph().setFont(font);
        // setBold:设置粗体,setItalic:斜体,setUnderline:下划线
        paragraphTitle.add("这是一份PDF测试文档").setBold().setFontSize(12);
        // 设置段落的对齐方式为居中
        paragraphTitle.setTextAlignment(TextAlignment.CENTER);
        document.add(paragraphTitle);

        // 创建一个可编辑的段落
        Paragraph nameOfStaff = new Paragraph().setFont(font).setFontSize(10);
        nameOfStaff.add("Name of Developer / 开发人员:");
        document.add(nameOfStaff);

        Paragraph fullname = new Paragraph().setFont(font).setFontSize(10);
        fullname.add("____________________(Note: 请写全名)");
        document.add(fullname);

        Paragraph paragraph1 = new Paragraph().setFont(font).setFontSize(9);
        paragraph1.add("这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!" +
                "这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!" +
                "这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!" +
                "这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!" +
                "这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!这是段落内容!");
        document.add(paragraph1);

        Paragraph declare = new Paragraph().setFont(font).setFontSize(9);
        declare.add("I hereby declare that:");
        document.add(declare);

        Paragraph section = new Paragraph().setFont(font).setFontSize(9).setBold().setUnderline();
        section.add("多选项声明确认!Multiple option declaration confirmation!");
        document.add(section);

        // 创建一个带有复选框的列表
        Paragraph paragraph2 = new Paragraph().setFont(font).setFontSize(9);
        paragraph2.add("(Please tick in the box as appropriate)").add("\n");
        paragraph2.add("口 声明内容1。。。声明内容1。。。声明内容1。。。声明内容1。。。声明内容1。。。声明内容1。。。").add("\n");
        paragraph2.add("口 声明内容2。。。声明内容2。。。声明内容2。。。声明内容2。。。声明内容2。。。声明内容2。。。").add("\n");
        document.add(paragraph2);


        /********************************  表格由 Table 区域编写 ******************************************/
        // 创建表格并设置列数和默认宽度
        Table table = new Table(4);
//            table.setMaxWidth(1000);  //固定式宽度
//            table.setAutoLayout();    //根据内容自适应宽度
        table.setWidth(UnitValue.createPercentValue(100));  //页面总宽固定
        // 添加表格标题(合并4列)
        Cell titleCell = new Cell(1, 4);
        // 创建文本对象
        titleCell.add(new Paragraph("Table Title"));
        titleCell.setTextAlignment(TextAlignment.CENTER);
        table.addHeaderCell(titleCell);

        // 添加表头
        table.addHeaderCell("Header 1");
        table.addHeaderCell("Header 2");
        table.addHeaderCell("Header 3");
        table.addHeaderCell("Header 4");

        // 添加表格内容
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 4; j++) {
                Cell cell = new Cell()
                        .setFont(font)
                        .add(new Paragraph("行 " + (i + 1) + ", Col " + (j + 1)))
                        .setWidth(UnitValue.createPercentValue(25));
                table.addCell(cell);
            }
        }
        // 设置表格样式
        table.setHorizontalAlignment(HorizontalAlignment.CENTER);

        // 将表格添加到文档中
        document.add(table);

        /********************************  内容区域编写END ******************************************/
    }

}

三、通过可填充PDF模板将业务参数进行填充

1、 设置可填充的PDF表单

至于编辑器自行查找,免费的基本大多会添加水印。

设置成功后,如下图,可编辑区高亮显示

 

2、代码开干,代码填充可编辑PDF并另存文件

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class FillingPdfTemplate {

    //文件根目录
    public static String RootPath = "D:/files-pdf/";
    // 设置字体文件路径
    //注意:如果没有中文字体,那PDF内容涉及中文的区域都不显示
    public static String fontPath = RootPath + "ZiTiQuanWeiJunHei-W1-2.ttf";


    public static void main(String[] args) {
        Map<String, String> mapParam = new HashMap<>();
        mapParam.put("fullname", "某某某");
        mapParam.put("Check Box1","On");
        mapParam.put("Check Box2", "Off");
        mapParam.put("account1", "account1");
        mapParam.put("broker1", "broker1");
        mapParam.put("number1", "number1");
        mapParam.put("security1", "security1");
        mapParam.put("sharehold1", "sharehold1");
        mapParam.put("clp1", "clp1");
        mapParam.put("shares1", "shares1");
        mapParam.put("sharehold3", "");
        mapParam.put("clp3", "");
        mapParam.put("shares3", "");
        mapParam.put("name1", "某某某");
        mapParam.put("position", "XXX高级");
        mapParam.put("company", "深圳市XXX科技有限公司");
        mapParam.put("date", "2023-05-24");

        String templatePdfPath = RootPath + "Acrobat-demo.pdf";
        String destPdfPath = RootPath + "Acrobat-demo-result.pdf";
        replaceTextFieldPdf(templatePdfPath, destPdfPath, mapParam);
    }

    /**
     * 获取设置的字体
     *
     * @return PdfFont 字体
     */
    private static PdfFont getFont() {
        // 设置中文字体
        PdfFont font = null;
        try {
            font = PdfFontFactory.createFont(fontPath);
        } catch (IOException e) {
            System.out.println("字体获取失败。。。。。。。。。。。");
            e.printStackTrace();
            return null;
        }
        return font;
    }

    /**
     * 替换PDF文本表单域变量
     *
     * @param templatePdfPath 要替换的pdf全路径
     * @param params          替换参数
     * @param destPdfPath     替换后保存的PDF全路径
     * @throws IOException
     */
    public static final void replaceTextFieldPdf(String templatePdfPath, String destPdfPath,
                                                 Map<String, String> params) {

        PdfDocument pdfDoc = null;
        try {
            pdfDoc = new PdfDocument(new PdfReader(templatePdfPath), new PdfWriter(destPdfPath));
        } catch (IOException e) {
            e.printStackTrace();
        }

        //获取表单信息
        PdfAcroForm pdfAcroForm = PdfAcroForm.getAcroForm(pdfDoc, true);

        //遍历填充预设的值
        Set<Map.Entry<String, String>> entries = params.entrySet();
        entries.stream().forEach(entry -> {
            if(pdfAcroForm.getField(entry.getKey()) != null){
                // 设置表单字段的值
                //复选框类型的:1勾选,2圆圈,3叉叉,4菱形,5方块,6星星
                //如果不想复选框被选中,要设置为"Off",选中设置为"On",注意大小写
                pdfAcroForm.getField(entry.getKey()).setCheckType(1).setValue(entry.getValue() , true).setFont(getFont());
            }
        });
        // 添加表单字段
//        PdfTextFormField textField = PdfFormField.createText(pdfDoc, new Rectangle(100, 100, 200, 20), "newField", "");
//        pdfAcroForm.addField(textField);
        //表单扁平化,设置后生成的文档不可再编辑
//        pdfAcroForm.flattenFields();
        pdfDoc.close();
    }


}

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java使用com.lowagie.text.pdf插件编写的PDF报表工具类,支持动态报表创建,使用简单,附件中包含了测试类和生成的报表文件。附件中的代码需要修改相关的保存路径后可以直接使用。创建一张报表例子: private JsFileExportResult createRowReport() { String condition = "开始时间:2018-02-02 14:00:30 结束时间:2018-02-06 16:00:30"; PDFGridReport pdfReport = new PDFGridReport("报表创建测试", GridReportTestModel.getModels()); pdfReport.addCondition(condition); pdfReport.header("字段名称1", "item1", 0, 0).width(160); pdfReport.header("字段名称3", "item3", 0, 2).getCell().backgroundColor(Color.ORANGE); pdfReport.header("字段名称4", "item4", 0, 3); pdfReport.header("字段名称5", "item5", 0, 4); pdfReport.header("字段名称2", "item2", 0, 1); pdfReport.header("值", "value", 0, 5).alignH(HAlign.ALIGN_CENTER).getCell().alignH(HAlign.ALIGN_RIGHT); pdfReport.header("时间", "time", 0, 6); pdfReport.header("图片", "image", 0, 7).width(60).alignH(HAlign.ALIGN_CENTER).getCell() .alignH(HAlign.ALIGN_CENTER).alignV(VAlign.ALIGN_MIDDLE); // 横向打印 pdfReport.getPageSetting().setPrintHorizontal(); pdfReport.group("item1").childGroup("item2"); pdfReport.setCellFormat(new PDFCellValueFormat() { @Override public String format(String fieldName, String oriValue) { if ("value".equals(fieldName)) { return String.format("%.2f", Double.parseDouble(oriValue)).toString(); } else { return oriValue; } } }); JsFileExportResult fileResult = pdfReport.createReport(); return fileResult; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值