實(shí)驗(yàn)時間: 2020-09-23
代碼: https://github.com/mefly521/springbootAllinone spring-boot-pdf-template模塊
本文介紹將一個制作好的模板自動填充上動態(tài)內(nèi)容的方法.
網(wǎng)上有好多方法沒有一一實(shí)驗(yàn),因?yàn)橛行┎荒芸缙脚_,有些需要裝dll 或其它第三方組件所以將其排除.
只介紹我實(shí)驗(yàn)成功的2種方法 :
方法1生成速度比較快,但需要下載 Adobe Acrobat dc 編輯模板,
方法2 為word 模板,先將word模板的動態(tài)內(nèi)容填充后,再將word 轉(zhuǎn)成 pdf.缺點(diǎn)是速度比較慢,將近10秒
1 pdf模板生成
下載 Adobe Acrobat dc
http://www.downza.cn/soft/20562.html
用dc 打開pdf , 編寫靜態(tài)文字
再點(diǎn)準(zhǔn)備表單
將文本框放上去, 將編輯名稱, 名稱是后面用于替換的key
引用的包
<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對應(yīng)PDF表單中的fieldNames赫舒,Value則是你想填充的值
HashMap map = new HashMap<String, String>();
map.put("number","2020");
map.put("sex","On"); //Value為On 則勾選這個復(fù)選框
map.put("test","On"); //Value為On 則勾選這個復(fù)選框
map.put("fill_1","被檢查單位123232");
map.put("fill_18","有一小鳥首装,它的家搭在最高的樹枝上跪帝,它的羽毛還未豐滿印蔬,不能要飛能庆,每日只在家里嘰嘰地叫著派哲,和兩只老鳥說著話兒偎血,他們都是覺得非常的快樂。這一天早晨雕沉,它醒了集乔,那兩個老鳥都找食物去了。一看見火紅的太陽坡椒,它們又害怕了扰路,因?yàn)樘柼罅耍鼈冇挚匆娨豢脴渖系囊黄么蟮臉淙~倔叼,樹葉上又有站著一只小鳥汗唱,正在吃害蟲,害蟲吃了很多樹葉丈攒,讓大樹不能長大哩罪,大樹是我們的好朋友,每一棵樹都產(chǎn)生氧氣巡验,讓我們每一個人呼吸际插。這時老鳥馬上飛過去,與小鳥一起吃害蟲显设,吃得飽飽的框弛,并為民除害。");
String sourceFile = "D:\\temp\\01\\p22.pdf"; //原文件路徑
String targetFile = "D:\\temp\\01\\output.pdf"; //目標(biāo)文件路徑
PdfUtils.genPdf(map,sourceFile,targetFile);
}
/**
* @param map 需要填充的字段
* @param sourceFile 原文件路徑
* @param targetFile 目標(biāo)文件路徑
* @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中的參數(shù)填充pdf捕捂,map中的key和pdf表單中的field對應(yīng) <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對應(yīng)的Value是否為On瑟枫,若是則勾選復(fù)選框
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("填充參數(shù)異常");
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: 讀取文件數(shù)組<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;
}
// 確保所有數(shù)據(jù)均被讀取
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(); //默認(rèn)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 {
//關(guān)閉PDF文檔流,OutputStream文件輸出流也將在PDF文檔流關(guān)閉方法內(nèi)部關(guān)閉
if (document != null) {
document.close();
}
}
}
}
2 先成word 再轉(zhuǎn)成pdf
制作一個word 模板再使用 poi-tl (http://deepoove.com/poi-tl/)這個組件填充內(nèi)容
再將word 轉(zhuǎn)成pdf (具體看這篇文章 https://blog.csdn.net/hunwanjie/article/details/97135633,親測可用)
但是測試后發(fā)現(xiàn)轉(zhuǎn)換時間比較長, 用了將近10秒,考慮到性能問題,暫時將第2種設(shè)為備選.
優(yōu)先使用第一種,除非找不到編輯pdf 的軟件 .
Java使用itext 根據(jù)PDF模板進(jìn)行填充并生成_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