java整合itext pdf实现自定义PDF文件格式导出方式

 更新时间:2025年07月09日 17:20:40   作者:一头生产的驴  
Spring Boot整合iTextPDF实现自定义PDF导出,按周次和星期显示打卡记录打勾,需定义数据VO、表格结构,确保所有单元格填充(含空值),测试接口生成格式正确的PDF文件

背景需求

使用PDF导出指定人员对应周次的打卡记录,每周对应星期几打卡过就打“√”。

如下图:

1、导入依赖

导入itextpdf依赖

<!--       itex PDF -->
<dependency>
  <groupId>com.itextpdf</groupId>
  <artifactId>itextpdf</artifactId>
  <version>5.5.13.3</version>
</dependency>

2、使用代码自定义导出

2.1 定义pdf数据vo对象

    // vo对象
    @Data
	class DataVo {
		/**
		 * 周次
		 */
		private String week;

		/**
		 * 打卡次数
		 */
		private int count;

		/**
		 * 周几
		 */
		private List<Integer> days;
	}

2.2 itextpdf相关代码

定义表格的列数,同时定义每列的大小或者格式,然后再依次填充每个单元格数据

注意:需要保证填充每个单元格,即使没数据也要填充空的数据,否则出现文件格式不对

    // itext pdf文件构建
	@PostMapping("/pdfExport")
	public void exportPdf(HttpServletResponse response, MyAttendanceStatisticsDto dto) {
		// 封装好的业务数据
		List<DataVo> vos = new ArrayList<>();
		for (int i = 1; i <= 5; i++) {
			DataVo vo = new DataVo();
			vo.setWeek("第"+i+"周");
			vo.setCount(3);
			vo.setDays(CollUtil.newArrayList(i,6,7));
			vos.add(vo);
		}
        
		if(CollUtil.isNotEmpty(vos)) {
			Rectangle pageSize = PageSize.A4.rotate();
			Document document = new Document(pageSize);

			try {
				String title = "文件名"+ RandomUtil.randomString(5);
				String fileName = URLEncoder.encode("文件名"+ RandomUtil.randomString(5), "UTF-8");

				// 设置响应文件类型PDF
				response.setContentType("application/pdf");
				response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".pdf");

				// 创建 PdfWriter 实例,将 PDF 内容写入 HTTP 响应流,1.7版本
				PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());
				writer.setPdfVersion(PdfWriter.PDF_VERSION_1_7);
				document.open();

				// 中文字体
				BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
				Font font = new Font(baseFont, 12);

				// 添加文档标题,居中,间距20,添加到文档中
				Paragraph pdfTitle = new Paragraph(title, font);
				pdfTitle.setAlignment(Element.ALIGN_CENTER);
				pdfTitle.setSpacingAfter(20f);
				document.add(pdfTitle);

				// 9 列的表格,宽度占满整个页面
				PdfPTable table = new PdfPTable(9);
				table.setWidthPercentage(100);

				// 单独设置前两2宽度
				float[] columnWidths = new float[9];
				columnWidths[0] = 3f;
				columnWidths[1] = 2f;
				for (int i = 2; i < 9; i++) {
					columnWidths[i] = 1f;
				}
				table.setTotalWidth(columnWidths);

				// 添加带斜线的单元格
				PdfPCell splitCell = new PdfPCell();
				// 绑定斜线事件
				splitCell.setCellEvent(new DiagonalLineEvent());
				// 设置单元格高度
				splitCell.setFixedHeight(30f);

				Paragraph day = new Paragraph("日", font);
				day.setAlignment(Element.ALIGN_RIGHT);
				splitCell.addElement(day);

				Paragraph month = new Paragraph("周", font);
				month.setAlignment(Element.ALIGN_LEFT);
				month.setSpacingBefore(-15f);
				splitCell.addElement(month);

				table.addCell(splitCell);
				// 添加第二列表头“周打卡数”
				PdfPCell cell2 = new PdfPCell(new Phrase("周打卡数", font));
				cell2.setHorizontalAlignment(Element.ALIGN_CENTER);
				cell2.setVerticalAlignment(Element.ALIGN_MIDDLE);
				table.addCell(cell2);

				for (int i = 1; i <= 7; i++) {
					PdfPCell cell = new PdfPCell(new Phrase(String.valueOf(i), font));
					cell.setHorizontalAlignment(Element.ALIGN_CENTER);
					cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
					table.addCell(cell);
				}

				for (DataVo vo : vos) {
					PdfPCell monthCell = new PdfPCell(new Phrase(vo.getWeek(), font));
					monthCell.setFixedHeight(20f);
					monthCell.setHorizontalAlignment(Element.ALIGN_CENTER);
					monthCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
					table.addCell(monthCell);

					PdfPCell totalCell = new PdfPCell(new Phrase(String.valueOf(vo.getCount()), font));
					totalCell.setHorizontalAlignment(Element.ALIGN_CENTER);
					totalCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
					table.addCell(totalCell);

					List<Integer> days = vo.getDays();
					for (int i = 1; i <= 7; i++) {
						PdfPCell cell = null;
						if (days.contains(i)) {
							cell = new PdfPCell(new Phrase("√", font));
						} else {
							cell = new PdfPCell(new Phrase("", font));
						}
						cell.setHorizontalAlignment(Element.ALIGN_CENTER);
						cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
						table.addCell(cell);
					}
				}
				document.add(table);
			} catch (Exception e) {
				log.error("导出pdf文件"+e);
			} finally {
				if (document.isOpen()) {
					document.close();
				}
			}
		}
	}

3、测试结果

调用接口测试,响应pdf文件打开如下:

总结

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

相关文章

  • SpringBoot实现抽奖算法的示例代码

    SpringBoot实现抽奖算法的示例代码

    这篇文章主要为大家详细介绍了如何通过SpringBoot实现抽奖算法,文中的示例代码简洁易懂,具有一定的参考价值,感兴趣的小伙伴可以了解一下
    2023-06-06
  • windows上部署Javaweb项目完整图文教程

    windows上部署Javaweb项目完整图文教程

    这篇文章主要介绍了windows上部署Javaweb项目的相关资料,通过图文详细讲解了配置项目参数、替换Eclipse相关设置、部署war包、调整server.xml配置及端口,最后通过Tomcat启动项目并访问,需要的朋友可以参考下
    2025-06-06
  • response.setContentType()参数以及作用详解

    response.setContentType()参数以及作用详解

    这篇文章主要介绍了response.setContentType()参数以及作用详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Java实现有限状态机的推荐方案分享

    Java实现有限状态机的推荐方案分享

    有限状态机又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型,这篇文章主要给大家介绍了关于Java实现有限状态机的推荐方案,需要的朋友可以参考下
    2021-11-11
  • Java线程阻塞工具LockSupport用法详解

    Java线程阻塞工具LockSupport用法详解

    Java中的LockSupport是一个用于线程同步的工具类,它提供了一种基于线程的阻塞和唤醒机制,LockSupport可以让线程在特定条件下阻塞挂起,等待其他线程发送信号来唤醒它,本文将通过一个小案例给大家介绍一下LockSupport怎么用,让你永远记住它
    2023-08-08
  • SpringBoot中实现接收文件和对象

    SpringBoot中实现接收文件和对象

    这篇文章主要介绍了SpringBoot实现接收文件和对象,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • Spring Boot(五)之跨域、自定义查询及分页

    Spring Boot(五)之跨域、自定义查询及分页

    这篇文章主要介绍了Spring Boot(五)之跨域、自定义查询及分页的的相关资料,需要的朋友可以参考下
    2017-04-04
  • 如何用java编写一个rmi

    如何用java编写一个rmi

    RMI能让一个Java程序去调用网络中另一台计算机的Java对象的方法,那么调用的效果就像是在本机上调用一样。下面我们来详细了解一下吧
    2019-06-06
  • SpringBoot发送短信验证码的实例

    SpringBoot发送短信验证码的实例

    第三方短信发送平台有很多种,各个平台有各自的优缺点,在选择的时候可以根据自己的具体实际情况定夺,本文主要介绍了SpringBoot发送短信验证码的实例,感兴趣的可以了解一下
    2022-02-02
  • spring boot 测试单元修改数据库不成功的解决

    spring boot 测试单元修改数据库不成功的解决

    这篇文章主要介绍了spring boot 测试单元修改数据库不成功的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09

最新评论