使用 iText
导出 pdf 表格
iText
是一种生成 PDF 报表的 Java 组件,先把 jar 包下下来,maven 依赖如下:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.0.6</version>
</dependency>
1. Hello World
接下来咱们就来搞一个 PDF 入门案例吧。
新建一个 SpringBoot 项目:
导入 POM 依赖
Controller:
@RestController
@RequestMapping("/pdf")
public class PdfContoller {
@Autowired
private PdfService pdfService;
// 导出pdf
@PostMapping("/exportPdf")
public void exportPdf() {
pdfService.exportPdf();
}
}
Service:
public interface PdfService {
void exportPdf();
}
ServiceImpl:
@Service
@Slf4j
public class PdfServiceImpl implements PdfService {
@Override
public void exportPdf() {
log.info("进入到方法exportPdf()");
String fileName = "test.pdf";
try {
PdfUtil.createPdf(fileName);
} catch (DocumentException e) {
log.error("【DocumentException】报错信息为{}", e.getMessage());
} catch (FileNotFoundException e) {
log.error("【FileNotFoundException】报错信息为{}", e.getMessage());
}
log.info("生成pdf文件完毕");
}
}
util:
public class PdfUtil {
// 生成pdf
public static void createPdf(String fileName) throws DocumentException, FileNotFoundException {
// 1.创建一个文档实例 设置文档纸张为A4
Document document = new Document(PageSize.A4);
// 2.创建PdfWriter对象,设置pdf生成路径
PdfWriter.getInstance(document, new FileOutputStream(fileName));
// 3.打开文档进行我们需要的操作
document.open();
document.add(new Paragraph("Hello World"));
// 4.关闭文档
document.close();
}
}
调用接口:
http://localhost:8080/pdf/exportPdf
会在当前工程下面生成一个 test.pdf
文件:
好了,iText
入门就到这了。
2. 生成一个表格的 PDF 文件
在工作中,用到比较多的就是导出 PDF 表格了,这里要用到一个很关键的类com.itextpdf.text.pdf.PDFPTable
。
生成一个如下的表格:
这是一个 2 列 5 行的表格。其中,单元格 five 占据 2 列;单元格 six 占据 两行。好了,接下来看看如何实现吧。
PdfServiceImpl:
@Override
public void exportPdf2() {
String fileName = "test2.pdf";
try {
// 重点方法
PdfUtil.createPdf2(fileName);
} catch (DocumentException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
PdfUtil:
package com.zzc.hardcore.util;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/**
* @author zzc
* @description:PDF工具类
* @create 2021-11-07 16:10
*/
public class PdfUtil {
// 字体路径
public static String fontPath = "C:/Users/zzc/Desktop/msyh.ttc,0";
// 字体
public static BaseFont baseFont = null;
static {
try {
baseFont = BaseFont.createFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
} catch (Exception e) {
e.printStackTrace();
}
}
// 生成pdf文件
public static void createPdf2(String fileName) throws DocumentException, FileNotFoundException {
// 1.创建一个文档实例 设置文档纸张为A4
Document document = new Document(PageSize.A4);
// 2.创建PdfWriter对象,设置pdf生成路径
PdfWriter instance = PdfWriter.getInstance(document, new FileOutputStream(fileName));
// 3.打开文档进行我们需要的操作
document.open();
Paragraph title = new Paragraph("Hello World");
Font font = new Font(baseFont, 8);
title.setFont(font);
title.setAlignment(Element.ALIGN_CENTER);
document.add(title);
// 4.获取表格信息
PdfPTable table = createTable();
document.add(table);
// 5.关闭文档
document.close();
}
// 获取表格信息
public static PdfPTable createTable() throws DocumentException{
// 1.生成表格
PdfPTable table = doCreateTable();
// 2.生成单元格
PdfPCell cell11 = createSpecialCell("one");
table.addCell(cell11);
PdfPCell cell12 = createCell("two");
// 不要边框
cell12.setBorder(0);
table.addCell(cell12);
PdfPCell cell21 = createCell("three");
cell21.setHorizontalAlignment(Element.ALIGN_CENTER);
cell21.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell21);
PdfPCell cell22 = createCell("four");
table.addCell(cell22);
PdfPCell cell3 = createCell("five");
cell3.setColspan(2);
table.addCell(cell3);
PdfPCell cell41 = createCell("six");
cell41.setMinimumHeight(2 * 20);
cell41.setRowspan(2);
table.addCell(cell41);
PdfPCell cell42 = createCell("seven");
table.addCell(cell42);
PdfPCell cell43 = createCell("eight");
table.addCell(cell43);
return table;
}
// 生成表格
public static PdfPTable doCreateTable() throws DocumentException {
// 列数
int columns = 2;
// 1.生成一个两列的表格
PdfPTable table = new PdfPTable(columns);
// 表格占比100%
table.setWidthPercentage(100);
table.setSpacingBefore(20f);
table.setSpacingAfter(20f);
// 2.每一个列宽
float[] columnWidths = {2f, 5f};
table.setWidths(columnWidths);
return table;
}
// 生成单元格
public static PdfPCell createCell(String cellContent) {
Phrase phrase = new Phrase(cellContent);
phrase.setFont(new Font(baseFont, 5));
PdfPCell cell = new PdfPCell(phrase);
return cell;
}
// 生成一个有特性的单元格
public static PdfPCell createSpecialCell(String cellContent) {
PdfPCell cell = createCell(cellContent);
// 边框:蓝色
cell.setBorderColor(BaseColor.BLUE);
// 内边距:10
cell.setPaddingLeft(10);
// 水平居中
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
return cell;
}
}
说明:
- 要想显示中文字体,必须引入字体文件,我这里免费提供一个 pdf字体下载
- PDF 中的 API 使用:Document、PdfPTable、PdfPCell
Document
Document document = new Document(PageSize.A4);
PdfWriter instance = PdfWriter.getInstance(document, new FileOutputStream(fileName));
document.open();
// document.add()
document.close();
pdf 文件中需要什么内容,直接调用 document.add()
进行添加
PdfPTable
table.setWidthPercentage(100);
table.setSpacingBefore(20f);
table.setSpacingAfter(20f);
// 每一个列宽
table.setWidths(columnWidths);
表格中添加单元格,必须得调用:table.addCell();
PdfPCell
// 添加边框颜色
cell.setBorderColor(BaseColor.BLUE);
// 不要边框
cell12.setBorder(0);
// 单元格内边距
cell.setPaddingLeft(10);
// 单元格内容水平居中
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
// 单元格内容垂直居中
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
// 设置最小高度
cell.setMinimumHeight();
// 合并列
cell.setColspan(2);
// 合并行
cell.setRowspan(2);
【注意】:每一行的长度要和初始化表格的长度相等,即要把整行给占满,否则后面的都不会打印出来
如上图,大致意思是:如果你是一个 5 * 2 的单元格,并且,每一个单元格默认宽度为 1,那么,每一行的单元格必须要有 2 个,这样,才会默认切换到下一行去。
3. 下载生成的 PDF 文件
前面的东西都是放到 java 项目中去跑的,没有太多实际用处,在 web 项目中用到才算真正的应用。接下来咱们就通过浏览器去下载生成的 pdf 文件。
咱们下载前面生成的 pdf 文件:
PdfContoller:
@PostMapping("/exportPdf2")
public void exportPdf2(HttpServletResponse response) {
pdfService.exportPdf2(response);
}
PdfServiceImpl:
@Override
public void exportPdf2(HttpServletResponse response) {
String fileName = "test2.pdf";
try {
// 1.生成pdf文件
PdfUtil.createPdf2(fileName);
// 2.下载pdf文件
downLoadFile(fileName, response);
// 3.删除临时生成的pdf文件
deleteFile(new File(fileName));
} catch (DocumentException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
下载 pdf 文件:
public boolean downLoadFile(String fileName, HttpServletResponse response) {
boolean flag = false;
log.info("【下载文件】文件名为:{}", fileName);
File file = new File(fileName);
if (!file.exists()) {
log.error("【下载文件】文件{}不存在", fileName);
return flag;
}
// 法一:
/*try(InputStream in = new BufferedInputStream(new FileInputStream(fileName))){
byte[] buffer = new byte[in.available()];
int length = 0;
while ((length = in.read(buffer)) > 0) {
response.reset();
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
response.addHeader("Content-Length", "" + file.length());
response.setContentType("application/pdf");
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
toClient.write(buffer);
toClient.flush();
toClient.close();
}
flag = true;*/
// 法二:
try {
InputStream in = new FileInputStream(fileName);
OutputStream outputStream = response.getOutputStream();
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
response.addHeader("Content-Length", "" + file.length());
response.setContentType("application/pdf");
IOUtils.copy(in, outputStream);
flag = true;
in.close();
outputStream.close();
} catch (Exception e) {
log.error("【下载文件】下载文件失败,失败信息为{}", e.getMessage());
return flag;
}
return flag;
}
删除临时生成的pdf文件:
// 递归删除目录下的所有文件及子目录下所有文件
public static boolean deleteFile(File file) {
if (!file.exists()) {
return false;
}
if (file.isDirectory()) {
String[] children = file.list();
//递归删除目录中的子目录下
for (int i=0; i<children.length; i++) {
boolean success = deleteFile(new File(file, children[i]));
if (!success) {
return false;
}
}
}
// 目录此时为空,可以删除
return file.delete();
}