根本原因是itext7默认字体不支持中文,需注册simhei.ttf等中文字体并显式使用;表格列宽需用百分比分配并启用换行;pdf输出前须设响应头、避免流重复写入;大数据量时应分批flush并复用对象。

用 iText7 导出 PDF 报表时中文显示为空白或方块
根本原因是默认字体不支持中文。iText7 不自带中文字体,Document 用的 PdfFontFactory.createStandardFont() 只能渲染 ASCII 字符。
- 必须显式注册并使用支持 GBK 或 UTF-8 的中文字体(如
simhei.ttf、NotoSansCJKsc-Regular.otf) - 推荐用
PdfFontFactory.register()注册字体路径,再通过PdfFontFactory.createFont()获取实例 - 别把字体文件硬编码成绝对路径;放在
src/main/resources/fonts/下,用getClass().getResourceAsStream("/fonts/simhei.ttf")加载更可靠 - 如果导出后中文变成“□□”,说明字体加载失败——检查路径是否拼错、流是否为 null、字体文件是否损坏
用 Table 构建员工列表时列宽错乱或内容被截断
iText7 的 Table 默认按内容自动撑开列宽,但实际报表常需固定列宽+文本换行,否则表格会溢出页面或挤压其他列。
- 创建
Table时传入带百分比的构造函数,比如new Table(UnitValue.createPercentArray(new float[]{2, 3, 2, 2})),让各列按比例分配宽度 - 对每列单元格调用
setPadding(2f)和setMinHeight(20f),避免文字贴边或行高塌陷 - 长文本(如部门描述)必须手动启用换行:
cell.setWordBreak(true),否则超出列宽直接被裁掉 - 别用
cell.add(new Paragraph("xxx"))直接塞段落——先设好Paragraph.setFont()和Paragraph.setFontSize(),否则继承默认字体导致中文失效
生成 PDF 后打开报错 “Failed to load document” 或空白页
常见于输出流未关闭、响应头未设对、或 PDF 内容写入前已提交响应。
- 确保
PdfWriter对应的OutputStream是从HttpServletResponse.getOutputStream()拿到的,并且在document.close()后才调用response.getOutputStream().flush() -
response.setContentType("application/pdf")和response.setHeader("Content-Disposition", "attachment; filename=employee-report.pdf")必须在任何输出之前设置 - 如果用了 Spring MVC,别在 Controller 方法里 return
ResponseEntity<byte></byte>同时又手动 write 流——二选一,否则会写两次导致 PDF 头损坏 - 本地调试时,先用
Files.write(Paths.get("test.pdf"), outputStream.toByteArray())把字节存成文件,确认能正常打开再接入 Web 流程
导出大量员工数据时内存溢出或速度极慢
iText7 默认把整个文档结构缓存在内存中,1000 行以上就容易 OOM,尤其每行都建 Paragraph + Cell + 字体对象时。
立即学习“Java免费学习笔记(深入)”;
- 用
document.setRenderer(new DocumentRenderer(document))替换默认渲染器没用;真正有效的是开启分页缓冲:document.setImmediateFlush(false),再配合document.flush()手动清空中间状态 - 避免在循环里反复 new
Paragraph和Cell——复用对象,或用字符串拼接后统一构建(但要注意换行和字体一致性) - 超过 500 条建议分批次:每 100 行调一次
document.add(table)+document.flush(),而不是攒一个超大Table - 别用
Image.getInstance()往每行加小图标——PDF 中图片是重量级对象,换成 Unicode 符号(如"✓")或 Base64 内联 SVG 更轻量










