0. 核心依賴(lài):
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.10</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
1. 設(shè)置頁(yè)眉圖片及下劃線(xiàn)
通過(guò)PdfPageEventHelper事件可以動(dòng)態(tài)的創(chuàng)建頁(yè)眉,數(shù)據(jù)構(gòu)建出多少頁(yè)pdf就有多少頁(yè)頁(yè)眉文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-561913.html
package com.example.pdf;
import com.example.pdf.vo.RenovationDocNameEnum;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
/**
* 內(nèi)部類(lèi) 添加頁(yè)眉、頁(yè)腳
*/
public class PdfEvent extends PdfPageEventHelper {
// 一頁(yè)加載完成觸發(fā),寫(xiě)入頁(yè)眉和頁(yè)腳
@Override
public void onEndPage(PdfWriter writer, Document document) {
PdfPTable head = new PdfPTable(1);
PdfObject businessType = document.getAccessibleAttribute(new PdfName("businessType"));
PdfObject flag = document.getAccessibleAttribute(new PdfName("flag"));
try {
if (RenovationDocNameEnum.CB.getName().equals(businessType.toString())
|| (RenovationDocNameEnum.SG.getName().equals(businessType.toString()) && flag != null && "1".equals(flag.toString()))) {
setCbPageHead(head, writer, document);
} else if (RenovationDocNameEnum.SG.getName().equals(businessType.toString()) || RenovationDocNameEnum.JC.getName().equals(businessType.toString())) {
setSinglePageHead(head, writer, document);
}
} catch (Exception e) {
throw new ExceptionConverter(e);
}
}
/**
* Chunk的offsetX控制頁(yè)眉圖片水平位置,offsetY會(huì)影響到圖片大??; 圖片上下位置可通過(guò)showTextAligned的y來(lái)控制
* 頁(yè)眉下劃線(xiàn)通過(guò)setTotalWidth控制先長(zhǎng)度,writeSelectedRows的xPos控制線(xiàn)的起始水平位置
*
* @param head
* @param writer
* @param document
* @throws DocumentException
*/
private void setSinglePageHead(PdfPTable head, PdfWriter writer, Document document) throws DocumentException {
Font font = PdfUtil.getFont(null);
// 通過(guò)表格構(gòu)建頁(yè)眉下劃線(xiàn)
head.setTotalWidth(PageSize.A4.getWidth() - 105);
head.setWidths(new int[]{24});
head.setLockedWidth(true);
head.getDefaultCell().setFixedHeight(-10);
head.getDefaultCell().setBorder(Rectangle.BOTTOM);
head.getDefaultCell().setBorderWidth(0.5f);
head.addCell(new Paragraph(" ", font));
// 將頁(yè)眉寫(xiě)到document中,位置可以指定,指定到下面就是頁(yè)腳
head.writeSelectedRows(0, -1, 55, PageSize.A4.getHeight() - 20, writer.getDirectContent());
PdfContentByte directContent = writer.getDirectContent();
// 最重要的是這個(gè),如果頁(yè)眉需要設(shè)置圖片的話(huà),需要在Phrase對(duì)象中添加一個(gè)Chunk對(duì)象,在Chunk對(duì)象中添加圖片信息即可
Phrase phrase = new Phrase("", font);
Image img = PdfUtil.getImg();
if (img != null) {
phrase.add(new Chunk(img, 30, -150));
}
// 寫(xiě)入頁(yè)眉
ColumnText.showTextAligned(directContent, Element.ALIGN_RIGHT, phrase, document.right(), PageSize.A4.getHeight() + 48, 0);
}
- 通過(guò)PdfPTable來(lái)構(gòu)建下劃線(xiàn)
- 通過(guò)new Chunk來(lái)顯示圖片,并通過(guò)ColumnText.showTextAligned來(lái)展示在頁(yè)眉
- 詳細(xì)見(jiàn)setSinglePageHead方法的注釋?zhuān)秸褪且活D調(diào),知道合適位置
2. document參數(shù)傳遞:
- 像下述這樣定義一個(gè)字符串參數(shù)于document,就可以像上述PdfEvent中獲取做業(yè)務(wù)判斷
- 使用的時(shí)候注意toString()
PdfName businessType = new PdfName("businessType");
document.setAccessibleAttribute(businessType, new PdfString(type));
3. 生成的pdf文件轉(zhuǎn)base64編碼:
- 主要以下兩個(gè)方法,FileUtil是hutool的工具類(lèi),Base64是java.util的工具類(lèi)
PdfUtil.getBase64(FileUtil.readBytes(file));
public static String getBase64(byte[] buffer) {
return Base64.getEncoder().encodeToString(buffer);
}
4. 平方2上標(biāo)顯示問(wèn)題:
本人生成pdf時(shí)用的是simkai.ttf字體,輸出的pdf沒(méi)有顯示2上標(biāo)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-561913.html
- 要么可以換字體,百度即可
- 要么像如下這樣,通過(guò)setTextRise來(lái)控制文字位置,來(lái)大概展示成2效果
- 方法正值為上標(biāo),負(fù)值可為下標(biāo),注意上標(biāo)的2的文字specialFont字體要定義小點(diǎn),本人定義5
public static PdfPCell getPDFCellSpecial(String name, Font font, Integer alignment) {
PdfPCell cell = new PdfPCell();
if (name == null) {
name = " ";
}
Paragraph p = new Paragraph(name, font);
Font specialFont = PdfUtil.getSpecialFont(null);
Chunk chunk = new Chunk("2", specialFont);
chunk.setTextRise(5f);
p.add(chunk);
p.add(new Chunk(")", font));
if (alignment == null) {
p.setAlignment(Element.ALIGN_CENTER);
} else {
p.setAlignment(alignment);
}
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.addElement(p);
return cell;
}
5. 壓縮包的文件流InputStream輸出文件:
- 業(yè)務(wù)上從別的接口獲取到一個(gè)zip包的文件流,需要將zip包的文件輸出到目錄,如下代碼:
- 涉及IO流要注意關(guān)流
private static List<String> extractAllByInputStream(InputStream inputStream, String pdfPath) {
ArrayList<String> list = Lists.newArrayList();
try {
dealZipInputStream(inputStream, pdfPath, list);
} catch (IOException e) {
LOGGER.info("下載pdf到本地異常,異常信息:{}", e);
}
return list;
}
private static void dealZipInputStream(InputStream inputStream, String pdfPath, ArrayList<String> list) throws IOException {
byte[] buffer = new byte[1024];
ZipEntry zipEntry;
try (ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
String entryName = zipEntry.getName();
if (!zipEntry.isDirectory()) {
String fileName;
if (entryName.contains(RenovationDocNameEnum.CB.getName())) {
fileName = pdfPath + RenovationDocNameEnum.CB.getName() + ".pdf";
} else if (entryName.contains(RenovationDocNameEnum.JC.getName())) {
fileName = pdfPath + RenovationDocNameEnum.JC.getName() + ".pdf";
} else if (entryName.contains(RenovationDocNameEnum.SG.getName())) {
fileName = pdfPath + RenovationDocNameEnum.SG.getName() + ".pdf";
} else {
fileName = pdfPath + UUID.randomUUID() + ".pdf";
}
list.add(fileName);
File subFile = new File(fileName);
subFile.createNewFile();
readSubFile(subFile, zipInputStream, buffer);
}
zipInputStream.closeEntry();
}
} finally {
IOUtils.closeQuietly(inputStream);
}
}
private static void readSubFile(File subFile, ZipInputStream zipInputStream, byte[] buffer) {
int len;
try (FileOutputStream fileOut = new FileOutputStream(subFile)) {
while ((len = zipInputStream.read(buffer)) > 0) {
fileOut.write(buffer, 0, len);
}
} catch (IOException e) {
throw new ExceptionConverter(e);
}
}
6. itext5進(jìn)行pdf合并:
- 本人文件合并后要?jiǎng)h除之前的文件,這時(shí)需要注意new PdfReader(inputStream)時(shí)使用inputStream
- 不然可能出現(xiàn):別的程序正在使用而無(wú)法刪除情況
/* 合并pdf文件
* @param files 要合并文件數(shù)組(絕對(duì)路勁{ "D:\\a.pdf", "D:\\b.pdf" })
* @param savePath 合并后新產(chǎn)生的文件絕對(duì)路徑如D:\\temp.pdf
*/
public static Integer mergePdfFiles(String[] files, String savePath) {
Document document = null;
PdfCopy copy = null;
try (FileOutputStream outputStream = new FileOutputStream(savePath)) {
// 創(chuàng)建一個(gè)與a.pdf相同紙張大小的document
document = new Document(new PdfReader(files[0]).getPageSize(1));
copy = new PdfCopy(document, outputStream);
document.open();
for (int i = 0; i < files.length; i++) {
// 一個(gè)一個(gè)的遍歷現(xiàn)有的PDF
dealFile(files[i], copy, document);
}
copy.close();
document.close();
return 1;
} catch (IOException | DocumentException e) {
LOGGER.info("合并pdf失敗,異常信息:{}", e);
} finally {
if (document != null) {
document.close();
}
if (copy != null) {
copy.close();
}
}
return 0;
}
private static void dealFile(String file, PdfCopy copy, Document document) {
PdfReader reader = null;
try (FileInputStream inputStream = new FileInputStream(file)) {
reader = new PdfReader(inputStream);
int n = reader.getNumberOfPages();// PDF文件總共頁(yè)數(shù)
for (int j = 1; j <= n; j++) {
document.newPage();
PdfImportedPage page = copy.getImportedPage(reader, j);
copy.addPage(page);
}
reader.close();
} catch (IOException | BadPdfFormatException e) {
throw new ExceptionConverter(e);
} finally {
if (reader != null) {
reader.close();
}
}
}
到了這里,關(guān)于itext5創(chuàng)建pdf表格及遇到的一些問(wèn)題的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!