哎呀,今天忙到飞起,文章晚点更新啦!不过好消息是,我们的小程序用户终于突破30啦,感谢大家的支持!而且,大家期待已久的文档转化功能明天就要上线啦,目前支持word转pdf,pdf转图片,xlsx转pdf。
记录下难点,有个问题是在docker部署时候word转pdf没有中文乱码,控制台报错
024-12-27 23:59:11.769 WARN 1 --- [nio-8004-exec-3] org.docx4j.fonts.RunFontSelector : Font 'SimSun' is not mapped to a physical font. 2024-12-27 23:59:11.788 WARN 1 --- [nio-8004-exec-3] org.docx4j.fonts.RunFontSelector : Font 'Cambria' is not mapped to a physical font. 2024-12-27 23:59:11.807 WARN 1 --- [nio-8004-exec-3] org.docx4j.fonts.fop.util.FopConfigUtil : Document font Cambria is not mapped to a physical font!
大概意思是某个字体映射没有找到,网上说的大概流程是查看docker字体,没有就去下载之类的
但是我是通过window的c盘fonts转过去的,容器中也有字体了
通过window的c盘fonts转到容器
命令如下,docker容器外进行
docker cp /usr/share/fonts/truetype/dejavu/. eblog:/usr/share/fonts/truetype/chinese/
eblog为你的容器名称,/usr/share/fonts/truetype/dejavu/是以下部分
/usr/share/fonts/truetype/chinese/为容器内的文件夹
通过上述命令可以将字体库放入docker容器中了
但是后续打包好jar包后运行,还是会报SimSun找不到的错误,导致转pdf全是乱码
即使是直接将对应的字体文件引入都不行,这里我设置了字体映射注册也不行
try {
// 设置字体映射
fontMapper.put("SimSun", PhysicalFonts.get("/usr/share/fonts/truetype/chinese/SIMSUN.TTC"));
// 检查是否成功
PhysicalFont font = PhysicalFonts.get("SimSun");
if (font == null) {
System.out.println("Failed to map SimSun to physical font.");
} else {
System.out.println("SimSun mapped to " + font.getName());
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Failed to map fonts.");
}
通过获取系统中所有已注册的字体并打印出来,发现并没有将SimSun注册
PhysicalFonts.getPhysicalFonts().forEach((key, font) -> {
System.out.println("Font: " + key);
});
我的解决办法就是将sisum.ttc文件一起打包上去,将simsun.ttc放在resources下的fonts中
获取字体文件的 URL并且注册fontMapper.put("宋体", PhysicalFonts.get("SimSun"));
// 获取字体文件的 URL,路径相对于类路径(即 resources 目录)
ClassLoader classLoader = FileServiceImpl.class.getClassLoader();
URL fontUrl = classLoader.getResource("fonts/simsun.ttc");
if (fontUrl == null) {
throw new RuntimeException("Resource not found: " + fontUrl);
}
fontMapper.put("宋体", PhysicalFonts.get("SimSun"));
打包运行转换成功
完整代码如下
private String convertWordToPdf(String filePath) throws Exception {
FileOutputStream fileOutputStream = null;
try {
// 获取当前时间戳
String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
// 获取文件名(去掉路径和扩展名)
File file = new File(filePath);
String fileName = file.getName().replaceAll("\\.docx$", "");
// 创建带时间戳的pdf路径,文件保存到fileDir目录下
String pdfPath = fileDir + fileName + "_" + timestamp + ".pdf";
// 进行文件转换
fileOutputStream = new FileOutputStream(new File(pdfPath));
WordprocessingMLPackage mlPackage = WordprocessingMLPackage.load(file);
setFontMapper(mlPackage);
Docx4J.toPDF(mlPackage, fileOutputStream);
System.out.println("PDF转换成功,文件保存为:" + pdfPath);
// 返回生成文件路径
return fileName + "_" + timestamp + ".pdf";
} catch (Exception e) {
e.printStackTrace();
System.out.println("转换失败");
throw new UnsupportedOperationException("Word 转 PDF 的功能尚未实现: " + filePath);
} finally {
IOUtils.closeQuietly(fileOutputStream);
}
}
private static void setFontMapper(WordprocessingMLPackage mlPackage) throws Exception {
Mapper fontMapper = new IdentityPlusMapper();
// 获取字体文件的 URL,路径相对于类路径(即 resources 目录)
ClassLoader classLoader = FileServiceImpl.class.getClassLoader();
URL fontUrl = classLoader.getResource("fonts/simsun.ttc");
if (fontUrl == null) {
throw new RuntimeException("Resource not found: " + fontUrl);
}
// 使用 PhysicalFonts 添加字体
PhysicalFonts.addPhysicalFonts("SimSun", fontUrl);
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("FangSong"));
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"));
// 设置字体映射
mlPackage.setFontMapper(fontMapper);
}
有兴趣体验小程序,搜索Listen Hui帮工办