Jsoup + docx4j解析富文本编辑器HTML 源码转 Word:Exception in thread "main" java.lang.NoSuchFieldError: COURIER_BOLD_OBLIQUE;java.lang.ClassNotFoundException: org.docx4j.jaxb.suninternal.NamespacePrefixMapper
请注意,docx4j 的 11.x 系列使用 Jakarta XML Binding(jakarta.xml.bind),而 8.x 系列使用 Javax XML Binding(javax.xml.bind)。因此,确保您的项目依赖项与所使用的 Java 版本和 XML Binding 版本兼容。
此外,docx4j 的 11.5.0 版本已迁移至 Jakarta XML Binding 4.0,适用于需要与 Spring Boot 3.3.0 等框架集成的项目。如果您使用的是 Java 11 或更高版本,建议升级到此版本以获得更好的兼容性和功能支持。
请根据上述信息调整您的项目配置,以确保使用正确的 docx4j 版本。
本案例使用 Java 8 进行集成,spring-boot-starter-parent 版本 2.7.9。
版本依赖导致的报错
java.lang.ClassNotFoundException: org.docx4j.jaxb.suninternal.NamespacePrefixMapper
这个错误说明你缺少了 docx4j 的 JAXB 依赖中一个关键类:org.docx4j.jaxb.suninternal.NamespacePrefixMapper
。
这是 docx4j 在运行过程中尝试为 XML 序列化配置命名空间前缀映射器(NamespacePrefixMapper)时,默认去找了一个类,但该类不在标准 JDK 中,而是:
- 仅在 JDK 6~8 中由
com.sun.xml.bind
提供; - 在 JDK 9+ 以及使用 模块化系统或 OpenJDK 中常常缺失;
- 而且 docx4j 在 JAXB 处理上依赖了一些特定实现,不完全兼容所有 JDK 版本默认 JAXB。
Exception in thread "main" java.lang.RuntimeException: javax.xml.bind.JAXBException: Can't create internal NamespacePrefixMapper
- with linked exception:
[java.lang.ClassNotFoundException: org.docx4j.jaxb.suninternal.NamespacePrefixMapper]
at org.docx4j.XmlUtils.marshaltoString(XmlUtils.java:941)
at org.docx4j.XmlUtils.marshaltoString(XmlUtils.java:857)
at org.docx4j.XmlUtils.marshaltoString(XmlUtils.java:797)
at org.docx4j.model.styles.StyleTree.createVirtualStylesForDocDefaults(StyleTree.java:527)
at org.docx4j.model.styles.StyleTree.init(StyleTree.java:141)
at org.docx4j.model.styles.StyleTree.<init>(StyleTree.java:81)
at org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart.getStyleTree(MainDocumentPart.java:203)
at org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart.getStyleTree(MainDocumentPart.java:173)
at org.docx4j.convert.in.xhtml.XHTMLImporterImpl.stylesToCSS(XHTMLImporterImpl.java:475)
at org.docx4j.convert.in.xhtml.XHTMLImporterImpl.getRenderer(XHTMLImporterImpl.java:282)
at org.docx4j.convert.in.xhtml.XHTMLImporterImpl.convert(XHTMLImporterImpl.java:711)
at cn.sh.ideal.data.middleware.controller.HtmlToWordConverter2.main(HtmlToWordConverter2.java:29)
Caused by: javax.xml.bind.JAXBException: Can't create internal NamespacePrefixMapper
- with linked exception:
[java.lang.ClassNotFoundException: org.docx4j.jaxb.suninternal.NamespacePrefixMapper]
at org.docx4j.jaxb.NamespacePrefixMapperUtils.getPrefixMapper(NamespacePrefixMapperUtils.java:67)
at org.docx4j.XmlUtils.marshaltoString(XmlUtils.java:889)
... 11 more
Caused by: java.lang.ClassNotFoundException: org.docx4j.jaxb.suninternal.NamespacePrefixMapper
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at org.docx4j.jaxb.NamespacePrefixMapperUtils.getPrefixMapper(NamespacePrefixMapperUtils.java:63)
... 12 more
解决方法:添加依赖引入兼容的 docx4j-JAXB-ReferenceImpl
包(确保 docx4j 和它的 JAXB 实现版本 匹配一致)。
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
<version>8.3.7</version>
</dependency>
Exception in thread “main” java.lang.NoSuchFieldError: COURIER_BOLD_OBLIQUE
docx4j 8.x 或 11.x 在处理 HTML 转 Word 时,默认会使用 openhtmltopdf 和其 pdfbox 后端,而你当前的 openhtmltopdf-pdfbox 版本 依赖一个不存在的字体字段:COURIER_BOLD_OBLIQUE。
这通常是:
- openhtmltopdf 或其 pdfbox 依赖版本不匹配;
- pdfbox 版本太新或太旧,和 openhtmltopdf 不兼容;
- 或者你的项目中混入了多个不同版本的 pdfbox。
Exception in thread "main" java.lang.NoSuchFieldError: COURIER_BOLD_OBLIQUE
at com.openhtmltopdf.pdfboxout.fontstore.AbstractFontStore$BuiltinFontStore.addCourier(AbstractFontStore.java:55)
at com.openhtmltopdf.pdfboxout.fontstore.AbstractFontStore$BuiltinFontStore.createInitialFontMap(AbstractFontStore.java:43)
at com.openhtmltopdf.pdfboxout.fontstore.AbstractFontStore$BuiltinFontStore.<init>(AbstractFontStore.java:38)
at com.openhtmltopdf.pdfboxout.PdfBoxFontResolver.<init>(PdfBoxFontResolver.java:82)
at org.docx4j.convert.in.xhtml.renderer.DocxRenderer.<init>(DocxRenderer.java:152)
at org.docx4j.convert.in.xhtml.renderer.DocxRenderer.<init>(DocxRenderer.java:100)
at org.docx4j.convert.in.xhtml.XHTMLImporterImpl.getRenderer(XHTMLImporterImpl.java:282)
at org.docx4j.convert.in.xhtml.XHTMLImporterImpl.convert(XHTMLImporterImpl.java:711)
at cn.sh.ideal.data.middleware.controller.HtmlToWordConverter2.main(HtmlToWordConverter2.java:29)
不排除依赖默认是这样的,可以通过 idea maven helper 插件,使用和安装方式自行百度即可
docx4j-ImportXHTML 中排除 pdfbox 相关的依赖,以及 fontbox 依赖,并在外面强制指定 pdfbox 版本
<!--HTML 转 Word:Jsoup + docx4j-->
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-core</artifactId>
<version>8.3.11</version>
</dependency>
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-ImportXHTML</artifactId>
<version>8.3.11</version>
<exclusions>
<!--docx4j-ImportXHTML 依赖的是 pdfbox 3.0.1,而docx4j-core 依赖的是 fontbox 2.0.30(它依赖的 pdfbox 应该是 2.x 系的)-->
<!--排除pdfbox字体依赖:Exception in thread "main" java.lang.NoSuchFieldError: COURIER_BOLD_OBLIQUE-->
<exclusion>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-io</artifactId>
</exclusion>
<!--排除fontbox字体依赖:docx4j-core也会引入这个依赖,是2.0.30版本-->
<exclusion>
<groupId>org.apache.pdfbox</groupId>
<artifactId>fontbox</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--引入pdfbox依赖-->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.30</version>
</dependency>
完整依赖
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-ImportXHTML</artifactId>
<version>8.3.11</version>
<exclusions>
<!--docx4j-ImportXHTML 依赖的是 pdfbox 3.0.1,而docx4j-core 依赖的是 fontbox 2.0.30(它依赖的 pdfbox 应该是 2.x 系的)-->
<!--排除pdfbox字体依赖:Exception in thread "main" java.lang.NoSuchFieldError: COURIER_BOLD_OBLIQUE-->
<exclusion>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-io</artifactId>
</exclusion>
<!--排除fontbox字体依赖:docx4j-core也会引入这个依赖,是2.0.30版本-->
<exclusion>
<groupId>org.apache.pdfbox</groupId>
<artifactId>fontbox</artifactId>
</exclusion>
<!--排除commons-io依赖-->
<exclusion>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</exclusion>
</exclusions>
</dependency>
<!--引入pdfbox依赖-->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.30</version>
</dependency>
<!--docx4j 官方提供的 JAXB 实现适配模块,它会注入兼容的 NamespacePrefixMapper,避免找不到类的报错-->
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
<version>8.3.11</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.19.1</version>
</dependency>
排除版本不一致问题后,整体的依赖架构如下:
工具类
富文本编辑器的内容如果有图片,前端一般会使用base64编码后转换为html源码传给后端,后端根据html将内容转为word。
html源码如:
<h1>一、标题</h1>
<p>
<br/>
</p>
<h2>尊敬的各级政府部门、企事业单位:</h2>
<p>
<br/>
<strong>关键词: 工业企业的安全生产管理, 环境保护政策, 大气污染, 生活品质, 监管, 低硫煤</strong>
<br/>
<em>二、正文</em>
<br/>
<br/>
<u>鉴于近期我国多地出现严重空气污染,为切实保障人民群众身体健康,有效控制和改善环境空气质量,现就加强大气污染防范工作紧急通知如下:</u>
<br/>
<br/>
<s>一、各地要立即启动大气污染应急响应机制,采取有效措施,减少大气污染物排放。燃煤设施必须使用低硫煤,煤炭经营单位需严格管理,确保燃煤质量符合国家标准。</s>
<br/>
<br/>
<span style="color:#e60000">二、餐饮服务业、集贸市场及早、夜市等单位必须使用清洁能源,禁止使用劣质燃料,减少油烟排放。</span>
<br/>
<br/>
<span style="background-color:#ff9900">三、加强施工工地监管,暂停高污染、高排放项目施工,强化道路清扫保洁,减少扬尘污染。</span>
<br/>
<br/>
<sub>四、加大对露天焚烧、烟花爆竹燃放等行为的管控力度,严禁一切可能加剧空气污染的行为。</sub>
<br/>
<br/>
<sup>五、各级环保部门要加大对违法排污行为的查处力度,对不合规单位依法依规严肃处理,确保环境保护政策得到有效执行。</sup>
<br/>
</p>
<ol>
<li>六、各工业企业需加强安全生产管理,落实主体责任,严格执行大气污染治理标准,确保生产过程中的污染物排放达标。</li>
</ol>
<p>
<br/>
</p>
<ul>
<li>七、政府将加大监管力度,确保各项防范措施落实到位,对不作为、乱作为的单位和个人依法问责。</li>
</ul>
<p