使用itextpdf解決PDF合并的問題
itextpdf解決PDF合并的問題
本文章是我在項(xiàng)目開發(fā)過程中解決了一個(gè)關(guān)于PDF顯示的需求而記錄的。
需求是這樣的,需要將兩個(gè)PDF進(jìn)行合并,一個(gè)PDF是根據(jù)數(shù)據(jù)庫的信息在在后臺(tái)形成的(實(shí)際不存在的PDF),另一個(gè)是磁盤保存的PDF文件(這個(gè)PDF文件后期會(huì)變成從云端獲?。?/p>
作為一個(gè)Java菜鳥,這個(gè)問題解決了數(shù)天,還是在leader的指導(dǎo)下解決的。在這里做一下關(guān)鍵代碼的記錄。
項(xiàng)目主要包含了以下關(guān)鍵詞:(我不做詳解了,主要是用了這些)
- Spring MVC、Spring、Hibernate
- Maven
- Java
- itextpdf
- MySQL
- JavaWeb相關(guān)
首先是itextpdf的依賴
<dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.10</version> </dependency>
如何在后臺(tái)生成一個(gè)PDF
這個(gè)問題,百度上有很多解決方案,因?yàn)槲倚枰獙⑦@個(gè)生成的PDF和已存在的PDF拼接,于是嘗試了多種方案,決定將這個(gè)以文檔的形式,將這個(gè)文檔轉(zhuǎn)為字節(jié)數(shù)組,然后用itextpdf將流讀取到PDF中。
生成PDF的部分代碼:
import java.io.ByteArrayOutputStream; import com.model.User; import com.itextpdf.text.BaseColor; import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Element; import com.itextpdf.text.Font; import com.itextpdf.text.Paragraph; import com.itextpdf.text.pdf.BaseFont; import com.itextpdf.text.pdf.PdfContentByte; import com.itextpdf.text.pdf.PdfPCell; import com.itextpdf.text.pdf.PdfPTable; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfWriter; import com.itextpdf.text.pdf.parser.PdfReaderContentParser; public class ReportKit { public static byte[] createReport(User user) throws Exception { ByteArrayOutputStream ba = new ByteArrayOutputStream(); Document doc = new Document();//創(chuàng)建一個(gè)document對(duì)象 PdfWriter writer = PdfWriter.getInstance(doc, ba);//這個(gè)PdfWriter會(huì)一直往文檔里寫內(nèi)容。 doc.open();//開啟文檔 BaseFont bfChinese = BaseFont.createFont("c://windows//fonts//msyh.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); com.itextpdf.text.Font FontChinese18 = new com.itextpdf.text.Font(bfChinese, 18, com.itextpdf.text.Font.BOLD); com.itextpdf.text.Font FontChinese12 = new com.itextpdf.text.Font(bfChinese, 12, com.itextpdf.text.Font.NORMAL); com.itextpdf.text.Font FontChinese11 = new com.itextpdf.text.Font(bfChinese, 11, com.itextpdf.text.Font.ITALIC); Font fontChinese = new Font(bfChinese , 12 , Font.NORMAL, BaseColor.BLACK); Paragraph pf = new Paragraph(""); //加入空行 Paragraph blankRow1 = new Paragraph(24f," ",FontChinese18); doc.add(blankRow1); //table2 PdfPTable table25 = new PdfPTable(2); //設(shè)置每列寬度比例 int width21[] = {2,98}; table25.setWidths(width21); table25.getDefaultCell().setBorder(0); PdfPCell cell25 = new PdfPCell(new Paragraph("這是一個(gè)報(bào)告",FontChinese18)); cell25.setBorder(0); table25.addCell(""); table25.addCell(cell25); doc.add(table25); Paragraph blankRow3 = new Paragraph(18f, "Report ", FontChinese11); blankRow3.setAlignment(PdfContentByte.ALIGN_RIGHT); doc.add(blankRow3); BaseColor lightGrey = new BaseColor(0xCC,0xCC,0xCC); PdfPTable table8 = new PdfPTable(6); //設(shè)置table的寬度為100% table8.setWidthPercentage(100); //設(shè)置不同列的寬度 float[] columnWidths = {1.6f, 1.6f, 1.6f, 1.6f, 1.6f, 1.6f}; table8.setWidths(columnWidths); PdfPCell cell1 = new PdfPCell(new Paragraph("用戶名",FontChinese12)); PdfPCell cell2 = new PdfPCell(new Paragraph("出生日期",FontChinese12)); PdfPCell cell3 = new PdfPCell(new Paragraph("性別",FontChinese12)); PdfPCell cell4 = new PdfPCell(new Paragraph("身高",FontChinese12)); PdfPCell cell5 = new PdfPCell(new Paragraph("體重",FontChinese12)); PdfPCell cell6 = new PdfPCell(new Paragraph("地區(qū)",FontChinese12)); PdfPCell cell7 = new PdfPCell(new Paragraph(user.getAccessname(),FontChinese12)); PdfPCell cell8 = new PdfPCell(new Paragraph(user.getBirthday(),FontChinese12)); PdfPCell cell9 = new PdfPCell(new Paragraph(sex,FontChinese12)); PdfPCell cell10 = new PdfPCell(new Paragraph(String.valueOf(user.getHeight()),FontChinese12)); PdfPCell cell11 = new PdfPCell(new Paragraph(String.valueOf(user.getWeight()),FontChinese12)); PdfPCell cell12 = new PdfPCell(new Paragraph(user.getArea_name(),FontChinese12)); //表格高度 cell1.setFixedHeight(30); cell2.setFixedHeight(30); cell3.setFixedHeight(30); cell4.setFixedHeight(30); cell5.setFixedHeight(30); cell6.setFixedHeight(30); cell7.setFixedHeight(30); cell8.setFixedHeight(30); cell9.setFixedHeight(30); cell10.setFixedHeight(30); cell11.setFixedHeight(30); cell12.setFixedHeight(30); //水平居中 cell1.setHorizontalAlignment(Element.ALIGN_CENTER); cell2.setHorizontalAlignment(Element.ALIGN_CENTER); cell3.setHorizontalAlignment(Element.ALIGN_CENTER); cell4.setHorizontalAlignment(Element.ALIGN_CENTER); cell5.setHorizontalAlignment(Element.ALIGN_CENTER); cell6.setHorizontalAlignment(Element.ALIGN_CENTER); cell7.setHorizontalAlignment(Element.ALIGN_CENTER); cell8.setHorizontalAlignment(Element.ALIGN_CENTER); cell9.setHorizontalAlignment(Element.ALIGN_CENTER); cell10.setHorizontalAlignment(Element.ALIGN_CENTER); cell11.setHorizontalAlignment(Element.ALIGN_CENTER); cell12.setHorizontalAlignment(Element.ALIGN_CENTER); //垂直居中 cell1.setVerticalAlignment(Element.ALIGN_MIDDLE); cell2.setVerticalAlignment(Element.ALIGN_MIDDLE); cell3.setVerticalAlignment(Element.ALIGN_MIDDLE); cell4.setVerticalAlignment(Element.ALIGN_MIDDLE); cell5.setVerticalAlignment(Element.ALIGN_MIDDLE); cell6.setVerticalAlignment(Element.ALIGN_MIDDLE); cell7.setVerticalAlignment(Element.ALIGN_MIDDLE); cell8.setVerticalAlignment(Element.ALIGN_MIDDLE); cell9.setVerticalAlignment(Element.ALIGN_MIDDLE); cell10.setVerticalAlignment(Element.ALIGN_MIDDLE); cell11.setVerticalAlignment(Element.ALIGN_MIDDLE); cell12.setVerticalAlignment(Element.ALIGN_MIDDLE); //邊框顏色 cell1.setBorderColor(lightGrey); cell2.setBorderColor(lightGrey); cell3.setBorderColor(lightGrey); cell4.setBorderColor(lightGrey); cell5.setBorderColor(lightGrey); cell6.setBorderColor(lightGrey); cell7.setBorderColor(lightGrey); cell8.setBorderColor(lightGrey); cell9.setBorderColor(lightGrey); cell10.setBorderColor(lightGrey); cell11.setBorderColor(lightGrey); cell12.setBorderColor(lightGrey); table8.addCell(cell1); table8.addCell(cell2); table8.addCell(cell3); table8.addCell(cell4); table8.addCell(cell5); table8.addCell(cell6); table8.addCell(cell7); table8.addCell(cell8); table8.addCell(cell9); table8.addCell(cell10); table8.addCell(cell11); table8.addCell(cell12); doc.add(table8); doc.close();//(有開啟文檔,就要記得關(guān)閉文檔) writer.close(); byte[] bytes = ba.toByteArray(); return bytes; } }
用document來編輯文檔,真的蠻惡心的,費(fèi)時(shí)費(fèi)力,排版也不好調(diào),如果能有更加好用的方式,希望大家能告訴我。
到這里,調(diào)用這個(gè)方法,就可以獲得這個(gè)文檔的字節(jié)數(shù)組了。
接下來開始拼接PDF。因?yàn)槭墙Y(jié)合前端頁面實(shí)現(xiàn)的。因此這個(gè)方法是我在controller完成的。
//注意這里的produces,“application/pdf”,正是因?yàn)樵O(shè)置了這個(gè),使得整個(gè)方法會(huì)將文檔以PDF的格式返回到頁面。 @RequestMapping(value = "/newPdf/{report_name}", produces = "application/pdf;charset=UTF-8") public void updateReport(Model model, @PathVariable String report_name, HttpServletRequest request, HttpServletResponse response,HttpSession session) { try { User user = (User) session.getAttribute("user"); //這是用戶登錄后保存到session里的用戶信息(可以用別的對(duì)象來替代這個(gè)) if(user==null){ return ; } PdfReader reader1 =null; try { // 調(diào)用剛剛寫的生成PDF的方法,將這個(gè)字節(jié)數(shù)組獲取。 byte[] pdfUserByte=ReportKit.createReport(user); if(pdfUserByte==null||pdfUserByte.length==0){ return; } //用pdfReader來讀取字節(jié)數(shù)組,這里將文檔信息讀入 reader1 = new PdfReader(pdfUserByte); } catch (Exception e) { System.out.println(e.getMessage()); return ; } if(reader1==null) return; //第二個(gè)PDF的讀取 PdfReader reader2; // 報(bào)告的PDF reader2 = new PdfReader("C:\\Users\\Administrator\\Desktop\\report.pdf"); Document document = new Document(); PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream()); document.open(); PdfContentByte cb = writer.getDirectContent(); int totalPages = 0; totalPages += reader1.getNumberOfPages(); totalPages += reader2.getNumberOfPages(); java.util.List<PdfReader> readers = new ArrayList<PdfReader>(); readers.add(reader1); readers.add(reader2); int pageOfCurrentReaderPDF = 0; Iterator<PdfReader> iteratorPDFReader = readers.iterator(); // Loop through the PDF files and add to the output. while (iteratorPDFReader.hasNext()) { PdfReader pdfReader = iteratorPDFReader.next(); // Create a new page in the target for each source page. while (pageOfCurrentReaderPDF < pdfReader.getNumberOfPages()) { document.newPage();//創(chuàng)建新的一頁 pageOfCurrentReaderPDF++; PdfImportedPage page = writer.getImportedPage(pdfReader, pageOfCurrentReaderPDF); cb.addTemplate(page, 0, 0); } pageOfCurrentReaderPDF = 0; } document.close(); writer.close(); } catch (IOException | DocumentException e) { e.printStackTrace(); } }
關(guān)于如何在頁面預(yù)覽這個(gè)PDF,我用了object標(biāo)簽來獲取。
jsp上的部分片段
<div class="pdf" id="pdf" ><!-- pdf --> <object type="application/pdf" data="http://localhost:8080/project/newPdf/${report.report_name}" id="review" style="width:1100px; height:1000px; margin-top:25px; margin-left:50px" > </object> </div>
標(biāo)簽很好的實(shí)現(xiàn)了PDF預(yù)覽的功能,如果是URL的PDF,data直接輸入U(xiǎn)RL,就能將PDF在頁面預(yù)覽,感覺蠻好用的。
iText 合并PDF文件報(bào)錯(cuò)
在使用iText操作PDF進(jìn)行合并的時(shí)候報(bào)錯(cuò):
com.lowagie.text.exceptions.BadPasswordException: PdfReader not opened with owner password
public static PdfReader unlockPdf(PdfReader pdfReader) { if (pdfReader == null) { return pdfReader; } try { java.lang.reflect.Field f = pdfReader.getClass().getDeclaredField("encrypted"); f.setAccessible(true); f.set(pdfReader, false); } catch (Exception e) { // ignore } return pdfReader; }
對(duì)reader使用上述方法即可解決該問題。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
j2ee mybatis注解@Data,@TableName,@TableField使用方式
這篇文章主要介紹了j2ee mybatis注解@Data,@TableName,@TableField使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04解決maven啟動(dòng)Spring項(xiàng)目報(bào)錯(cuò)的問題
下面小編就為大家分享一篇解決maven啟動(dòng)Spring項(xiàng)目報(bào)錯(cuò)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12解讀springboot配置mybatis的sql執(zhí)行超時(shí)時(shí)間(mysql)
這篇文章主要介紹了解讀springboot配置mybatis的sql執(zhí)行超時(shí)時(shí)間(mysql),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01java實(shí)現(xiàn)定制數(shù)據(jù)透視表的示例詳解
數(shù)據(jù)透視表(Pivot?Table)是一種數(shù)據(jù)分析工具,通常用于對(duì)大量數(shù)據(jù)進(jìn)行匯總、分析和展示,本文主要介紹了如何使用Java將計(jì)算項(xiàng)添加到數(shù)據(jù)透視表中,感興趣的可以了解下2023-12-12java中treemap和treeset實(shí)現(xiàn)紅黑樹
這篇文章主要為大家詳細(xì)介紹了java中treemap和treeset實(shí)現(xiàn)紅黑樹,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11