使用itextpdf解决PDF合并的问题
itextpdf解决PDF合并的问题
本文章是我在项目开发过程中解决了一个关于PDF显示的需求而记录的。
需求是这样的,需要将两个PDF进行合并,一个PDF是根据数据库的信息在在后台形成的(实际不存在的PDF),另一个是磁盘保存的PDF文件(这个PDF文件后期会变成从云端获取)。
作为一个Java菜鸟,这个问题解决了数天,还是在leader的指导下解决的。在这里做一下关键代码的记录。
项目主要包含了以下关键词:(我不做详解了,主要是用了这些)
- Spring MVC、Spring、Hibernate
- Maven
- Java
- itextpdf
- MySQL
- JavaWeb相关
首先是itextpdf的依赖
<dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.10</version> </dependency>
如何在后台生成一个PDF
这个问题,百度上有很多解决方案,因为我需要将这个生成的PDF和已存在的PDF拼接,于是尝试了多种方案,决定将这个以文档的形式,将这个文档转为字节数组,然后用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();//创建一个document对象 PdfWriter writer = PdfWriter.getInstance(doc, ba);//这个PdfWriter会一直往文档里写内容。 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); //设置每列宽度比例 int width21[] = {2,98}; table25.setWidths(width21); table25.getDefaultCell().setBorder(0); PdfPCell cell25 = new PdfPCell(new Paragraph("这是一个报告",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); //设置table的宽度为100% table8.setWidthPercentage(100); //设置不同列的宽度 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("地区",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();//(有开启文档,就要记得关闭文档) writer.close(); byte[] bytes = ba.toByteArray(); return bytes; } }
用document来编辑文档,真的蛮恶心的,费时费力,排版也不好调,如果能有更加好用的方式,希望大家能告诉我。
到这里,调用这个方法,就可以获得这个文档的字节数组了。
接下来开始拼接PDF。因为是结合前端页面实现的。因此这个方法是我在controller完成的。
//注意这里的produces,“application/pdf”,正是因为设置了这个,使得整个方法会将文档以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里的用户信息(可以用别的对象来替代这个) if(user==null){ return ; } PdfReader reader1 =null; try { // 调用刚刚写的生成PDF的方法,将这个字节数组获取。 byte[] pdfUserByte=ReportKit.createReport(user); if(pdfUserByte==null||pdfUserByte.length==0){ return; } //用pdfReader来读取字节数组,这里将文档信息读入 reader1 = new PdfReader(pdfUserByte); } catch (Exception e) { System.out.println(e.getMessage()); return ; } if(reader1==null) return; //第二个PDF的读取 PdfReader reader2; // 报告的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();//创建新的一页 pageOfCurrentReaderPDF++; PdfImportedPage page = writer.getImportedPage(pdfReader, pageOfCurrentReaderPDF); cb.addTemplate(page, 0, 0); } pageOfCurrentReaderPDF = 0; } document.close(); writer.close(); } catch (IOException | DocumentException e) { e.printStackTrace(); } }
关于如何在页面预览这个PDF,我用了object标签来获取。
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>
标签很好的实现了PDF预览的功能,如果是URL的PDF,data直接输入URL,就能将PDF在页面预览,感觉蛮好用的。
iText 合并PDF文件报错
在使用iText操作PDF进行合并的时候报错:
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; }
对reader使用上述方法即可解决该问题。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持猪先飞。
相关文章
java 画pdf用itext调整表格宽度、自定义各个列宽的方法
这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31Vue初始化中的选项合并之initInternalComponent详解
这篇文章主要介绍了Vue初始化中的选项合并之initInternalComponent的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-06-11- 这篇文章主要介绍了浅谈实现在线预览PDF的几种解决办法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-10
- 这篇文章主要介绍了java 用itext设置pdf纸张大小操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31
- 这篇文章主要介绍了vue中使用vue-pdf的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-09-05
- 下面小编就为大家分享一篇Qt 使用Poppler实现pdf阅读器的示例代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-04-25
- 这篇文章主要介绍了JavaScript数组合并案例讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-08-16
- 这篇文章主要为大家详细介绍了C#合并及拆分PDF文件的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
C#将Word转换成PDF方法汇总(基于Office和WPS)
这篇文章主要汇总了C#将Word转换成PDF方法,基于Office和WPS的两种解决方案,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25- 这篇文章主要介绍了C#实现的pdf生成图片文字水印类,结合完整实例形式分析了C#针对pdf文件的创建、添加文字、水印等相关操作技巧,需要的朋友可以参考下...2020-06-25
- 这篇文章主要介绍了ES2020系列之空值合并运算符 '??',文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-07-22
- 这篇文章主要介绍了C#获取指定PDF文件页数的方法,涉及C#操作pdf文件的技巧,非常具有实用价值,需要的朋友可以参考下...2020-06-25
- 这篇文章主要为大家详细介绍了C#合并多种格式文件为PDF的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
- 这篇文章主要介绍了C#实现简单合并word文档的方法,涉及C#针对word文档的读取、插入、保存等技巧,非常具有实用价值,需要的朋友可以参考下...2020-06-25
- 今天小编就为大家分享一篇关于C#实现Word转为PDF的方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...2020-06-25
- 这篇文章主要介绍了python操作mysql、excel、pdf的示例,帮助大家更好的理解和学习使用python,感兴趣的朋友可以了解下...2021-03-29
- 本文主要介绍了Java读取PDF中的表格的方法示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-10-22
- 今天小编就为大家分享一篇Python-numpy实现灰度图像的分块和合并方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-04-27
- 这篇文章主要介绍了C# PDF Page操作设置页面切换按钮的方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 这篇文章主要介绍了C#将jpg转换为pdf的方法,主要通过itextsharp.dll文件实现,是非常实用的技巧,需要的朋友可以参考下...2020-06-25