Java自定义生成PDF报告
流程分析
為滿足上述需求,需要通過程序?qū)崿F(xiàn)自定義生成PDF文件。幸運(yùn)的是目前已有對(duì)應(yīng)的代碼解決方案可以實(shí)現(xiàn)該需求。方案涉及到itextpdf類庫、AdobeAcrobat DC的使用。整體流程如下:
自定義生成PDF文件流程圖
由上圖可知,生成自定義PDF文件流程主要分為三個(gè)部分。模板配置,數(shù)據(jù)映射,數(shù)據(jù)填充。其中,模板配置需要用到AdobeAcrobat DC軟件(一款PDF編輯器),在模板配置過程中,需要設(shè)置好PDF文件各個(gè)屬性名稱,方便后續(xù)的數(shù)據(jù)映射。最后通過itextpdf類庫提供的方案,將業(yè)務(wù)數(shù)據(jù)填充到PDF模板并生成PDF文件。
步驟介紹
一、PDF模板配置
?????? 配置PDF模板需要用到AdobeAcrobat DC軟件,該軟件的綠色版本請(qǐng)見附件。首先需要?jiǎng)?chuàng)建一個(gè)PDF文件,然后使用AdobeAcrobat DC打開,如下圖:
?打開空白PDF文檔
????????選擇右側(cè)“準(zhǔn)備表單”選項(xiàng),即可編輯PDF模板。模板中可以添加圖片域、文本域,可以設(shè)置各個(gè)域的名稱。例如標(biāo)題的名稱為title。如下圖:
?PDF模板配置
注:上述PDF模板中配置的各個(gè)域和預(yù)期生成的PDF文件數(shù)據(jù)要一一對(duì)應(yīng),例如,如果需要在PDF文件上方居中位置展示標(biāo)題內(nèi)容,則需要在PDF模板中創(chuàng)建一個(gè)文本域,文本域名稱為title。然后在JAVA代碼中,將標(biāo)題內(nèi)容通過title這個(gè)key填充到模板中。
?????? 在設(shè)置PDF模板時(shí),我們可以自定義各個(gè)域的展示效果,包括圖片域、按鈕域中展示的圖片具體如下圖:
添加PDF模板默認(rèn)圖標(biāo)?
還可以設(shè)置文本域中文字的展示字體、大小。如下圖:
?設(shè)置PDF模板文字屬性
按照業(yè)務(wù)需要配置完P(guān)DF模板后需要將模板保存為PDF文件,后續(xù)JAVA代碼填充數(shù)據(jù)時(shí)需要向該P(yáng)DF文件中寫入數(shù)據(jù)。配置完成的PDF文件如下:
?PDF模板編輯效果
二、數(shù)據(jù)寫入
?????? 當(dāng)我們配置好PDF模板以后,我們需要通過JAVA代碼講業(yè)務(wù)數(shù)據(jù)填入PDF模板,從而得到最終的PDF文件。
?????? 數(shù)據(jù)寫入需要用到itextpdf和itext-asian兩個(gè)類庫。使用方法也很簡單。只需要在項(xiàng)目pom文件中導(dǎo)入這兩個(gè)類庫的maven依賴。
| <dependency> ??????????? <groupId>com.itextpdf</groupId> ??????????? <artifactId>itextpdf</artifactId> ??????????? <version>5.5.13.2</version> ??????? </dependency> ??????? <dependency> ??????????? <groupId>com.itextpdf</groupId> ??????????? <artifactId>itext-asian</artifactId> ??????????? <version>5.2.0</version> ??????? </dependency> |
?????? 依賴引入成功后,我們就可以使用PdfReader 和PdfStamper這兩個(gè)類來實(shí)現(xiàn)PDF模板的讀取和PDF數(shù)據(jù)填充功能。
(1)配置文件讀取/寫入
?????? 配置文件的讀取很簡單,首先通過PdfReader讀取PDF模板文件,然后結(jié)合數(shù)據(jù)輸出流,創(chuàng)建PdfStamper即可。如下圖:
| PdfReader reader = new PdfReader("D:\\test.pdf")?? //讀取模板文件 ByteArrayOutputStream bos = new ByteArrayOutputStream();? //創(chuàng)建輸出流 PdfStamper stamper = stamper = new PdfStamper(reader, bos) //創(chuàng)建PDF文件填充對(duì)象 |
(2)業(yè)務(wù)數(shù)據(jù)映射
?????? 文件填充對(duì)象創(chuàng)建成功后,需要向該對(duì)象添加數(shù)據(jù),常見的數(shù)據(jù)有兩種,一種是文本數(shù)據(jù),一種是圖片數(shù)據(jù)。接下來我將分別說明兩種數(shù)據(jù)的填充方式,并分別提供案例。
?????? 第一種文本數(shù)據(jù),文本數(shù)據(jù)相對(duì)比較簡單,只需要處理stamper對(duì)象中的AcroFields對(duì)象即可。處理時(shí)需要設(shè)置文本字體和文本內(nèi)容與PDF模板的映射。
| AcroFields form = stamper.getAcroFields();?? //獲取AcroFields對(duì)象 BaseFont bf =? com.itextpdf.text.pdf.BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false); Font FontChinese = new Font(bf, 5, Font.NORMAL);?? //創(chuàng)建字體 form.addSubstitutionFont(bf);? //添加字體屬性 Map<String,String> fieldMap = new HashMap<>(); fieldMap.put("name","張三");?? //創(chuàng)建文本映射關(guān)系 form.setField(key, fieldMap.get(“name”));?? //填充文本信息 |
注:
Key和PDF模板的映射關(guān)系如下圖:
?
第二種圖片數(shù)據(jù),圖片數(shù)據(jù)同樣需要處理AcroFields對(duì)象,但是相比于文本數(shù)據(jù),圖片數(shù)據(jù)的處理更加負(fù)責(zé),如下代碼:
| Map<String,String> map2 = new HashMap(); map2.put("testimage","D:\\qwqqqq.png");?? //獲取需要填充的圖片 //根據(jù)圖片存儲(chǔ)路徑創(chuàng)建圖片對(duì)象 String value = map2.get(“testimage”); String imgpath = value; int pageNo = form.getFieldPositions(key).get(0).page; Rectangle signRect = form.getFieldPositions(key).get(0).position;? //此處key與PDF模板對(duì)應(yīng) float x = signRect.getLeft();? //圖片坐標(biāo) float y = signRect.getBottom(); //圖片坐標(biāo),默認(rèn)按照PDF模板設(shè)置展示 //根據(jù)路徑讀取圖片 Image image = Image.getInstance(imgpath); //獲取圖片頁面 PdfContentByte under = stamper.getOverContent(pageNo); //圖片大小自適應(yīng) image.scaleToFit(signRect.getWidth(), signRect.getHeight()); //添加圖片 image.setAbsolutePosition(x, y); under.addImage(image); |
?????? 文本和圖片數(shù)據(jù)添加完成后,需要執(zhí)行最后一步,生成PDF文件。
| stamper.setFormFlattening(true);// 如果為false,生成的PDF文件可以編輯,如果為true,生成的PDF文件不可以編輯 FileOutputStream out = new FileOutputStream(filePath+fileName);? //PDF文件最終輸出路徑和PDF文件名稱 stamper.close(); Document doc = new Document(); Font font = new Font(bf, 32); PdfCopy copy = new PdfCopy(doc, out);? //將數(shù)據(jù)輸出流通過copy輸出 doc.open(); PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1); copy.addPage(importPage); doc.close(); |
總結(jié)
以上是生活随笔為你收集整理的Java自定义生成PDF报告的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于 block的一些浅识
- 下一篇: JVM内存结构和Java内存模型别再傻傻