java springboot 生成pdf 亲测可用 附源码

实验时间: 2020-09-23
代码: https://github.com/mefly521/springbootAllinone spring-boot-pdf-template模块

本文介绍将一个制作好的模板自动填充上动态内容的方法.
网上有好多方法没有一一实验,因为有些不能跨平台,有些需要装dll 或其它第三方组件所以将其排除.

只介绍我实验成功的2种方法 :
方法1生成速度比较快,但需要下载 Adobe Acrobat dc 编辑模板,
方法2 为word 模板,先将word模板的动态内容填充后,再将word 转成 pdf.缺点是速度比较慢,将近10秒

1 pdf模板生成

下载 Adobe Acrobat dc
http://www.downza.cn/soft/20562.html

用dc 打开pdf , 编写静态文字


image.png

再点准备表单
将文本框放上去, 将编辑名称, 名称是后面用于替换的key


image.png

引用的包

<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.11</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.8.0</version>
        </dependency>

        <!-- itextpdf 依赖包 -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.10</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>

代码

package com.demo.controller;

import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.*;
import java.util.*;

/**
 * 生成pdf的工具类
 */
public class PdfUtils
{
    public static void main(String[] args) throws IOException
    {
        //Map中Key对应PDF表单中的fieldNames,Value则是你想填充的值
        HashMap map = new HashMap<String, String>();
        map.put("number","2020");
        map.put("sex","On");    //Value为On 则勾选这个复选框
        map.put("test","On");   //Value为On 则勾选这个复选框
        map.put("fill_1","被检查单位123232");
        map.put("fill_18","有一小鸟,它的家搭在最高的树枝上,它的羽毛还未丰满,不能要飞,每日只在家里叽叽地叫着,和两只老鸟说着话儿,他们都是觉得非常的快乐。这一天早晨,它醒了,那两个老鸟都找食物去了。一看见火红的太阳,它们又害怕了,因为太阳太大了,它们又看见一棵树上的一片好大的树叶,树叶上又有站着一只小鸟,正在吃害虫,害虫吃了很多树叶,让大树不能长大,大树是我们的好朋友,每一棵树都产生氧气,让我们每一个人呼吸。这时老鸟马上飞过去,与小鸟一起吃害虫,吃得饱饱的,并为民除害。");
        String sourceFile = "D:\\temp\\01\\p22.pdf"; //原文件路径
        String targetFile = "D:\\temp\\01\\output.pdf";     //目标文件路径
        PdfUtils.genPdf(map,sourceFile,targetFile);
    }

    /**
     * @param map 需要填充的字段
     * @param sourceFile  原文件路径
     * @param targetFile  目标文件路径
     * @throws IOException
     */
    public static void genPdf(HashMap map, String sourceFile, String targetFile) throws IOException {
        File templateFile = new File(sourceFile);
        fillParam(map, FileUtils.readFileToByteArray(templateFile), targetFile);
    }

    /**
     * Description: 使用map中的参数填充pdf,map中的key和pdf表单中的field对应 <br>
     * @author mk
     * @Date 2018-11-2 15:21 <br>
     * @Param
     * @return
     */
    public static void fillParam(Map<String, String> fieldValueMap, byte[] file, String contractFileName) {
        FileOutputStream fos = null;
        try {

            fos = new FileOutputStream(contractFileName);
            PdfReader reader = null;
            PdfStamper stamper = null;
            BaseFont base = null;
            try {
                reader = new PdfReader(file);
                stamper = new PdfStamper(reader, fos);
                stamper.setFormFlattening(true);
                base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); //简体中文字体
                //base = BaseFont.createFont("MHei-Medium", "UniCNS-UCS2-H", BaseFont.NOT_EMBEDDED);  //繁体中文字体
                AcroFields acroFields = stamper.getAcroFields();
                for (String key : acroFields.getFields().keySet()) {
                    acroFields.setFieldProperty(key, "textfont", base, null);
                    acroFields.setFieldProperty(key, "textsize", new Float(9), null);   //字体大小
                }
                if (fieldValueMap != null) {
                    for (String fieldName : fieldValueMap.keySet())
                    {
                        if (StringUtils.isNotBlank(fieldValueMap.get(fieldName)))
                        {
                            //获取map中key对应的Value是否为On,若是则勾选复选框
                            if (fieldValueMap.get(fieldName).equals("On") || fieldValueMap.get(fieldName) == "On")
                            {
                                acroFields.setField(fieldName, fieldValueMap.get(fieldName),true);
                            }else
                            {
                                acroFields.setField(fieldName, fieldValueMap.get(fieldName));
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (stamper != null) {
                    try {
                        stamper.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                if (reader != null) {
                    reader.close();
                }
            }

        } catch (Exception e) {
            System.out.println("填充参数异常");
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(fos);
        }
    }


    /**
     * Description: 获取pdf表单中的fieldNames<br>
     * @author mk
     * @Date 2018-11-2 15:21 <br>
     * @Param
     * @return
     */
    public static Set<String> getTemplateFileFieldNames(String pdfFileName) {
        Set<String> fieldNames = new TreeSet<String>();
        PdfReader reader = null;
        try {
            reader = new PdfReader(pdfFileName);
            Set<String> keys = reader.getAcroFields().getFields().keySet();
            for (String key : keys) {
                int lastIndexOf = key.lastIndexOf(".");
                int lastIndexOf2 = key.lastIndexOf("[");
                fieldNames.add(key.substring(lastIndexOf != -1 ? lastIndexOf + 1 : 0, lastIndexOf2 != -1 ? lastIndexOf2 : key.length()));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                reader.close();
            }
        }

        return fieldNames;
    }


    /**
     * Description: 读取文件数组<br>
     * @author mk
     * @Date 2018-11-2 15:21 <br>
     * @Param
     * @return
     */
    public static byte[] fileBuff(String filePath) throws IOException {
        File file = new File(filePath);
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            //System.out.println("file too big...");
            return null;
        }
        FileInputStream fi = new FileInputStream(file);
        byte[] file_buff = new byte[(int) fileSize];
        int offset = 0;
        int numRead = 0;
        while (offset < file_buff.length && (numRead = fi.read(file_buff, offset, file_buff.length - offset)) >= 0) {
            offset += numRead;
        }
        // 确保所有数据均被读取
        if (offset != file_buff.length) {
            throw new IOException("Could not completely read file " + file.getName());
        }
        fi.close();
        return file_buff;
    }

    /**
     * Description: 合并pdf <br>
     * @author mk
     * @Date 2018-11-2 15:21 <br>
     * @Param
     * @return
     */
    public static void mergePdfFiles(String[] files, String savepath) {
        Document document = null;
        try {
            document = new Document(); //默认A4大小
            PdfCopy copy = new PdfCopy(document, new FileOutputStream(savepath));
            document.open();
            for (int i = 0; i < files.length; i++) {
                PdfReader reader = null;
                try {
                    reader = new PdfReader(files[i]);
                    int n = reader.getNumberOfPages();
                    for (int j = 1; j <= n; j++) {
                        document.newPage();
                        PdfImportedPage page = copy.getImportedPage(reader, j);
                        copy.addPage(page);
                    }
                } finally {
                    if (reader != null) {
                        reader.close();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭PDF文档流,OutputStream文件输出流也将在PDF文档流关闭方法内部关闭
            if (document != null) {
                document.close();
            }

        }
    }
}


2 先成word 再转成pdf

制作一个word 模板再使用 poi-tl (http://deepoove.com/poi-tl/)这个组件填充内容
再将word 转成pdf (具体看这篇文章 https://blog.csdn.net/hunwanjie/article/details/97135633,亲测可用)
但是测试后发现转换时间比较长, 用了将近10秒,考虑到性能问题,暂时将第2种设为备选.
优先使用第一种,除非找不到编辑pdf 的软件 .

Java使用itext 根据PDF模板进行填充并生成_weixin_43910274的博客-CSDN博客
https://blog.csdn.net/weixin_43910274/article/details/104916106?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342