使用 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;
    }

}

说明:

  1. 要想显示中文字体,必须引入字体文件,我这里免费提供一个 pdf字体下载
  2. 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();
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐