目的
使用docx4j可以将 docx, pptx, xlsx 文件转为 pdf
添加依赖
首先,在pom.xml中引入相关依赖
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-export-fo</artifactId>
<version>11.2.9</version>
</dependency>
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
<version>11.2.9</version>
</dependency>
转PDF
下面两套代码均可以实现
代码1
private static boolean docx4jConvert(String src, String dst) {
OutputStream os = null;
try {
File srcFile = new File(src);
WordprocessingMLPackage mlPackage = WordprocessingMLPackage.load(srcFile);
FOSettings foSettings = Docx4J.createFOSettings();
foSettings.setOpcPackage(mlPackage);
OutputStream os = new FileOutputStream(dst);
Docx4J.toFO(foSettings, os, Docx4J.FLAG_EXPORT_PREFER_XSL);
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Docx4JException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
代码2
private static boolean docx4jConvert(String src, String dst) {
OutputStream os = null;
try {
File srcFile = new File(src);
WordprocessingMLPackage mlPackage = WordprocessingMLPackage.load(srcFile);
os = new FileOutputStream(dst);
Docx4J.toPDF(mlPackage, os);
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Docx4JException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
解决乱码问题
运行上面代码,程序打印一切正常,并输出pdf文件。但是你会发现PDF里,只要有中文的地方,都是乱码。这是由于在转换时没有找到对应字体导致的
PDF乱码部分节选
因此我们需要在这里手动加载中文字体。如果该字体不存在于系统的字体库,我们需要使用 addPhysicalFonts
方法进行加载
/**
* 设置字体,解决中文乱码的问题
*/
private static void setFontMapper(WordprocessingMLPackage mlPackage) throws Exception {
Mapper fontMapper = new IdentityPlusMapper();
// 加载本地字体
//PhysicalFonts.addPhysicalFonts("SimSun", new URL("/fonts/SIMSUN.TTC"));
fontMapper.put("隶书", PhysicalFonts.get("LiSu"));
fontMapper.put("宋体",PhysicalFonts.get("SimSun"));
fontMapper.put("微软雅黑",PhysicalFonts.get("Microsoft Yahei"));
fontMapper.put("黑体",PhysicalFonts.get("SimHei"));
fontMapper.put("楷体",PhysicalFonts.get("KaiTi"));
fontMapper.put("新宋体",PhysicalFonts.get("NSimSun"));
fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));
fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));
fontMapper.put("宋体扩展",PhysicalFonts.get("simsun-extB"));
fontMapper.put("仿宋",PhysicalFonts.get("FangSong"));
fontMapper.put("仿宋_GB2312",PhysicalFonts.get("FangSong_GB2312"));
fontMapper.put("幼圆",PhysicalFonts.get("YouYuan"));
fontMapper.put("华文宋体",PhysicalFonts.get("STSong"));
fontMapper.put("华文中宋",PhysicalFonts.get("STZhongsong"));
fontMapper.put("等线", PhysicalFonts.get("SimSun"));
fontMapper.put("等线 Light", PhysicalFonts.get("SimSun"));
fontMapper.put("华文琥珀", PhysicalFonts.get("STHupo"));
fontMapper.put("华文隶书", PhysicalFonts.get("STLiti"));
fontMapper.put("华文新魏", PhysicalFonts.get("STXinwei"));
fontMapper.put("华文彩云", PhysicalFonts.get("STCaiyun"));
fontMapper.put("方正姚体", PhysicalFonts.get("FZYaoti"));
fontMapper.put("方正舒体", PhysicalFonts.get("FZShuTi"));
fontMapper.put("华文细黑", PhysicalFonts.get("STXihei"));
fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB"));
fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));
fontMapper.put("新細明體", PhysicalFonts.get("SimSun"));
//解决宋体(正文)和宋体(标题)的乱码问题
PhysicalFonts.put("PMingLiU", PhysicalFonts.get("SimSun"));
PhysicalFonts.put("新細明體", PhysicalFonts.get("SimSun"));
//宋体&新宋体
PhysicalFont simsunFont = PhysicalFonts.get("SimSun");
fontMapper.put("SimSun", simsunFont);
mlPackage.setFontMapper(fontMapper);
}
之后即可正常显示了
转换限制
docx4j 只能转换 docx/pptx/xlsx 这三种类型的文件,如果你使用诸如 txt、doc 这类文件,就会报如下错误
ClassNotFoundException
javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
这是由于,你在 pom.xml 中只引用了 docx4j-export-fo
,却没用引用 JAXB 的实现。在 docx4j 的官网中可以找到该模块的实现库 docx4j-JAXB-ReferenceImpl
。注意,不要去引用 Javax 的那些 JAXB 库或者其他相关库,因为这样会引入更多错误
注意:如果你的代码用的是JDK8,那么只能使用上图8.3.1的版本;如果是JDK11及以上那么使用11.2.9版本。版本使用错会导致编译不过