使⽤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;
del.User;
import BaseColor;
import Document;
import DocumentException;
import Element;
import Font;
ssm框架实现登录功能import Paragraph;
import pdf.BaseFont;
import pdf.PdfContentByte;
import pdf.PdfPCell;
import pdf.PdfPTable;
import pdf.PdfReader;
import pdf.PdfWriter;
import 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 = Instance(doc, ba);//这个PdfWriter会⼀直往⽂档⾥写内容。
doc.open();//开启⽂档
BaseFont bfChinese = ateFont("c://windows//fonts//msyh.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
Font FontChinese18 = new Font(bfChinese, 18, Font.BOLD);
Font FontChinese12 = new Font(bfChinese, 12, Font.NORMAL);
Font FontChinese11 = new Font(bfChinese, 11, 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);
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 Accessname(),FontChinese12));
PdfPCell cell8 = new PdfPCell(new Birthday(),FontChinese12));
PdfPCell cell9 = new PdfPCell(new Paragraph(sex,FontChinese12));
PdfPCell cell10 = new PdfPCell(new Paragraph(String.Height()),FontChinese12));
PdfPCell cell11 = new PdfPCell(new Paragraph(String.Weight()),FontChinese12));
PdfPCell cell12 = new PdfPCell(new Area_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) Attribute("user");
//这是⽤户登录后保存到session⾥的⽤户信息(可以⽤别的对象来替代这个)
if(user==null){
return ;
}
PdfReader reader1 =null;
try {
// 调⽤刚刚写的⽣成PDF的⽅法,将这个字节数组获取。
byte[] ateReport(user);
if(pdfUserByte==null||pdfUserByte.length==0){
return;
}
//⽤pdfReader来读取字节数组,这⾥将⽂档信息读⼊
reader1 = new PdfReader(pdfUserByte);
} catch (Exception e) {
System.out.Message());
return ;
}
if(reader1==null) return;
//第⼆个PDF的读取
PdfReader reader2;
// 报告的PDF
reader2 = new PdfReader("C:\\Users\\Administrator\\Desktop\\report.pdf");
Document document = new Document();
PdfWriter writer = Instance(document, OutputStream());
document.open();
PdfContentByte cb = DirectContent();
int totalPages = 0;
totalPages += NumberOfPages();
totalPages += NumberOfPages();
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 = ();
// Create a new page in the target for each source page.
while (pageOfCurrentReaderPDF < NumberOfPages()) {
pageOfCurrentReaderPDF++;
PdfImportedPage page = ImportedPage(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="localhost:8080/project/newPdf/${port_name}" id="review" > </object>
</div>
标签很好的实现了PDF预览的功能,如果是URL的PDF,data直接输⼊URL,就能将PDF在页⾯预览,感觉蛮好⽤的。
iText 合并PDF⽂件报错
在使⽤iText操作PDF进⾏合并的时候报错:
xceptions.BadPasswordException: PdfReader not opened with owner password
public static PdfReader unlockPdf(PdfReader pdfReader) {
if (pdfReader == null) {
return pdfReader;
}
try {
flect.Field f = Class().getDeclaredField("encrypted");
f.setAccessible(true);
f.set(pdfReader, false);
} catch (Exception e) {
// ignore
}
return pdfReader;
}
对reader使⽤上述⽅法即可解决该问题。
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论