使用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使用上述方法即可解决该问题。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
推荐阅读
-
解决jQuery使用append添加的元素事件无效的问题
-
使用CAD最常遇到的11种问题 如怎么一次剪除多条线段等的解决办法
-
Mysql5.7中使用group concat函数数据被截断的问题完美解决方法
-
使用Python的SymPy库解决数学运算问题的方法
-
解决使用PyCharm时无法启动控制台的问题
-
倒计时cocos定时器schude使用的过程中 帧率浮动较大导致执行时机不准确的问题解决
-
Three.js使用THREE.TextGeometry创建三维文本中文乱码的问题如何解决?
-
解决在Bootstrap模糊框中使用WebUploader的问题
-
解决v-for中使用v-if或者v-bind:class失效的问题
-
解决pandas使用read_csv()读取文件遇到的问题