Apache POI实现HTML转Word时@page CSS样式失效的解决方案咨询
解决Apache POI HTML转Word中@page CSS样式不生效的问题
首先得明确:你当前使用的POIFSFileSystem生成的是旧版的二进制.doc格式,这种方式本质是把HTML作为Word的嵌入式片段处理,但Word的旧格式对CSS的支持极其有限——@page这类页面级的CSS规则完全不在支持范围内,所以你的页码样式根本不会被识别。
下面给你两种可行的解决方向,优先推荐第一种:
方案1:切换到XWPF生成.docx文档(推荐,支持更完善)
Apache POI的XWPF组件是专门处理.docx格式的,对HTML转Word的支持更好,而且可以通过API直接控制页面布局和页码(替代@page的效果)。
步骤1:添加必要依赖(Maven示例)
确保你的项目引入了POI的OOXML相关依赖:
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.5</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-full</artifactId> <version>5.2.5</version> </dependency>
步骤2:修改转换代码
我们先把HTML转成XWPFDocument,再手动实现@page里的页码和边距需求:
import org.apache.poi.xwpf.usermodel.*; import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter; import org.apache.poi.xwpf.converter.xhtml.XHTMLOptions; import org.w3c.dom.Document; import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.*; import java.math.BigInteger; public void convertHtmlToDocx(String html, OutputStream outputStream) throws Exception { // 解析HTML为W3C文档对象 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document w3cDoc = builder.parse(new InputSource(new StringReader(html))); // 将HTML转换为XWPFDocument XWPFDocument xwpfDoc = new XWPFDocument(); XHTMLOptions options = XHTMLOptions.create(); XHTMLConverter.getInstance().convert(w3cDoc, xwpfDoc, options); // 实现@bottom-right的页码效果 XWPFHeaderFooterPolicy headerFooterPolicy = xwpfDoc.getHeaderFooterPolicy(); if (headerFooterPolicy == null) { headerFooterPolicy = xwpfDoc.createHeaderFooterPolicy(); } // 创建默认页脚 XWPFFooter footer = headerFooterPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT); XWPFParagraph footerPara = footer.createParagraph(); footerPara.setAlignment(ParagraphAlignment.RIGHT); // 右对齐对应@bottom-right XWPFRun run = footerPara.createRun(); run.setText("Page "); // 插入动态页码字段 run.getCTR().addNewFldSimple().setInstr("PAGE"); // 实现@page里的padding-right:20px(Word用缇作为单位,20px≈14缇) CTSectPr sectPr = xwpfDoc.getDocument().getBody().addNewSectPr(); CTPageMar pageMar = sectPr.addNewPgMar(); // 默认右边距是144缇(1英寸),加上20px对应的14缇 pageMar.setRight(BigInteger.valueOf(144 + 14)); // 写入输出流 xwpfDoc.write(outputStream); xwpfDoc.close(); }
说明
这里没有直接依赖CSS的@page,而是用XWPF的API精确控制页脚和页面边距——因为当前版本的XHTMLConverter对@page的支持仍然不完善,但API方式可以保证效果稳定。
方案2:坚持生成.doc格式(不推荐,限制多)
如果必须生成旧版.doc格式,只能用HWPF组件,但HWPF对HTML的支持极差,且页面属性的操作非常繁琐:
关键代码示例
import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.usermodel.*; import org.apache.poi.hwpf.model.SectionProperties; import java.io.*; public void convertHtmlToDoc(String html, OutputStream outputStream) throws Exception { HWPFDocument doc = new HWPFDocument(); Range range = doc.getRange(); // 注意:HWPF转换HTML的能力很弱,可能需要先把HTML转成纯文本或简单格式再插入 // 这里省略HTML转HWPF的具体步骤(可尝试用JTidy预处理HTML) // 设置页面右边距(增加20px对应的14缇) SectionProperties sectProps = range.getSection(0).getSectionProperties(); sectProps.setRightMargin(sectProps.getRightMargin() + 14); // 添加页脚页码(HWPF的字段处理很繁琐,这里是简化示例) HeaderStories headerStories = doc.getHeaderStories(); Range footerRange = headerStories.getFooterRange(); footerRange.insertAfter("Page "); Field pageField = footerRange.insertAfter(""); pageField.setType(Field.PAGE); pageField.update(); doc.write(outputStream); doc.close(); }
注意
这个方案会面临样式丢失、页码位置难以精确控制等问题,除非有硬性要求,否则不建议使用。
总结
优先选择切换到.docx格式的方案,用XWPF的API实现@page里的需求,这是目前最稳定可靠的方式。旧版.doc格式的限制太多,很难完美实现你的页面样式要求。
内容的提问来源于stack exchange,提问作者Chanchal Sharma
相关产品推荐
相关产品推荐

