使用XDOCReport转换DOCX到PDF时页眉页脚未被转换的问题
解决XDOCReport转换DOCX到PDF丢失页眉页脚的问题
嘿,我之前也踩过XDOCReport转换PDF时丢失页眉页脚的坑!默认的PdfConverter并不会自动处理DOCX里的页眉页脚内容,得咱们手动配置页事件来搞定它。
问题原因
XDOCReport的PDF转换底层依赖iText,但默认配置没有启用页眉页脚的解析逻辑,所以转换时只会处理正文,页眉页脚区域就变成空白了。
解决方案:自定义页眉页脚处理逻辑
我们需要写一个自定义的PdfPageEventHelper子类,用来拦截PDF生成的页面事件,把DOCX里的页眉页脚内容绘制到PDF对应的位置。
第一步:创建自定义页事件类
这个类负责读取DOCX的页眉页脚,并在PDF生成时绘制它们:
import com.lowagie.text.Document; import com.lowagie.text.Phrase; import com.lowagie.text.pdf.PdfPTable; import com.lowagie.text.pdf.PdfPageEventHelper; import com.lowagie.text.pdf.PdfWriter; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFHeader; import org.apache.poi.xwpf.usermodel.XWPFFooter; class HeaderFooterPageEvent extends PdfPageEventHelper { private final XWPFDocument docxDocument; public HeaderFooterPageEvent(XWPFDocument docxDocument) { this.docxDocument = docxDocument; } // 处理页眉:在每页开始时绘制 @Override public void onStartPage(PdfWriter writer, Document pdfDoc) { try { // 获取DOCX里的第一个页眉(如果有多个节,需要循环处理所有页眉) if (!docxDocument.getHeaderList().isEmpty()) { XWPFHeader header = docxDocument.getHeaderList().get(0); PdfPTable headerTable = new PdfPTable(1); headerTable.setWidthPercentage(100); // 这里简化处理,直接取页眉文本;如果有复杂格式,需要遍历段落/表格/图片逐个转换 headerTable.addCell(new Phrase(header.getText())); // 把页眉绘制到PDF页面顶部 headerTable.writeSelectedRows(0, -1, pdfDoc.left(), pdfDoc.top() + 20, writer.getDirectContent()); } } catch (Exception e) { e.printStackTrace(); } } // 处理页脚:在每页结束时绘制 @Override public void onEndPage(PdfWriter writer, Document pdfDoc) { // 1. 绘制DOCX里的页脚内容 if (!docxDocument.getFooterList().isEmpty()) { XWPFFooter footer = docxDocument.getFooterList().get(0); PdfPTable footerTable = new PdfPTable(1); footerTable.setWidthPercentage(100); footerTable.addCell(new Phrase(footer.getText())); // 把DOCX页脚绘制到PDF页面底部 footerTable.writeSelectedRows(0, -1, pdfDoc.left(), pdfDoc.bottom() - 30, writer.getDirectContent()); } // 2. 可选:添加页码(如果DOCX里没有页码,或者需要补充) PdfPTable pageNumTable = new PdfPTable(1); pageNumTable.setWidthPercentage(100); pageNumTable.addCell(new Phrase("第 " + writer.getPageNumber() + " 页")); pageNumTable.writeSelectedRows(0, -1, pdfDoc.left(), pdfDoc.bottom() - 15, writer.getDirectContent()); } }
第二步:修改转换代码,启用自定义页事件
把自定义的页事件绑定到PdfOptions里,这样转换时就会自动处理页眉页脚了:
import fr.opensagres.xdocreport.converter.PdfConverter; import fr.opensagres.xdocreport.converter.PdfOptions; import org.apache.poi.xwpf.usermodel.XWPFDocument; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; public class DocxToPdfConverter { public static void main(String[] args) throws Exception { String inputDocxFilePath = "input.docx"; String outputPdfFilePath = "output.pdf"; try (InputStream is = new FileInputStream(new File(inputDocxFilePath)); OutputStream out = new FileOutputStream(new File(outputPdfFilePath))) { XWPFDocument document = new XWPFDocument(is); PdfOptions options = PdfOptions.create(); // 关键:添加自定义页眉页脚事件 options.setPageEvent(new HeaderFooterPageEvent(document)); PdfConverter.getInstance().convert(document, out, options); } } }
额外注意事项
- 如果你的页眉页脚包含复杂格式(比如图片、多列表格、字体样式),上面的简化代码可能不够用,需要遍历XWPFHeader/XWPFFooter里的
XWPFParagraph、XWPFTable等元素,逐个转换为iText对应的组件(比如Paragraph、PdfPTable)。 - 确认DOCX文档的页眉页脚不是仅存在于特定节(比如第一页),如果有多节,需要循环处理
document.getHeaderList()里的所有页眉。 - 确保依赖版本兼容:XDOCReport的版本和iText版本要匹配,比如XDOCReport 2.0.0通常搭配iText 2.1.7或兼容的版本,避免出现类找不到或方法不兼容的问题。
内容的提问来源于stack exchange,提问作者vijaykumar g
相关产品推荐
相关产品推荐

