You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache POI生成docx转PDF遇SAXParseException等错误求助

解决Apache POI生成Docx转PDF的样式缺失问题

问题场景

使用以下依赖:

  • org.apache.poi:poi-ooxml:5.2.3
  • fr.opensages.xdocreport:org.apache.poi.xwpf.converter.pdf:1.0.6

通过Apache POI创建空白Docx并写入内容后,调用PDF转换器时触发样式相关错误。原始代码如下:

@GetMapping("pdf")
fun getPdf(aResponse: HttpServletResponse) {

   val myDoc = XWPFDocument ()
   val myParagraph = myDoc.createParagraph ()
   val myRun = myParagraph.createRun ()
   myRun.setText ("Hello, world!")

   val myPdfOptions = PdfOptions.create ()

   aResponse.contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE
   aResponse.addHeader ("Content-disposition", "attachment; filename=\"hello-world.pdf\"")

   aResponse.outputStream.use {
      PdfConverter.getInstance ().convert (myDoc, it, myPdfOptions)
   }
}

首次错误信息

java.lang.IllegalStateException: Expecting one Styles document part, but found 0
   at org.apache.poi.xwpf.usermodel.XWPFDocument.getStyle(XWPFDocument.java:587)
   at org.apache.poi.xwpf.converter.core.styles.XWPFStylesDocument.<init>(XWPFStylesDocument.java:190)
   at org.apache.poi.xwpf.converter.core.styles.XWPFStylesDocument.<init>(XWPFStylesDocument.java:184)
   at org.apache.poi.xwpf.converter.core.XWPFDocumentVisitor.createStylesDocument(XWPFDocumentVisitor.java:166)
   at org.apache.poi.xwpf.converter.core.XWPFDocumentVisitor.<init>(XWPFDocumentVisitor.java:159)
   at org.apache.poi.xwpf.converter.pdf.internal.PdfMapper.<init>(PdfMapper.java:149)
   at org.apache.poi.xwpf.converter.pdf.PdfConverter.doConvert(PdfConverter.java:55)
   at org.apache.poi.xwpf.converter.pdf.PdfConverter.doConvert(PdfConverter.java:38)
   at org.apache.poi.xwpf.converter.core.AbstractXWPFConverter.convert(AbstractXWPFConverter.java:45)

尝试调用myDoc.createStyles()添加空样式后,出现新错误:

org.xml.sax.SAXParseException: Premature end of file.
   at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
   at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:178)
   at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400)
   at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327)
   at java.xml/com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1471)
   at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:1013)
   at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
   at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
   at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:534)
   at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:888)
   at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
   at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
   at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1216)
   at java.xml/com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:635)
   at org.apache.xmlbeans.impl.store.Locale$SaxLoader.load(Locale.java:2532)
   at org.apache.xmlbeans.impl.store.Locale.lambda$parseToXmlObject$3(Locale.java:717)
   at org.apache.xmlbeans.impl.store.Locale.syncWrap(Locale.java:490)
   at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:716)
   at org.apache.xmlbeans.impl.schema.SchemaTypeLoaderBase.parse(SchemaTypeLoaderBase.java:233)
   at org.apache.xmlbeans.impl.schema.AbstractDocumentFactory.parse(AbstractDocumentFactory.java:71)
   at org.apache.poi.xwpf.usermodel.XWPFDocument.getStyle(XWPFDocument.java:591)
... continues same as above error

解决方案

直接创建的XWPFDocument不包含Word默认的样式结构(styles.xml),而xdocreport的PDF转换器依赖完整的样式定义。最简便可靠的解决方式是基于包含默认样式的空白Docx模板来创建文档:

  1. 准备一个空白的Word文档(通过Microsoft Word或WPS创建,确保包含默认样式),保存为blank-template.docx,放入项目的resources目录。
  2. 修改代码,从模板加载文档而非创建全新的空白文档:
@GetMapping("pdf")
fun getPdf(aResponse: HttpServletResponse) {
    // 从资源目录加载带默认样式的空白模板
    val templateStream = this::class.java.classLoader.getResourceAsStream("blank-template.docx")
        ?: throw IllegalArgumentException("空白模板文件不存在")
    
    // 使用use自动关闭流和文档资源
    XWPFDocument(templateStream).use { myDoc ->
        val myParagraph = myDoc.createParagraph()
        val myRun = myParagraph.createRun()
        myRun.setText("Hello, world!")

        val myPdfOptions = PdfOptions.create()

        aResponse.contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE
        aResponse.addHeader("Content-disposition", "attachment; filename=\"hello-world.pdf\"")

        aResponse.outputStream.use {
            PdfConverter.getInstance().convert(myDoc, it, myPdfOptions)
        }
    }
}

原理说明

手动创建的XWPFDocument仅包含最基础的文档结构,缺少Word默认的样式集合。而通过模板加载的文档自带完整的styles.xml部分,能满足PDF转换器对样式结构的要求,避免触发样式缺失相关的异常。

内容的提问来源于stack exchange,提问作者Jesser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 10:15:13