使用itextpdf解决PDF合并的问题

2022-07-22,,,

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使用上述方法即可解决该问题。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

《使用itextpdf解决PDF合并的问题.doc》

下载本文的Word格式文档,以方便收藏与打印。